amazon_seller_central 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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