peddler 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
- .DS_Store
2
- peddler.gemspec
3
- pkg
1
+ pkg/*
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ amazon.yml
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -cfd
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ rvm --create use ree@peddler
2
+ rvm wrapper ree@peddler
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in peddler.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,47 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ peddler (0.3.0)
5
+ activesupport (>= 2.3.2)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activesupport (3.0.1)
11
+ addressable (2.2.2)
12
+ crack (0.1.8)
13
+ diff-lcs (1.1.2)
14
+ json (1.4.6)
15
+ rdiscount (1.6.5)
16
+ rdoc (2.4.3)
17
+ rspec (2.0.1)
18
+ rspec-core (~> 2.0.1)
19
+ rspec-expectations (~> 2.0.1)
20
+ rspec-mocks (~> 2.0.1)
21
+ rspec-core (2.0.1)
22
+ rspec-expectations (2.0.1)
23
+ diff-lcs (>= 1.1.2)
24
+ rspec-mocks (2.0.1)
25
+ rspec-core (~> 2.0.1)
26
+ rspec-expectations (~> 2.0.1)
27
+ sdoc (0.2.20)
28
+ json (>= 1.1.3)
29
+ rdoc (= 2.4.3)
30
+ sdoc-helpers (0.1.4)
31
+ sdoc (~> 0.2)
32
+ vcr (1.2.0)
33
+ webmock (1.4.0)
34
+ addressable (>= 2.2.2)
35
+ crack (>= 0.1.7)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ activesupport (>= 2.3.2)
42
+ peddler!
43
+ rdiscount (~> 1.6.5)
44
+ rspec (~> 2.0.0)
45
+ sdoc-helpers (~> 0.1.4)
46
+ vcr (~> 1.2.0)
47
+ webmock (~> 1.4.0)
data/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
1
  (The MIT License)
2
-
3
- Copyright (c) 2009 Paper Cavalier
4
-
2
+
3
+ Copyright (c) 2009-2010 Paper Cavalier
4
+
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
7
7
  'Software'), to deal in the Software without restriction, including
@@ -9,14 +9,14 @@ without limitation the rights to use, copy, modify, merge, publish,
9
9
  distribute, sublicense, and/or sell copies of the Software, and to
10
10
  permit persons to whom the Software is furnished to do so, subject to
11
11
  the following conditions:
12
-
12
+
13
13
  The above copyright notice and this permission notice shall be
14
14
  included in all copies or substantial portions of the Software.
15
-
15
+
16
16
  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
17
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
18
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
19
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
20
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
21
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,128 @@
1
+ Peddler
2
+ =======
3
+
4
+ Peddler is a Ruby wrapper to the Amazon Inventory management API.
5
+
6
+ ![Peddler](http://github.com/papercavalier/peddler/raw/master/mussels.jpg)
7
+
8
+ Example usage
9
+ -------------
10
+
11
+ Set up a client:
12
+
13
+ client = Peddler::Client.new(
14
+ :username => 'foo@bar.com',
15
+ :password => 'secret',
16
+ :region => :us)
17
+
18
+ Create an inventory file:
19
+
20
+ batch = client.new_inventory_batch
21
+ item = client.new_inventory_item(
22
+ :product_id => '1234567890',
23
+ :price => 100.00,
24
+ :sku => 'SKU-123',
25
+ :quantity => 10)
26
+ batch << item
27
+
28
+ Repeat ad infinitum and upload:
29
+
30
+ batch.upload
31
+
32
+ The batch now should have an upload ID. Now, check the error log:
33
+
34
+ upload_log = client.new_report(
35
+ :upload,
36
+ :id => batch.id)
37
+ upload_log.body
38
+ => "Feed Processing Summary:\n\tNumber of records processed\t\t1\n\tNumber of records successful\t\t1\n\n"
39
+
40
+ You are wondering if you have any new orders:
41
+
42
+ orders_report = client.new_report :order
43
+ orders = client.detab(orders_report.body)
44
+ p orders.size
45
+ => 1500
46
+ p orders[0].item_name
47
+ => "A Thousand Plateaus: Capitalism and Schizophrenia (Paperback) by Gilles Deleuze"
48
+
49
+ After processing the orders, post back the results to Amazon:
50
+
51
+ feed = client.new_order_fulfillment_feed
52
+ fulfilled_order = client.new_fulfilled_order(
53
+ :order_id => '123-1234567-1234567',
54
+ :order_date => '2009-08-01',
55
+ :carrier_code => 'USPS',
56
+ :tracking_number => '0308 0330 0000 0000 0000')
57
+ feed << fulfilled_order
58
+
59
+ Once done, upload:
60
+
61
+ feed.upload
62
+
63
+ Want to see the processing report?
64
+
65
+ p feed.status
66
+ => "_SUBMITTED_"
67
+
68
+ Refresh until you get:
69
+
70
+ p feed.status!
71
+ => "_DONE_"
72
+
73
+ Then, check the report:
74
+
75
+ p feed.download.to_s
76
+
77
+ You have an order you can't fill and haven't shipped yet. No problem:
78
+
79
+ feed = client.new_order_cancellation_feed
80
+ cancelled_order = client.new_cancelled_order(
81
+ :order_id => '123-1234567-1234567',
82
+ :cancellation_reason_code => 'NoInventory',
83
+ :amazon_order_item_code => '12341234567890')
84
+ feed << cancelled_order
85
+ feed.upload
86
+ sleep(60)
87
+ feed.status!
88
+ => "_DONE_"
89
+ p feed.download.to_s
90
+ => ...
91
+
92
+ To post a refund for an already-shipped item, you use the batch refund method:
93
+
94
+ refunds = client.new_refund_batch
95
+ refund = client.new_refund(
96
+ :order_id => '123-1234567-1234567',
97
+ :payments_transaction_id => '12341234567890',
98
+ :refund_amount => 1.00,
99
+ :reason => 'GeneralAdjustment',
100
+ :message => 'With our apologies.')
101
+ refunds << refund
102
+ refunds.upload
103
+
104
+ For a change, let's download something different from Amazon, like a preorder report:
105
+
106
+ preorder_report = client.new_report(
107
+ :preorder,
108
+ :product_line => 'Books',
109
+ :frequency => 2)
110
+ preorders = client.detab(preorder_report.body)
111
+ p preorders.size
112
+ => 2000
113
+ p preorders[0].asin
114
+ => "1234567890"
115
+ p preorders[0].average_asking_price
116
+ => "100"
117
+
118
+ [Read source](http://gloss.papercavalier.com/peddler) for more info.
119
+
120
+ Todo
121
+ ----
122
+
123
+ Switch to using the [Amazon Marketplace Web Service (Amazon MWS)](https://mws.amazon.com/index.html).
124
+
125
+ Compatibility
126
+ -------------
127
+
128
+ Specs pass against Ruby 1.8.7, Ruby 1.9.2, and Rubinius 1.1.
data/Rakefile CHANGED
@@ -1,18 +1,12 @@
1
- require 'rubygems'
2
- require 'rake'
3
- begin
4
- require 'jeweler'
5
- Jeweler::Tasks.new do |s|
6
- s.name = 'peddler'
7
- s.summary = 'A Ruby wrapper to the Amazon Inventory Management API'
8
- s.email = 'hakan.ensari@papercavalier.com'
9
- s.homepage = 'http://papercavalier.github.com/peddler'
10
- s.description = 'Peddler is a Ruby wrapper to the Amazon Inventory Management API.'
11
- s.authors = ['Hakan Şenol Ensari']
12
- s.add_dependency 'activesupport', '>= 2.3.5'
13
- s.add_development_dependency 'rspec', '>= 1.3.0'
14
- end
15
- Jeweler::GemcutterTasks.new
16
- rescue LoadError
17
- puts 'Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler'
18
- end
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+ require 'sdoc_helpers'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ desc 'Run all specs in spec directory'
8
+ RSpec::Core::RakeTask.new(:spec) do |spec|
9
+ spec.pattern = 'spec/**/*_spec.rb'
10
+ end
11
+
12
+ task :default => :spec
@@ -26,7 +26,7 @@ module Peddler
26
26
  end
27
27
  params.each_pair { |k, v| self.send("#{k}=", v) }
28
28
  end
29
-
29
+
30
30
  # Creates an inventory batch.
31
31
  #
32
32
  # batch = client.new_inventory_batch
@@ -47,7 +47,7 @@ module Peddler
47
47
  def new_inventory_batch
48
48
  Peddler::Inventory::Batch.new(transport.dup)
49
49
  end
50
-
50
+
51
51
  # A short-hand method to purge inventory.
52
52
  #
53
53
  # client.purge_inventory
@@ -55,20 +55,20 @@ module Peddler
55
55
  def purge_inventory
56
56
  empty_batch = Peddler::Inventory::Batch.new(transport.dup)
57
57
  empty_batch.upload(:method => 'purge')
58
-
58
+
59
59
  end
60
-
60
+
61
61
  # Creates an inventory item. Parameter keys are lowercased and underscored but otherwise the same as
62
62
  # the colum titles in the tab-delimited upload templates provided by Amazon.
63
63
  def new_inventory_item(params={})
64
64
  Peddler::Inventory::Item.new(params)
65
65
  end
66
-
66
+
67
67
  # Returns count of pending inventory uploads queued at Amazon.
68
68
  def inventory_queue
69
69
  Peddler::Inventory::Queue.count(transport)
70
70
  end
71
-
71
+
72
72
  # Creates an order fulfillment batch.
73
73
  #
74
74
  # feed = client.new_order_fulfillment_feed
@@ -87,13 +87,13 @@ module Peddler
87
87
  def new_order_fulfillment_feed
88
88
  Peddler::Feeds::OrderFulfillment::Batch.new(transport.dup)
89
89
  end
90
-
90
+
91
91
  # Creates an item that can then be added to an order fulfillment feed. Keys are lowercased and underscored but
92
92
  # otherwise the same as Amazon's headers. See section 7.1 in the API docs.
93
93
  def new_fulfilled_order(params={})
94
94
  Peddler::Feeds::OrderFulfillment::Item.new(params)
95
95
  end
96
-
96
+
97
97
  # Creates an order cancellation batch.
98
98
  #
99
99
  # feed = client.new_order_cancellation_feed
@@ -113,13 +113,13 @@ module Peddler
113
113
  def new_order_cancellation_feed
114
114
  Peddler::Feeds::OrderCancellation::Batch.new(transport.dup)
115
115
  end
116
-
116
+
117
117
  # Creates an item that can then be added to an order cancellation feed. Keys are lowercased and underscored but
118
118
  # otherwise the same as Amazon's headers. See section 7.4 in the API docs.
119
119
  def new_cancelled_order(params={})
120
120
  Peddler::Feeds::OrderCancellation::Item.new(params)
121
121
  end
122
-
122
+
123
123
  # Creates a refund batch.
124
124
  #
125
125
  # batch = client.new_refund_batch
@@ -142,14 +142,14 @@ module Peddler
142
142
  def new_refund_batch
143
143
  Peddler::Refunds::Batch.new(transport.dup)
144
144
  end
145
-
145
+
146
146
  # Creates a refund item that can then be added to a refund batch.
147
147
  #
148
148
  # Possible reasons: ["GeneralAdjustment", "CouldNotShip", "DifferentItem", "MerchandiseNotReceived", "MerchandiseNotAsDescribed"]
149
149
  def new_refund(params={})
150
150
  Peddler::Refunds::Item.new(params)
151
151
  end
152
-
152
+
153
153
  # Creates an instance for an already-generated report. Works only with
154
154
  # legacy reports, meaning anything that comes before section 7 in the API
155
155
  # docs.
@@ -178,7 +178,7 @@ module Peddler
178
178
  def new_report(name,params={})
179
179
  Peddler::LegacyReports::Report.new(transport.dup, name, params)
180
180
  end
181
-
181
+
182
182
  # Requests a report. Returns true when successful.
183
183
  #
184
184
  # Possible report names: [:order, :open_listings, :open_listings_lite, :open_listings_liter]
@@ -189,7 +189,7 @@ module Peddler
189
189
  def generate_report(name,params={})
190
190
  Peddler::LegacyReports.generate(transport, name, params)
191
191
  end
192
-
192
+
193
193
  # Creates an unshipped order report. Takes on some optional parameters, such as :id, :starts_at, :ends_at. By default,
194
194
  # it will request a new unshipped order report for the past seven days.
195
195
  #
@@ -204,7 +204,7 @@ module Peddler
204
204
  def new_unshipped_orders_report(params={})
205
205
  Peddler::Reports::UnshippedOrdersReport.new(transport.dup, params)
206
206
  end
207
-
207
+
208
208
  # Returns status of most recent reports. Optional "count" defaults to 10. Name can be [ :upload, :order, :batch_refund, :open_listings, :open_listings_lite, :open_listings_liter ].
209
209
  #
210
210
  # reports = client.latest_reports :order, :count => 1
@@ -214,14 +214,14 @@ module Peddler
214
214
  def latest_reports(name,params={})
215
215
  Peddler::LegacyReports.latest(transport, name, params)
216
216
  end
217
-
217
+
218
218
  # Decodes tab-delimited content into an array of OpenStruct objects.
219
219
  def detab(msg)
220
220
  Peddler::Handlers::TabDelimitedHandler.decode_response(msg)
221
221
  end
222
-
222
+
223
223
  private
224
-
224
+
225
225
  def transport #:nodoc:all
226
226
  @transport ||= Peddler::Transport.new
227
227
  end
data/lib/peddler/feeds.rb CHANGED
@@ -1,32 +1,32 @@
1
1
  module Peddler
2
-
2
+
3
3
  # This module includes functionality to handle the charge-when-ship-related
4
4
  # feeds Amazon added to the API in 2009.
5
5
  module Feeds
6
-
6
+
7
7
  # This is a downloadable file. Outputs Amazon's response verbatim for now.
8
8
  class Download
9
9
  attr_accessor :id, :type, :related_reference_id, :available_at, :acknowledged
10
-
10
+
11
11
  MAPPED_PARAMS = {
12
12
  'DownloadId' => 'id',
13
13
  'DownloadType' => 'type',
14
14
  'RelatedReferenceId' => 'related_reference_id',
15
15
  'AvailableDate' => 'available_at',
16
16
  'Acknowledged' => 'acknowledged'}
17
-
17
+
18
18
  def initialize(transport, params={})
19
19
  @transport = transport
20
20
  params.each_pair{ |k, v| self.send "#{MAPPED_PARAMS[k]}=", v }
21
21
  end
22
-
22
+
23
23
  # Retrieves and returns report.
24
24
  def to_s
25
25
  @body ||= download_report
26
26
  end
27
-
27
+
28
28
  private
29
-
29
+
30
30
  def download_report
31
31
  return nil if @id.nil?
32
32
  @transport.modernize_request
@@ -36,12 +36,12 @@ module Peddler
36
36
  @transport.execute_request
37
37
  end
38
38
  end
39
-
39
+
40
40
  # This is the base class.
41
41
  class Feed
42
42
  attr_writer :file_content
43
43
  attr_accessor :batch, :download, :status, :type, :id, :submitted_at, :started_processing_at, :completed_processing_at, :messages_processed, :messages_successful, :messages_with_errors, :messages_with_warnings
44
-
44
+
45
45
  MAPPED_PARAMS = {
46
46
  'UploadStatus' => 'status',
47
47
  'UploadType' => 'type',
@@ -54,12 +54,12 @@ module Peddler
54
54
  'MessagesSuccessful' => 'messages_successful',
55
55
  'MessagesWithErrors' => 'messages_with_errors',
56
56
  'MessagesWithWarnings' => 'messages_with_warnings'}
57
-
57
+
58
58
  def initialize(transport)
59
59
  @transport = transport
60
60
  @batch = []
61
61
  end
62
-
62
+
63
63
  # Returns content of the upload file.
64
64
  def file_content
65
65
  return @file_content if @file_content
@@ -67,14 +67,14 @@ module Peddler
67
67
  @batch.each{ |item| out << item.to_s }
68
68
  @file_content = out
69
69
  end
70
-
70
+
71
71
  # Returns status and will also refresh if not already "done."
72
72
  def status!
73
73
  return @status if @status.nil? || @status =~ /_DONE_/
74
74
  refresh_status
75
75
  @status
76
76
  end
77
-
77
+
78
78
  # Uploads batch.
79
79
  def upload
80
80
  raise PeddlerError.new('Batch already uploaded') unless @id.nil?
@@ -87,14 +87,14 @@ module Peddler
87
87
  process_response(res)
88
88
  @status
89
89
  end
90
-
90
+
91
91
  # Adds an item to the batch.
92
92
  def <<(item)
93
93
  @batch << item
94
94
  end
95
-
95
+
96
96
  private
97
-
97
+
98
98
  def refresh_status
99
99
  @transport.modernize_request
100
100
  @transport.query_params.merge!({
@@ -103,7 +103,7 @@ module Peddler
103
103
  res = @transport.execute_request
104
104
  process_response(res)
105
105
  end
106
-
106
+
107
107
  def process_response(res)
108
108
  upload = Hash.from_xml(res)['Response']['Upload'] || Hash.from_xml(res)['Response']['UploadsStatusList']['Upload']
109
109
  upload.each_pair do |key, value|
@@ -115,7 +115,7 @@ module Peddler
115
115
  end
116
116
  end
117
117
  end
118
-
118
+
119
119
  module OrderFulfillment
120
120
  # This class contains methods to upload order fulfillment info to Amazon.
121
121
  # See sections 7.1 through 7.3 in the API documentation for more detail.
@@ -126,7 +126,7 @@ module Peddler
126
126
  super(transport)
127
127
  end
128
128
  end
129
-
129
+
130
130
  # This is an order fulfillment item.
131
131
  class Item
132
132
  attr_accessor :order_id, :order_item_id, :quantity, :ship_date, :carrier_name, :tracking_number, :ship_method
@@ -135,19 +135,19 @@ module Peddler
135
135
  def initialize(params={})
136
136
  params.each_pair{ |key, value| send("#{key}=", value) }
137
137
  end
138
-
138
+
139
139
  # Validates when setting carrier code.
140
140
  def carrier_code=(carrier_code)
141
141
  @carrier_code = carrier_code if %w{USPS UPS FedEx other}.include?(carrier_code)
142
142
  end
143
-
143
+
144
144
  # Outputs a formatted line for the tab-delimited upload file.
145
145
  def to_s
146
146
  "#{@order_id}\t#{@order_item_id}\t#{@quantity}\t#{@ship_date}\t#{@carrier_code}\t#{@carrier_name}\t#{@tracking_number}\t#{@ship_method}\r\n"
147
147
  end
148
148
  end
149
149
  end
150
-
150
+
151
151
  # This module contains methods to upload cancelled orders to Amazon.
152
152
  # See section 7.4 in the API documentation for more detail.
153
153
  module OrderCancellation
@@ -164,16 +164,16 @@ module Peddler
164
164
  class Item
165
165
  attr_accessor :order_id, :amazon_order_item_code
166
166
  attr_reader :cancellation_reason_code
167
-
167
+
168
168
  def initialize(params={})
169
169
  params.each_pair{ |key, value| send("#{key}=", value) }
170
170
  end
171
-
171
+
172
172
  # Validates when setting cancellation reason code.
173
173
  def cancellation_reason_code=(cancellation_reason_code)
174
174
  @cancellation_reason_code = cancellation_reason_code if %w{ BuyerCanceled CustomerExchange CustomerReturn GeneralAdjustment MerchandiseNotReceived NoInventory ShippingAddressUndeliverable }.include?(cancellation_reason_code)
175
175
  end
176
-
176
+
177
177
  # Outputs a formatted line for the tab-delimited upload file.
178
178
  def to_s
179
179
  if @cancellation_reason_code.nil? != @amazon_order_item_code.nil?
@@ -184,4 +184,4 @@ module Peddler
184
184
  end
185
185
  end
186
186
  end
187
- end
187
+ end
@@ -1,17 +1,17 @@
1
1
  module Peddler
2
2
  module Handlers
3
3
  class XMLHandler
4
-
4
+
5
5
  # Parses legacy responses to queries on statuses of generated reports and inventory uploads.
6
6
  def self.parse_legacy(hash)
7
7
  if hash['Batches']
8
- hash['Batches']['Batch'].collect { |input| Peddler::LegacyReports::UploadStatus.new(input) }
8
+ [hash['Batches']['Batch']].flatten.collect { |input| Peddler::LegacyReports::UploadStatus.new(input) }
9
9
  elsif hash['Reports']
10
- hash['Reports']['Report'].collect { |input| Peddler::LegacyReports::ReportStatus.new(input) }
10
+ [hash['Reports']['Report']].flatten.collect { |input| Peddler::LegacyReports::ReportStatus.new(input) }
11
11
  end
12
12
  end
13
13
  end
14
-
14
+
15
15
  class TabDelimitedHandler
16
16
  # Decodes tab-delimited content into an array of OpenStruct objects. It
17
17
  # assumes first line contains parameter names.
@@ -35,4 +35,4 @@ module Peddler
35
35
  end
36
36
  end
37
37
  end
38
- end
38
+ end