amazon_seller_central 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. data/README.md +42 -5
  2. data/VERSION +1 -1
  3. data/amazon_seller_central.gemspec +22 -4
  4. data/lib/amazon_seller_central/feedback_page.rb +1 -13
  5. data/lib/amazon_seller_central/inventory.rb +23 -0
  6. data/lib/amazon_seller_central/inventory_page.rb +126 -0
  7. data/lib/amazon_seller_central/listing.rb +42 -0
  8. data/lib/amazon_seller_central/listing_set.rb +13 -0
  9. data/lib/amazon_seller_central/mechanizer.rb +10 -5
  10. data/lib/amazon_seller_central/page.rb +26 -0
  11. data/lib/amazon_seller_central.rb +5 -0
  12. data/spec/lib/feedback_page_spec.rb +5 -25
  13. data/spec/lib/inventory_page_spec.rb +120 -0
  14. data/spec/lib/inventory_spec.rb +26 -0
  15. data/spec/lib/listing_set_spec.rb +39 -0
  16. data/spec/lib/listing_spec.rb +78 -0
  17. data/spec/lib/mechanizer_spec.rb +24 -19
  18. data/spec/spec_helper.rb +3 -0
  19. data/spec/support/page_body_regexen.rb +7 -0
  20. data/spec/support/page_examples.rb +23 -0
  21. data/spec/support/sample_pages/Feedback Manager.html +1 -1
  22. data/spec/support/sample_pages/another_listings_page.html +12299 -0
  23. data/spec/support/sample_pages/listings_last_page.html +3345 -0
  24. data/spec/support/sample_pages/listings_page_1.html +12937 -0
  25. data/spec/support/sample_pages/listings_page_2.html +12970 -0
  26. data/spec/support/sample_pages/update_inventory_result_from_last_page.html +3345 -0
  27. data/spec/support/sample_pages/update_inventory_result_from_page_1.html +12939 -0
  28. data/spec/support/sample_pages/update_inventory_result_from_page_2.html +11274 -0
  29. data/spec/support/sample_pages.rb +25 -12
  30. metadata +82 -64
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
- # amazon_seller_central
1
+ # amazon\_seller\_central
2
2
 
3
3
  This gem is intended to wrap Amazon's SellerCentral pages with a Ruby
4
- API. Currently this gem supports accessing buyer feedback only.
4
+ API. Currently this gem supports accessing buyer feedback, accessing
5
+ current inventory listings, and simple updates to those listings.
5
6
 
6
7
  ## Setup
7
8
 
@@ -36,14 +37,50 @@ the block form:
36
37
  feedback.rating # an integer, 1 - 5
37
38
  end
38
39
 
39
- ## ToDo
40
+ ## Inventory Access
41
+
42
+ You can access current inventory in much the same way as feedback:
43
+
44
+ AmazonSellerCentral::Inventory.each_page do |page|
45
+ listings = page.listings
46
+ listing = listings.first
47
+
48
+ listing.sku # <Your sku for this listing>
49
+ listing.asin # An ASIN, e.g. B003962DXE
50
+ listing.product_name # The name of the product
51
+ listing.created_at # a Time object representing when you created this listing
52
+ listing.quantity # an integer
53
+ listing.condition # "New" or "Used - Very Good" or whichever
54
+ listing.price_cents # an integer of cents. listing.price is also available to get dollars
55
+ listing.status # "Open", "Closed (Out of Stock)", or "Incomplete"
56
+ end
57
+
58
+ ## Updating Inventory
59
+
60
+ Currently this gem supports updating a listing you've already created
61
+ via the web interface or some other API. Future versions may include
62
+ creating listing entries from scratch.
63
+
64
+ To update a listing, you use `ListingPage#apply_listings`, like so:
65
+
66
+ # alternately get a page inside the 'each_page' method above
67
+ page = AmazonSellerCentral::Inventory.load_first_page
68
+ # Updating a listing for my sku, "PR6902-2":
69
+ listing = page.listings.find("PR6902-2")
70
+ listing.quantity = 10
71
+ listing.price_cents = 1599
72
+ # Note the array syntax here allows you to update multiple listings
73
+ # on this page at the same time.
74
+ page.apply_listings([listing])
75
+
76
+ ## TODO
40
77
 
41
78
  * Access to more sections of Amazon SellerCentral.
42
79
  * Rework Mechanize access to allow parallel / thread-safe usage
43
80
  * **Note**: This library is likely not thread-safe. (It's untested)
44
81
 
45
- ## Contributing to amazon_seller_central
46
-
82
+ ## Contributing to amazon\_seller\_central
83
+
47
84
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
48
85
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
49
86
  * Fork the project
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{amazon_seller_central}
8
- s.version = "0.1.1"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["optoro"]
12
- s.date = %q{2011-07-09}
12
+ s.date = %q{2011-09-01}
13
13
  s.description = %q{This gem is intended to wrap Amazon's SellerCentral pages with a Ruby API. Currently this gem supports accessing buyer feedback only.}
14
14
  s.email = %q{dev@optoro.com}
15
15
  s.extra_rdoc_files = [
@@ -31,12 +31,23 @@ Gem::Specification.new do |s|
31
31
  "lib/amazon_seller_central/configuration.rb",
32
32
  "lib/amazon_seller_central/feedback.rb",
33
33
  "lib/amazon_seller_central/feedback_page.rb",
34
+ "lib/amazon_seller_central/inventory.rb",
35
+ "lib/amazon_seller_central/inventory_page.rb",
36
+ "lib/amazon_seller_central/listing.rb",
37
+ "lib/amazon_seller_central/listing_set.rb",
34
38
  "lib/amazon_seller_central/mechanizer.rb",
39
+ "lib/amazon_seller_central/page.rb",
35
40
  "spec/amazon_seller_central_spec.rb",
36
41
  "spec/lib/feedback_page_spec.rb",
37
42
  "spec/lib/feedback_spec.rb",
43
+ "spec/lib/inventory_page_spec.rb",
44
+ "spec/lib/inventory_spec.rb",
45
+ "spec/lib/listing_set_spec.rb",
46
+ "spec/lib/listing_spec.rb",
38
47
  "spec/lib/mechanizer_spec.rb",
39
48
  "spec/spec_helper.rb",
49
+ "spec/support/page_body_regexen.rb",
50
+ "spec/support/page_examples.rb",
40
51
  "spec/support/sample_pages.rb",
41
52
  "spec/support/sample_pages/Feedback Manager.html",
42
53
  "spec/support/sample_pages/Feedback Page 1.html",
@@ -44,12 +55,19 @@ Gem::Specification.new do |s|
44
55
  "spec/support/sample_pages/Feedback Page Last.html",
45
56
  "spec/support/sample_pages/Seller Central Homepage.html",
46
57
  "spec/support/sample_pages/Seller Central Redirect.html",
47
- "spec/support/sample_pages/Seller Central.html"
58
+ "spec/support/sample_pages/Seller Central.html",
59
+ "spec/support/sample_pages/another_listings_page.html",
60
+ "spec/support/sample_pages/listings_last_page.html",
61
+ "spec/support/sample_pages/listings_page_1.html",
62
+ "spec/support/sample_pages/listings_page_2.html",
63
+ "spec/support/sample_pages/update_inventory_result_from_last_page.html",
64
+ "spec/support/sample_pages/update_inventory_result_from_page_1.html",
65
+ "spec/support/sample_pages/update_inventory_result_from_page_2.html"
48
66
  ]
49
67
  s.homepage = %q{http://github.com/optoro/amazon_seller_central}
50
68
  s.licenses = ["MIT"]
51
69
  s.require_paths = ["lib"]
52
- s.rubygems_version = %q{1.5.2}
70
+ s.rubygems_version = %q{1.5.0}
53
71
  s.summary = %q{Ruby API to access Amazon's SellerCentral}
54
72
 
55
73
  if s.respond_to? :specification_version then
@@ -1,20 +1,11 @@
1
1
  module AmazonSellerCentral
2
- class FeedbackPage
2
+ class FeedbackPage < Page
3
3
  attr_accessor :body
4
4
 
5
- def initialize(options={})
6
- @page = options.delete(:page)
7
- @body = @page ? @page.body : ""
8
- end
9
-
10
5
  def has_next?
11
6
  @has_next ||= @page.search('a').map(&:text).grep(/Next/).count > 0
12
7
  end
13
8
 
14
- def last_page?
15
- !has_next?
16
- end
17
-
18
9
  def next_page
19
10
  @next_page ||= begin
20
11
  raise NoNextPageAvailableError unless has_next?
@@ -54,9 +45,6 @@ module AmazonSellerCentral
54
45
 
55
46
  extend ClassMethods
56
47
 
57
- class NoNextPageAvailableError < StandardError
58
- end
59
-
60
48
  private
61
49
  def feedback_row_to_object(row)
62
50
  data = row.search('.//td').map(&:text)
@@ -0,0 +1,23 @@
1
+ module AmazonSellerCentral
2
+ class Inventory
3
+ module ClassMethods
4
+ def load_first_page
5
+ AmazonSellerCentral.mechanizer.login_to_seller_central
6
+ manage_inventory = AmazonSellerCentral.mechanizer.follow_link_with(:text => "Manage Inventory")
7
+ InventoryPage.new( :page => manage_inventory, :page_no => 1, :uri_base => manage_inventory.uri.to_s )
8
+ end
9
+
10
+ def load_all_pages
11
+ pages = [load_first_page]
12
+ while pages.last.has_next?
13
+ pages << pages.last.next_page
14
+ yield pages.last if block_given?
15
+ end
16
+ pages
17
+ end
18
+ alias each_page load_all_pages
19
+ end
20
+
21
+ extend ClassMethods
22
+ end
23
+ end
@@ -0,0 +1,126 @@
1
+ module AmazonSellerCentral
2
+ class InventoryPage < Page
3
+ def initialize(options={})
4
+ @listings_applied = false
5
+ @page_no = options.delete(:page_no)
6
+ @uri_base = options.delete(:uri_base)
7
+ super
8
+ end
9
+
10
+ def has_next?
11
+ @has_next ||= @page.search(".//div[@id='nextPage']").any?
12
+ end
13
+
14
+ def next_page
15
+ @next_page ||= begin
16
+ raise NoNextPageAvailableError unless has_next?
17
+
18
+ next_page = AmazonSellerCentral.mechanizer.agent.get("#{@uri_base}&searchPageOffset=#{@page_no + 1}")
19
+ InventoryPage.new(
20
+ :page => next_page,
21
+ :page_no => (@page_no + 1),
22
+ :uri_base => @uri_base
23
+ )
24
+ end
25
+ end
26
+
27
+ def listings(rescan=false)
28
+ @listings = nil if rescan
29
+ @listings ||= begin
30
+ set = ListingSet.new
31
+ # being more specific here breaks on some pages
32
+ @page.parser.css('tr').select{|r| r['id'] =~ /^sku-/ && r.css('td').size == 12 }.each do |row|
33
+ set << listing_row_to_object(row)
34
+ end
35
+ set
36
+ end
37
+ end
38
+ alias :parse :listings
39
+
40
+ def apply_listings(new_listings)
41
+ if @listings_applied
42
+ raise UnsupportedModification.new("Can't apply listing data twice from the same page object. Refetch this page before attempting to update listings")
43
+ end
44
+
45
+ form = @page.form_with(:name => 'itemSummaryForm')
46
+ new_listings.each do |l|
47
+ if listings(true).find(l.sku).price.nil? && l.price != nil
48
+ raise UnsupportedModification.new("Can't set price for #{l.asin} to $#{l.price}, the listing is not yet complete and this library doesn't yet support completing listings")
49
+ end
50
+
51
+ form["inv|#{l.sku}|#{l.asin}"] = l.quantity
52
+ form["price|#{l.sku}|#{l.asin}"] = l.price
53
+ end
54
+ form['formOperation'] = 'saveChanges'
55
+ r = form.submit
56
+ @listings_applied = true
57
+ true
58
+ end
59
+
60
+ class UnsupportedModification < StandardError; end
61
+
62
+ private
63
+
64
+ # 0 - hidden input of sku
65
+ # 1 - checkbox itemOffer
66
+ # 2 - actions
67
+ # 3 - sku
68
+ # 4 - asin
69
+ # 5 - product name
70
+ # 6 - date created
71
+ # 7 - qty
72
+ # 8 - condition
73
+ # 9 - your price
74
+ # 10 - low price
75
+ # 11 - status
76
+ def listing_row_to_object(row)
77
+ l = Listing.new
78
+ row.css('td').each_with_index do |td, i|
79
+
80
+ txt = td.text.strip # yes, slightly slower to do this here, but I type less.
81
+
82
+ case i
83
+ when 3
84
+ l.sku = txt
85
+ when 4
86
+ l.asin = txt
87
+ when 5
88
+ l.product_name = txt
89
+ when 6
90
+ l.created_at = Time.parse(txt)
91
+ when 7
92
+ l.quantity = td.css('input').first['value'].to_i
93
+ when 8
94
+ l.condition = txt
95
+ when 9
96
+ l.price = get_price(td)
97
+ when 10
98
+ l.low_price = get_low_price(td)
99
+ when 11
100
+ l.status = txt
101
+ end
102
+ end
103
+ l
104
+ end
105
+
106
+ def get_price(td)
107
+ if td.css('input').size == 0 # incomplete listing
108
+ nil
109
+ else
110
+ td.css('input').first['value'].to_f
111
+ end
112
+ end
113
+
114
+ # Turns out you can't get this without a subrequest
115
+ def get_low_price(td)
116
+ nil
117
+ # if td.css('a').size == 0 # no listing complete
118
+ # nil
119
+ # elsif td.css('a div').size == 1
120
+ # true
121
+ # else
122
+ # td.text.gsub(/[^\d.]/,'').to_f
123
+ # end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,42 @@
1
+ module AmazonSellerCentral
2
+ # It turns out you can't get low_price without executing a sub-request, so
3
+ # I'm leaving it alone for now.
4
+ class Listing
5
+ module ClassMethods
6
+ def is_asin?(value)
7
+ value.to_s =~ /^B.{9}$/
8
+ end
9
+ end
10
+ extend ClassMethods
11
+
12
+ attr_accessor :sku, :asin, :product_name, :created_at, :quantity, :condition, :price_cents, :low_price_cents, :status
13
+
14
+ alias :qty :quantity
15
+ alias :qty= :quantity=
16
+
17
+ alias :product :product_name
18
+ alias :product= :product_name=
19
+
20
+ def price
21
+ @price_cents.kind_of?(Numeric) ? @price_cents / 100.0 : @price_cents
22
+ end
23
+ def price=(price)
24
+ @price_cents = price.kind_of?(Numeric) ? (price * 100).round : price
25
+ end
26
+
27
+ alias :your_price :price
28
+ alias :your_price= :price=
29
+
30
+ def low_price
31
+ @low_price_cents.kind_of?(Numeric) ? @low_price_cents / 100.0 : @low_price_cents
32
+ end
33
+ def low_price=(low_price)
34
+ @low_price_cents = low_price.kind_of?(Numeric) ? (low_price * 100).round : low_price
35
+ end
36
+
37
+ def save
38
+ puts "Sorry, you want to send this listing as part of an array to the InventoryPage it came from, with InventoryPage#apply_listings"
39
+ false
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ module AmazonSellerCentral
2
+ class ListingSet < Array
3
+
4
+ def find(selector)
5
+ if Listing.is_asin?(selector)
6
+ select{|e| e.asin == selector }
7
+ else
8
+ detect{|e| e.sku == selector }
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -5,7 +5,7 @@ module AmazonSellerCentral
5
5
  include Singleton
6
6
  MASQUERADE_AGENTS = ['Mac Safari', 'Mac FireFox', 'Linux Firefox']
7
7
 
8
- attr_reader :agent, :last_page
8
+ attr_reader :agent
9
9
 
10
10
  def login_email
11
11
  AmazonSellerCentral.configuration.login_email
@@ -19,25 +19,30 @@ module AmazonSellerCentral
19
19
  @agent ||= Mechanize.new {|ag| ag.user_agent_alias = MASQUERADE_AGENTS[rand(MASQUERADE_AGENTS.size)] }
20
20
  end
21
21
 
22
+ def last_page
23
+ agent.current_page
24
+ end
25
+
22
26
  def login_to_seller_central
23
27
  page = agent.get('https://sellercentral.amazon.com/')
24
28
  form = page.form_with(:name => 'signin')
25
29
 
26
- form.email = login_email
30
+ form.email = login_email
27
31
  form.password = login_password
28
- @last_page = form.submit
32
+ form.submit
33
+ last_page.body =~ /Welcome! You are signed in as/
29
34
  end
30
35
 
31
36
  def follow_link_with(options)
32
37
  raise AgentResetError unless last_page
33
38
  link = last_page.link_with(options)
34
39
  raise LinkNotFoundError unless link
35
- @last_page = agent.click(link)
40
+ agent.click(link)
36
41
  end
37
42
 
38
43
  def reset!
39
44
  @agent = nil
40
- @last_page = nil
45
+ #@last_page = nil
41
46
  end
42
47
 
43
48
  class LinkNotFoundError < StandardError; end
@@ -0,0 +1,26 @@
1
+ module AmazonSellerCentral
2
+ class Page
3
+ attr_accessor :body
4
+
5
+ def initialize(options={})
6
+ @page = options.delete(:page)
7
+ @body = @page ? @page.body : ""
8
+ end
9
+
10
+ def has_next?
11
+ false
12
+ end
13
+
14
+ def last_page?
15
+ !has_next?
16
+ end
17
+
18
+ def next_page
19
+ raise NoNextPageAvailableError.new("Unimplemented, override Page#next_page")
20
+ end
21
+
22
+ class NoNextPageAvailableError < StandardError
23
+ end
24
+
25
+ end
26
+ end
@@ -1,7 +1,12 @@
1
1
  require 'amazon_seller_central/configuration'
2
2
  require 'amazon_seller_central/mechanizer'
3
+ require 'amazon_seller_central/listing_set'
4
+ require 'amazon_seller_central/page'
3
5
  require 'amazon_seller_central/feedback'
4
6
  require 'amazon_seller_central/feedback_page'
7
+ require 'amazon_seller_central/listing'
8
+ require 'amazon_seller_central/inventory'
9
+ require 'amazon_seller_central/inventory_page'
5
10
 
6
11
  module AmazonSellerCentral
7
12
  def self.configuration
@@ -3,36 +3,16 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
3
  describe "FeedbackPage" do
4
4
  before :all do
5
5
  #AmazonSellerCentral.mechanizer.reset!
6
- @first_page_test_regex = /Wow! Amazing price, super fast shipping./
7
- @second_page_test_regex = /This printer was not in good shape as the seller described./
8
- @last_page_test_regex = /easy to put together - ignore the first review/
6
+ @first_page_test_regex = FEEDBACK_FIRST_PAGE_TEST_REGEX
7
+ @second_page_test_regex = FEEDBACK_SECOND_PAGE_TEST_REGEX
8
+ @last_page_test_regex = FEEDBACK_LAST_PAGE_TEST_REGEX
9
9
 
10
10
  @first_page = AmazonSellerCentral::FeedbackPage.load_first_page
11
11
  @second_page = @first_page.next_page
12
12
  @last_page = @second_page.next_page
13
13
  end
14
14
 
15
- it "knows if there is a next page of feedback" do
16
- @first_page.has_next?.should be_true
17
- @second_page.has_next?.should be_true
18
- @last_page.has_next?.should be_false
19
- end
20
-
21
- it "returns the next page when there is one" do
22
- @first_page.next_page.body.should =~ @second_page_test_regex
23
- end
24
-
25
- it "raises an exception when asked for a next page and there is none" do
26
- lambda {
27
- @last_page.next_page
28
- }.should raise_exception(AmazonSellerCentral::FeedbackPage::NoNextPageAvailableError)
29
- end
30
-
31
- it "knows if it is the last page" do
32
- @first_page.last_page?.should be_false
33
- @second_page.last_page?.should be_false
34
- @last_page.last_page?.should be_true
35
- end
15
+ it_should_behave_like "all pages"
36
16
 
37
17
  it "transforms itself into a collection of Feedback objects" do
38
18
  feedback = @first_page.feedbacks
@@ -40,7 +20,7 @@ describe "FeedbackPage" do
40
20
  feedback.last.comments.should == "quick delivery. product arrived in perfect condition. good experience."
41
21
  end
42
22
 
43
- describe "class methods" do
23
+ describe "ClassMethods" do
44
24
  it "loads the first page of feedback data" do
45
25
  AmazonSellerCentral.mechanizer.reset!
46
26
  page = AmazonSellerCentral::FeedbackPage.load_first_page
@@ -0,0 +1,120 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "InventoryPage" do
4
+ before :all do
5
+ @first_page_test_regex = INVENTORY_FIRST_PAGE_TEST_REGEX
6
+ @second_page_test_regex = INVENTORY_SECOND_PAGE_TEST_REGEX
7
+ @last_page_test_regex = INVENTORY_LAST_PAGE_TEST_REGEX
8
+ end
9
+
10
+ before :each do
11
+ mock_seller_central_page_results!
12
+ @first_page = AmazonSellerCentral::Inventory.load_first_page
13
+ @second_page = @first_page.next_page
14
+ @last_page = @second_page.next_page
15
+ end
16
+
17
+ it_should_behave_like "all pages"
18
+
19
+ it "returns a ListingSet for listings" do
20
+ listings = @first_page.listings
21
+ listings.should be_kind_of(AmazonSellerCentral::ListingSet)
22
+ end
23
+
24
+ it "transforms itself into a set of Listing objects" do
25
+ listings = @first_page.listings
26
+ listings.size.should == 250
27
+
28
+ listings[27].sku.should == "PR30122-11"
29
+ listings[27].asin.should == "B0019MU9C2"
30
+ listings[27].product_name.should == "Battery Brain Platinum"
31
+ listings[27].created_at.should == Time.parse("2011-08-31 00:36:22")
32
+ listings[27].quantity.should == 0
33
+ listings[27].condition.should == "New"
34
+ listings[27].price_cents.should == nil
35
+ listings[27].low_price.should == nil
36
+ listings[27].low_price_cents.should == nil
37
+ listings[27].status.should == "Incomplete"
38
+
39
+ listings[1].sku.should == "PR48458-3"
40
+ listings[1].asin.should == "B004O0TRDI"
41
+ listings[1].product_name.should == "Onkyo HT-S3400 5.1 Channel Home Theater Receiver/Speaker Package"
42
+ listings[1].created_at.should == Time.parse("2011-08-31 18:14:49")
43
+ listings[1].quantity.should == 1
44
+ listings[1].condition.should == "Used - Good"
45
+ listings[1].price_cents.should == 22559
46
+ # listings[1].low_price.should == true
47
+ # listings[1].low_price_cents.should == true
48
+ listings[1].status.should == "Open"
49
+
50
+ listings[10].sku.should == "PR27880-11"
51
+ listings[10].asin.should == "B003962DXE"
52
+ listings[10].product_name.should == "Panasonic Lumix DMC-FH20K 14.1 MP Digital Camera with 8x Optical Image Stabilized Zoom and 2.7-Inch LCD (Black)"
53
+ listings[10].created_at.should == Time.parse("2011-08-31 10:40:13")
54
+ listings[10].quantity.should == 1
55
+ listings[10].condition.should == "New"
56
+ listings[10].price_cents.should == 10899
57
+ #listings[10].low_price_cents.should == 10250
58
+ listings[10].status.should == "Open"
59
+ end
60
+
61
+ it "loads listings appropriately for another sample page" do
62
+ # This sample page was only parsing 25 results before
63
+ FakeWeb.register_uri(:get, 'https://sellercentral.amazon.com/gp/ezdpc-gui/inventory-status/status.html/ref=ag_invmgr_mmap_home', :response => mock_pages[:another_listings_page])
64
+ listings = AmazonSellerCentral::Inventory.load_first_page.listings
65
+ listings.size.should == 250
66
+
67
+ listings[1].sku.should == "PR6902-2"
68
+ listings[1].asin.should == "B000Q82PIQ"
69
+ listings[1].product_name.should == "Western Digital 500 GB Caviar Blue SATA 3 Gb/s 7200 RPM 16 MB Cache Bulk/OEM Desktop Hard Drive - WD5000AAKS"
70
+ listings[1].created_at.should == Time.parse("2011-08-31 22:42:13")
71
+ listings[1].quantity.should == 1
72
+ listings[1].condition.should == "Used - Very Good"
73
+ listings[1].price_cents.should == 3819
74
+ # listings[1].low_price.should == true
75
+ listings[1].status.should == "Open"
76
+ end
77
+
78
+ it "accepts a set of Listing objects to apply updates to the page" do
79
+ listings = @first_page.listings
80
+ l = listings[0]
81
+ # l.quantity = 0
82
+ # l.price = 225.59
83
+ l.quantity = 2
84
+ l.price = 220.99
85
+
86
+ listings = [l]
87
+
88
+ @first_page.apply_listings(listings).should be_true
89
+
90
+ (AmazonSellerCentral.mechanizer.last_page.parser.css('div#msg_saveSuccess')[0]['style'] !~ /display: none/).should be_true
91
+
92
+ FakeWeb.register_uri(:get, 'https://sellercentral.amazon.com/gp/ezdpc-gui/inventory-status/status.html/ref=ag_invmgr_mmap_home', :response => mock_pages[:update_inventory_result_from_page_1])
93
+ listing = AmazonSellerCentral::Inventory.load_first_page.listings[0]
94
+ listing.sku.should == l.sku
95
+ listing.quantity.should == l.quantity
96
+ listing.price.should == l.price
97
+ end
98
+
99
+ it "raises an unsupported modification error when trying to set the price on an incomplete listing" do
100
+ listings = @first_page.listings
101
+ l = listings[27]
102
+ l.price = 24.26
103
+ lambda {
104
+ @first_page.apply_listings([l])
105
+ }.should raise_exception(AmazonSellerCentral::InventoryPage::UnsupportedModification)
106
+ end
107
+
108
+ it "raises an unsupported modification error when trying to apply listings twice" do
109
+ listings = @first_page.listings
110
+ l = listings[0]
111
+ l.price = 24.26
112
+ @first_page.apply_listings([l])
113
+
114
+ l.price = 26.26
115
+ lambda {
116
+ @first_page.apply_listings([l])
117
+ }.should raise_exception(AmazonSellerCentral::InventoryPage::UnsupportedModification)
118
+ end
119
+
120
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Inventory" do
4
+ it "loads the first page of inventory data" do
5
+ AmazonSellerCentral.mechanizer.reset!
6
+ page = AmazonSellerCentral::Inventory.load_first_page
7
+ page.should be_kind_of(AmazonSellerCentral::InventoryPage)
8
+ page.body.should =~ INVENTORY_FIRST_PAGE_TEST_REGEX
9
+ end
10
+
11
+ it "loads all inventory pages" do
12
+ AmazonSellerCentral.mechanizer.reset!
13
+ pages = AmazonSellerCentral::Inventory.load_all_pages
14
+ pages.size.should == 3
15
+ pages.first.body.should =~ INVENTORY_FIRST_PAGE_TEST_REGEX
16
+ pages.last.body.should =~ INVENTORY_LAST_PAGE_TEST_REGEX
17
+ end
18
+
19
+ it "passes a page to a block when given" do
20
+ last_seen = nil
21
+ AmazonSellerCentral::Inventory.each_page do |page|
22
+ last_seen = page
23
+ end
24
+ last_seen.body.should =~ INVENTORY_LAST_PAGE_TEST_REGEX
25
+ end
26
+ end