snl-peddler 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/History.txt +2 -0
- data/LICENSE +22 -0
- data/README.rdoc +104 -0
- data/Rakefile +17 -0
- data/VERSION.yml +4 -0
- data/lib/peddler.rb +25 -0
- data/lib/peddler/client.rb +240 -0
- data/lib/peddler/feeds.rb +181 -0
- data/lib/peddler/handlers.rb +58 -0
- data/lib/peddler/inventory.rb +108 -0
- data/lib/peddler/legacy_reports.rb +107 -0
- data/lib/peddler/refunds.rb +54 -0
- data/lib/peddler/reports.rb +94 -0
- data/lib/peddler/transport.rb +135 -0
- data/peddler.gemspec +78 -0
- data/spec/peddler/client_spec.rb +47 -0
- data/spec/peddler/feeds_spec.rb +70 -0
- data/spec/peddler/handlers_spec.rb +15 -0
- data/spec/peddler/inventory_spec.rb +74 -0
- data/spec/peddler/legacy_reports_spec.rb +86 -0
- data/spec/peddler/refunds_spec.rb +35 -0
- data/spec/peddler/reports_spec.rb +19 -0
- data/spec/peddler/transport_spec.rb +58 -0
- data/spec/spec_helper.rb +3 -0
- metadata +106 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.DS_Store
|
data/History.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2009 Hakan Şenol Ensari
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
= Peddler
|
2
|
+
|
3
|
+
Peddler is a Ruby wrapper to the Amazon Inventory management API.
|
4
|
+
|
5
|
+
== Example usage
|
6
|
+
|
7
|
+
Fire off a client:
|
8
|
+
|
9
|
+
client = Peddler::Client.new(
|
10
|
+
:username => "foo@bar.com",
|
11
|
+
:password => "secret",
|
12
|
+
:region => "us")
|
13
|
+
|
14
|
+
Create an inventory file:
|
15
|
+
|
16
|
+
batch = client.new_inventory_batch
|
17
|
+
item = client.new_inventory_item(
|
18
|
+
:product_id => "1234567890",
|
19
|
+
:price => 100.00,
|
20
|
+
:sku => "SKU-123",
|
21
|
+
:quantity => 10)
|
22
|
+
batch << item
|
23
|
+
...
|
24
|
+
|
25
|
+
Repeat ad infinitum and then upload:
|
26
|
+
|
27
|
+
batch.upload
|
28
|
+
|
29
|
+
The batch now should have an upload ID assigned to it. Let's check its error log.
|
30
|
+
|
31
|
+
upload_log = client.new_report(
|
32
|
+
:upload,
|
33
|
+
:id => batch.id)
|
34
|
+
upload_log.body
|
35
|
+
=> "Feed Processing Summary:\n\tNumber of records processed\t\t1\n\tNumber of records successful\t\t1\n\n"
|
36
|
+
|
37
|
+
You're done uploading your inventory and now want to download some reports from Amazon. Let's go ahead and fetch a preorder list for the past two days to see if there is anything you can fill:
|
38
|
+
|
39
|
+
preorders_report = client.new_report(
|
40
|
+
:preorder,
|
41
|
+
:product_line => "Books",
|
42
|
+
:frequency => 2)
|
43
|
+
preorders = Peddler::Handlers::TabDelimitedHandler.decode_response(preorders_report.body)
|
44
|
+
p preorders.size
|
45
|
+
=> 2000
|
46
|
+
p preorders[0].asin
|
47
|
+
=> "1234567890"
|
48
|
+
p preorders[0].average_asking_price
|
49
|
+
=> "100"
|
50
|
+
|
51
|
+
Maybe you're probably wondering if you have any new orders:
|
52
|
+
|
53
|
+
orders_report = client.new_report :order
|
54
|
+
orders = Peddler::Handlers::TabDelimitedHandler.decode_response(orders_report.body)
|
55
|
+
p orders.size
|
56
|
+
=> 1500
|
57
|
+
p orders[0].item_name
|
58
|
+
=> "A Thousand Plateaus: Capitalism and Schizophrenia (Paperback) by Gilles Deleuze"
|
59
|
+
|
60
|
+
You have processed the orders and want to post back the results to Amazon, now that they're "charge when ship." Let's start with sending shipment info:
|
61
|
+
|
62
|
+
feed = client.new_order_fulfillment_feed
|
63
|
+
fulfilled_order = new_fulfilled_order(
|
64
|
+
:order_id => "123-1234567-1234567",
|
65
|
+
:order_date => "2009-08-01",
|
66
|
+
:carrier_code => "USPS",
|
67
|
+
:tracking_number => "0308 0330 0000 0000 0000")
|
68
|
+
feed << fulfilled_order
|
69
|
+
|
70
|
+
Again, repeat until done and upload:
|
71
|
+
|
72
|
+
feed.upload
|
73
|
+
|
74
|
+
Curious to see the processing report?
|
75
|
+
|
76
|
+
p feed.status
|
77
|
+
=> "_SUBMITTED_"
|
78
|
+
|
79
|
+
Refresh until you see:
|
80
|
+
|
81
|
+
p feed.status!
|
82
|
+
=> "_DONE_"
|
83
|
+
|
84
|
+
Finally, check the report:
|
85
|
+
|
86
|
+
p feed.download.to_s
|
87
|
+
=> ...
|
88
|
+
|
89
|
+
Sadly, you also have an order you can't fulfill. No problem. The workflow is quite similar:
|
90
|
+
|
91
|
+
feed = client.new_order_cancellation_feed
|
92
|
+
cancelled_order = new_cancelled_order(
|
93
|
+
:order_id => "123-1234567-1234567")
|
94
|
+
feed << cancelled_order
|
95
|
+
feed.upload
|
96
|
+
sleep(60)
|
97
|
+
feed.status!
|
98
|
+
=> "_DONE_"
|
99
|
+
p feed.download.to_s
|
100
|
+
=> ...
|
101
|
+
|
102
|
+
Run rdoc and check the source for more detailed info.
|
103
|
+
|
104
|
+
Copyright © 2009 Hakan Senol Ensari, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake"
|
3
|
+
begin
|
4
|
+
require "jeweler"
|
5
|
+
Jeweler::Tasks.new do |s|
|
6
|
+
s.name = "peddler"
|
7
|
+
s.summary = "Peddler is a Ruby wrapper to the Amazon Inventory Management API."
|
8
|
+
s.email = "hakan.ensari@papercavalier.com"
|
9
|
+
s.homepage = "http://github.com/snl/peddler"
|
10
|
+
s.description = "Peddler is a Ruby wrapper to the Amazon Inventory Management API."
|
11
|
+
s.authors = ["Hakan Senol Ensari"]
|
12
|
+
s.add_dependency "xmlsimple"
|
13
|
+
s.add_development_dependency "rspec"
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
17
|
+
end
|
data/VERSION.yml
ADDED
data/lib/peddler.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Peddler is a Ruby wrapper to the Amazon Inventory management API.
|
2
|
+
module Peddler
|
3
|
+
VERSION = "0.1"
|
4
|
+
end
|
5
|
+
|
6
|
+
class String #:nodoc: all
|
7
|
+
def camelize
|
8
|
+
self.gsub(/(^|_)(.)/) { $2.upcase }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require "net/https"
|
13
|
+
require "ostruct"
|
14
|
+
require "tempfile"
|
15
|
+
require "time"
|
16
|
+
require "xmlsimple"
|
17
|
+
|
18
|
+
require File.dirname(__FILE__) + "/peddler/client"
|
19
|
+
require File.dirname(__FILE__) + "/peddler/handlers"
|
20
|
+
require File.dirname(__FILE__) + "/peddler/feeds"
|
21
|
+
require File.dirname(__FILE__) + "/peddler/inventory"
|
22
|
+
require File.dirname(__FILE__) + "/peddler/legacy_reports"
|
23
|
+
require File.dirname(__FILE__) + "/peddler/refunds"
|
24
|
+
require File.dirname(__FILE__) + "/peddler/reports"
|
25
|
+
require File.dirname(__FILE__) + "/peddler/transport"
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# = Peddler
|
2
|
+
# Peddler is a Ruby wrapper to the Amazon Inventory management API.
|
3
|
+
#
|
4
|
+
# Peddler::Client has some detailed explanation and examples of usage.
|
5
|
+
module Peddler
|
6
|
+
# This is the public interface of the Peddler library.
|
7
|
+
class Client
|
8
|
+
# Creates a client instance.
|
9
|
+
#
|
10
|
+
# client = Peddler::Client.new :username => "foo@bar.com",
|
11
|
+
# :password => "secret",
|
12
|
+
# :region => "us"
|
13
|
+
#
|
14
|
+
def initialize(params={})
|
15
|
+
params.each_pair { |key, value| self.send("#{key}=", value) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def username=(username)
|
19
|
+
self.transport.username = username
|
20
|
+
end
|
21
|
+
|
22
|
+
def password=(password)
|
23
|
+
self.transport.password = password
|
24
|
+
end
|
25
|
+
|
26
|
+
# Sets Amazon region. Works with [ "us", "uk", "de", "ca", "fr", "jp" ].
|
27
|
+
def region=(region)
|
28
|
+
self.transport.region = region
|
29
|
+
end
|
30
|
+
|
31
|
+
# Creates an inventory batch.
|
32
|
+
#
|
33
|
+
# A sample workflow:
|
34
|
+
#
|
35
|
+
# batch = client.new_inventory_batch
|
36
|
+
# book = new_inventory_item(
|
37
|
+
# :product_id => "1234567890",
|
38
|
+
# :sku => "SKU-001",
|
39
|
+
# :price => 10.00,
|
40
|
+
# :quantity => 1)
|
41
|
+
# batch << book
|
42
|
+
# batch.upload
|
43
|
+
#
|
44
|
+
# The batch should now have an upload id assigned to it by Amazon. Once processed, you can use this to
|
45
|
+
# check the error log:
|
46
|
+
#
|
47
|
+
# report = client.new_report :upload, :id => batch.id
|
48
|
+
# report.body
|
49
|
+
#
|
50
|
+
# That should output something like the following, assuming everything went well with the upload:
|
51
|
+
#
|
52
|
+
# "Feed Processing Summary:\n\tNumber of records processed\t\t1\n\tNumber of records successful\t\t1\n\n"
|
53
|
+
#
|
54
|
+
def new_inventory_batch
|
55
|
+
Peddler::Inventory::Batch.new(self.transport.dup)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Creates an inventory item. Parameter keys are lowercased and underscored but otherwise the same as
|
59
|
+
# Amazon's colum titles in their tab-delimited templates.
|
60
|
+
def new_inventory_item(params={})
|
61
|
+
Peddler::Inventory::Item.new(params)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns count of pending inventory uploads queued at Amazon.
|
65
|
+
def inventory_queue
|
66
|
+
Peddler::Inventory::Queue.count(self.transport)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates an order fulfillment batch.
|
70
|
+
#
|
71
|
+
# A sample workflow:
|
72
|
+
#
|
73
|
+
# feed = client.new_order_fulfillment_feed
|
74
|
+
# fulfilled_order = new_fulfilled_order(
|
75
|
+
# :order_id => "123-1234567-1234567",
|
76
|
+
# :order_date => "2009-08-01")
|
77
|
+
# feed << fulfilled_order
|
78
|
+
# feed.upload
|
79
|
+
# feed.status
|
80
|
+
# => "_SUBMITTED_"
|
81
|
+
#
|
82
|
+
# Now, refresh the status until you see:
|
83
|
+
#
|
84
|
+
# feed.status!
|
85
|
+
# => "_DONE_"
|
86
|
+
#
|
87
|
+
# Finally, check the processing report:
|
88
|
+
#
|
89
|
+
# feed.download.to_s
|
90
|
+
#
|
91
|
+
def new_order_fulfillment_feed
|
92
|
+
Peddler::Feeds::OrderFulfillment::Batch.new(self.transport.dup)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Creates an item that can then be added to an order fulfillment feed. Keys are lowercased and underscored but
|
96
|
+
# otherwise the same as Amazon's headers. See section 7.1 in the API docs.
|
97
|
+
def new_fulfilled_order(params={})
|
98
|
+
Peddler::Feeds::OrderFulfillment::Item.new(params)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Creates an order cancellation batch.
|
102
|
+
#
|
103
|
+
# A sample workflow:
|
104
|
+
#
|
105
|
+
# feed = client.new_order_cancellation_feed
|
106
|
+
# cancelled_order = new_cancelled_order(
|
107
|
+
# :order_id => "123-1234567-1234567")
|
108
|
+
# feed << cancelled_order
|
109
|
+
# feed.upload
|
110
|
+
# feed.status
|
111
|
+
# => "_SUBMITTED_"
|
112
|
+
#
|
113
|
+
# Now, refresh the status until you see:
|
114
|
+
#
|
115
|
+
# feed.status!
|
116
|
+
# => "_DONE_"
|
117
|
+
#
|
118
|
+
# Finally, check the processing report:
|
119
|
+
#
|
120
|
+
# feed.download.to_s
|
121
|
+
#
|
122
|
+
def new_order_cancellation_feed
|
123
|
+
Peddler::Feeds::OrderCancellation::Batch.new(self.transport.dup)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Creates an item that can then be added to an order cancellation feed. Keys are lowercased and underscored but
|
127
|
+
# otherwise the same as Amazon's headers. See section 7.4 in the API docs.
|
128
|
+
def new_cancelled_order(params={})
|
129
|
+
Peddler::Feeds::OrderCancellation::Item.new(params)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Creates a refund batch.
|
133
|
+
#
|
134
|
+
# batch = client.new_refund_batch
|
135
|
+
# refund = client.new_refund(
|
136
|
+
# :order_id => "123-1234567-1234567",
|
137
|
+
# :payments_transaction_id => "12341234567890",
|
138
|
+
# :refund_amount => 10.00,
|
139
|
+
# :reason => "CouldNotShip",
|
140
|
+
# :message => "With our apologies.")
|
141
|
+
# batch << refund
|
142
|
+
# batch.upload
|
143
|
+
#
|
144
|
+
# To follow up on the status of the upload a little while afterwards:
|
145
|
+
#
|
146
|
+
# status = client.latest_reports :batch_refund, :count => 1
|
147
|
+
# report = client.new_report(
|
148
|
+
# :batch_refund,
|
149
|
+
# :id => status[0].id)
|
150
|
+
#
|
151
|
+
# Assuming the refund was successfully processed, report.body should now output:
|
152
|
+
#
|
153
|
+
# "123-1234567-1234567order-item-id: 12341234567890\tSUCCESS 10.00 is Refunded.\r\n"
|
154
|
+
#
|
155
|
+
def new_refund_batch
|
156
|
+
Peddler::Refunds::Batch.new(self.transport.dup)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Creates a refund item that can then be added to a refund batch.
|
160
|
+
#
|
161
|
+
# Reasons can be [ "GeneralAdjustment" "CouldNotShip" "DifferentItem" "MerchandiseNotReceived" "MerchandiseNotAsDescribed" ].
|
162
|
+
def new_refund(params={})
|
163
|
+
Peddler::Refunds::Item.new(params)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Creates an instance for an already-generated report. Works only with what I call legacy reports, that is,
|
167
|
+
# anything that comes before section 7 in the API docs. Report names can be [ :upload, :order, :preorder, :batch_refund, :open_listings, :open_listings_lite, :open_listings_liter ].
|
168
|
+
#
|
169
|
+
# You can download a specific report by using its ID. Otherwise, the instance will fetch the latest available report. One
|
170
|
+
# oddball exception: upload reports do require an ID and will return nil if you don't provide one.
|
171
|
+
#
|
172
|
+
# orders_report = client.new_report :order
|
173
|
+
# orders = Peddler::Handlers::TabDelimitedHandler.decode_response(orders_report.body)
|
174
|
+
# orders[0].buyer_name
|
175
|
+
# => "John Doe"
|
176
|
+
#
|
177
|
+
# preorders_report = client.new_report(
|
178
|
+
# :preorder,
|
179
|
+
# :product_line => "Books",
|
180
|
+
# :frequency => 2)
|
181
|
+
# preorders = Peddler::Handlers::TabDelimitedHandler.decode_response(preorders_report.body)
|
182
|
+
# preorders[0].average_asking_price
|
183
|
+
# => "100"
|
184
|
+
#
|
185
|
+
def new_report(name,params={})
|
186
|
+
Peddler::LegacyReports::Report.new(self.transport.dup, name, params)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Requests a report. Returns true when successful. Name can be [ :order, :open_listings, :open_listings_lite, :open_listings_liter ].
|
190
|
+
#
|
191
|
+
# Here's some sample usage:
|
192
|
+
#
|
193
|
+
# client.generate_report :order, :number_of_days => 15
|
194
|
+
#
|
195
|
+
# client.generate_report :open_listings
|
196
|
+
#
|
197
|
+
# A word of caution. Open listings may crap up with larger inventories. I will have to migrate to a cURL-based
|
198
|
+
# HTTP client to get that working again.
|
199
|
+
def generate_report(name,params={})
|
200
|
+
Peddler::LegacyReports.generate(self.transport, name, params)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Creates an unshipped order report. Takes on some optional parameters, such as :id, :starts_at, :ends_at. By default,
|
204
|
+
# it will request a new unshipped order report for the past seven days.
|
205
|
+
#
|
206
|
+
# report = client.new_unshipped_order_report
|
207
|
+
# report.status
|
208
|
+
# => "_SUBMITTED_"
|
209
|
+
#
|
210
|
+
# Now, refresh the status until you see:
|
211
|
+
#
|
212
|
+
# report.status!
|
213
|
+
# => "_DONE_"
|
214
|
+
#
|
215
|
+
# Once done, you'll get a nifty array of unshipped orders:
|
216
|
+
#
|
217
|
+
# report.unshipped_orders
|
218
|
+
#
|
219
|
+
def new_unshipped_orders_report(params={})
|
220
|
+
Peddler::Reports::UnshippedOrdersReport.new(self.transport.dup, params)
|
221
|
+
end
|
222
|
+
|
223
|
+
# 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 ].
|
224
|
+
#
|
225
|
+
# Some sample usage:
|
226
|
+
#
|
227
|
+
# reports = client.latest_reports :order, :count => 1
|
228
|
+
# reports[0]
|
229
|
+
# => #<Peddler::LegacyReports::ReportStatus starts_at="07-29-2009:10-00-06" ...
|
230
|
+
#
|
231
|
+
def latest_reports(name,params={})
|
232
|
+
Peddler::LegacyReports.latest(self.transport, name, params)
|
233
|
+
end
|
234
|
+
|
235
|
+
protected
|
236
|
+
def transport #:nodoc:all
|
237
|
+
@transport ||= Peddler::Transport.new
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
module Peddler
|
2
|
+
# This module includes functionality to handle the charge-when-ship-related feeds Amazon added to the API
|
3
|
+
# in its latest incarnation in 2009.
|
4
|
+
module Feeds
|
5
|
+
# Downloadable file. The processing report in case of feeds. Outputs Amazon's response verbatim.
|
6
|
+
# Will add functionality to parse the response some time down the road.
|
7
|
+
class Download
|
8
|
+
attr_accessor :id, :type, :related_reference_id, :available_at, :acknowledged
|
9
|
+
|
10
|
+
def initialize(transport, params={})
|
11
|
+
@mapped_params = {
|
12
|
+
"DownloadId" => "id",
|
13
|
+
"DownloadType" => "type",
|
14
|
+
"RelatedReferenceId" => "related_reference_id",
|
15
|
+
"AvailableDate" => "available_at",
|
16
|
+
"Acknowledged" => "acknowledged"}
|
17
|
+
@transport = transport
|
18
|
+
params.each_pair{ |key, value| self.send "#{@mapped_params[key]}=", value }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Retrieves and returns report
|
22
|
+
def to_s
|
23
|
+
@body ||= download_report
|
24
|
+
end
|
25
|
+
private
|
26
|
+
def download_report
|
27
|
+
return nil if @id.nil?
|
28
|
+
@transport.modernize_request
|
29
|
+
@transport.query_params.merge!({
|
30
|
+
"Action" => "download",
|
31
|
+
"downloadId" => @id})
|
32
|
+
@transport.execute_request
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# This is the base class.
|
37
|
+
class Feed
|
38
|
+
attr_writer :file_content
|
39
|
+
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
|
40
|
+
|
41
|
+
def initialize(transport)
|
42
|
+
@transport = transport
|
43
|
+
@batch = []
|
44
|
+
@mapped_params = {
|
45
|
+
"UploadStatus" => "status",
|
46
|
+
"UploadType" => "type",
|
47
|
+
"UploadId" => "id",
|
48
|
+
"SubmittedDate" => "submitted_at",
|
49
|
+
"StartedProcessingDate" => "started_processing_at",
|
50
|
+
"CompletedProcessingDate" => "completed_processing_at",
|
51
|
+
"CompletedProcesssingDate" => "completed_processing_at",
|
52
|
+
"MessagesProcessed" => "messages_processed",
|
53
|
+
"MessagesSuccessful" => "messages_successful",
|
54
|
+
"MessagesWithErrors" => "messages_with_errors",
|
55
|
+
"MessagesWithWarnings" => "messages_with_warnings"}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns content of the upload file.
|
59
|
+
def file_content
|
60
|
+
return @file_content if @file_content
|
61
|
+
out = @file_header
|
62
|
+
@batch.each{ |item| out << item.to_s }
|
63
|
+
@file_content = out
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns status and will also refresh if not already "done."
|
67
|
+
def status!
|
68
|
+
return @status if @status.nil? || @status =~ /_DONE_/
|
69
|
+
refresh_status
|
70
|
+
@status
|
71
|
+
end
|
72
|
+
|
73
|
+
# Uploads batch.
|
74
|
+
def upload
|
75
|
+
raise PeddlerError.new("Batch already uploaded") unless @id.nil?
|
76
|
+
@transport.modernize_request
|
77
|
+
@transport.query_params.merge!({
|
78
|
+
"Action" => "upload",
|
79
|
+
"uploadType" => @type})
|
80
|
+
@transport.body = file_content
|
81
|
+
res = @transport.execute_request
|
82
|
+
process_response(res)
|
83
|
+
@status
|
84
|
+
end
|
85
|
+
|
86
|
+
# Adds an item to the batch.
|
87
|
+
def <<(item)
|
88
|
+
@batch << item
|
89
|
+
end
|
90
|
+
private
|
91
|
+
def refresh_status
|
92
|
+
@transport.modernize_request
|
93
|
+
@transport.query_params.merge!({
|
94
|
+
"Action" => "uploadStatus",
|
95
|
+
"uploadId" => @id})
|
96
|
+
res = @transport.execute_request
|
97
|
+
process_response(res)
|
98
|
+
end
|
99
|
+
|
100
|
+
def process_response(res)
|
101
|
+
xml = Peddler::Handlers::XMLHandler.decode_response(res)
|
102
|
+
params = Peddler::Handlers::XMLHandler.parse(:upload, xml)
|
103
|
+
if params[0]
|
104
|
+
params[0].each_pair do |key, value|
|
105
|
+
if key == "RelatedDownloadsList"
|
106
|
+
params = Peddler::Handlers::XMLHandler.parse(:download, value)
|
107
|
+
@download = Peddler::Feeds::Download.new(@transport, params[0])
|
108
|
+
else
|
109
|
+
self.send "#{@mapped_params[key]}=", value
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
module OrderFulfillment
|
117
|
+
# This class contains methods to upload order fulfillment info to Amazon.
|
118
|
+
# See sections 7.1 through 7.3 in the API documentation for more detail.
|
119
|
+
class Batch < Peddler::Feeds::Feed
|
120
|
+
def initialize(transport)
|
121
|
+
@file_header = "order-id\torder-item-id\tquantity\tship-date\tcarrier-code\tcarrier-name\ttracking-number\tship-method\r\n"
|
122
|
+
@type = "_POST_FLAT_FILE_FULFILLMENT_DATA_"
|
123
|
+
super(transport)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# This is an order fulfillment item.
|
128
|
+
class Item
|
129
|
+
attr_accessor :order_id, :order_item_id, :quantity, :ship_date, :carrier_name, :tracking_number, :ship_method
|
130
|
+
attr_reader :carrier_code
|
131
|
+
|
132
|
+
def initialize(params={})
|
133
|
+
params.each_pair{ |key, value| send("#{key}=", value) }
|
134
|
+
end
|
135
|
+
|
136
|
+
# Validates when setting carrier code.
|
137
|
+
def carrier_code=(carrier_code)
|
138
|
+
@carrier_code = carrier_code if %w{USPS UPS FedEx other}.include?(carrier_code)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Outputs a formatted line for the tab-delimited upload file.
|
142
|
+
def to_s
|
143
|
+
"#{@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"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# This module contains methods to upload cancelled orders to Amazon.
|
149
|
+
# See section 7.4 in the API documentation for more detail.
|
150
|
+
module OrderCancellation
|
151
|
+
class Batch < Peddler::Feeds::Feed
|
152
|
+
def initialize(transport)
|
153
|
+
@file_header = "TemplateType=OrderCancellation Version=1.0/1.0.3 This row for Amazon.com use only. Do not modify or delete.\r\n" +
|
154
|
+
"order-id\tcancellation-reason-code\tamazon-order-item-code\r\n"
|
155
|
+
@type = "_POST_FLAT_FILE_ORDER_ACKNOWLEDGEMENT_DATA_"
|
156
|
+
super(transport)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# This is a cancelled order item.
|
161
|
+
class Item
|
162
|
+
attr_accessor :order_id, :amazon_order_item_code
|
163
|
+
attr_reader :cancellation_reason_code
|
164
|
+
|
165
|
+
def initialize(params={})
|
166
|
+
params.each_pair{ |key, value| send("#{key}=", value) }
|
167
|
+
end
|
168
|
+
|
169
|
+
# Validates when setting cancellation reason code.
|
170
|
+
def cancellation_reason_code=(cancellation_reason_code)
|
171
|
+
@cancellation_reason_code = cancellation_reason_code if %w{ BuyerCanceled CustomerExchange CustomerReturn GeneralAdjustment MerchandiseNotReceived NoInventory ShippingAddressUndeliverable }.include?(cancellation_reason_code)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Outputs a formatted line for the tab-delimited upload file.
|
175
|
+
def to_s
|
176
|
+
"#{@order_id}\t#{@cancellation_reason_code}\t#{@amazon_order_item_code}\r\n"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|