snl-peddler 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +3 -1
- data/README.rdoc +41 -22
- data/VERSION.yml +1 -1
- data/lib/peddler/client.rb +31 -56
- data/lib/peddler/feeds.rb +3 -0
- data/lib/peddler/handlers.rb +1 -1
- data/peddler.gemspec +1 -1
- data/spec/peddler/feeds_spec.rb +10 -0
- metadata +1 -1
data/History.txt
CHANGED
data/README.rdoc
CHANGED
@@ -22,42 +22,28 @@ Create an inventory file:
|
|
22
22
|
batch << item
|
23
23
|
...
|
24
24
|
|
25
|
-
Repeat ad infinitum and
|
25
|
+
Repeat ad infinitum and upload:
|
26
26
|
|
27
27
|
batch.upload
|
28
28
|
|
29
|
-
The batch now should have an upload ID
|
29
|
+
The batch now should have an upload ID. Go ahead and check the error log:
|
30
30
|
|
31
31
|
upload_log = client.new_report(
|
32
32
|
:upload,
|
33
33
|
:id => batch.id)
|
34
34
|
upload_log.body
|
35
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
|
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:
|
36
|
+
|
37
|
+
You're done listing and are wondering if you have any new orders:
|
52
38
|
|
53
39
|
orders_report = client.new_report :order
|
54
|
-
orders =
|
40
|
+
orders = client.detab(orders_report.body)
|
55
41
|
p orders.size
|
56
42
|
=> 1500
|
57
43
|
p orders[0].item_name
|
58
44
|
=> "A Thousand Plateaus: Capitalism and Schizophrenia (Paperback) by Gilles Deleuze"
|
59
45
|
|
60
|
-
|
46
|
+
Now that you have diligently processed the orders, post back the results to Amazon:
|
61
47
|
|
62
48
|
feed = client.new_order_fulfillment_feed
|
63
49
|
fulfilled_order = new_fulfilled_order(
|
@@ -86,11 +72,13 @@ Finally, check the report:
|
|
86
72
|
p feed.download.to_s
|
87
73
|
=> ...
|
88
74
|
|
89
|
-
Sadly, you also have an order you can't fulfill. No problem. The workflow is
|
75
|
+
Sadly, you also have an order you can't fulfill. No problem. The workflow is similar:
|
90
76
|
|
91
77
|
feed = client.new_order_cancellation_feed
|
92
78
|
cancelled_order = new_cancelled_order(
|
93
|
-
:order_id => "123-1234567-1234567"
|
79
|
+
:order_id => "123-1234567-1234567",
|
80
|
+
:cancellation_reason_code => "NoInventory",
|
81
|
+
:amazon_order_item_code => "12341234567890")
|
94
82
|
feed << cancelled_order
|
95
83
|
feed.upload
|
96
84
|
sleep(60)
|
@@ -99,6 +87,37 @@ Sadly, you also have an order you can't fulfill. No problem. The workflow is qui
|
|
99
87
|
p feed.download.to_s
|
100
88
|
=> ...
|
101
89
|
|
90
|
+
Need to post a partial refund? You'll have to revert to the older batch refund API thingie:
|
91
|
+
|
92
|
+
refunds = client.new_refund_batch
|
93
|
+
refund = client.new_refund(
|
94
|
+
:order_id => "123-1234567-1234567",
|
95
|
+
:payments_transaction_id => "12341234567890",
|
96
|
+
:refund_amount => 1.00,
|
97
|
+
:reason => "GeneralAdjustment",
|
98
|
+
:message => "With our apologies.")
|
99
|
+
refunds << refund
|
100
|
+
refunds.upload
|
101
|
+
|
102
|
+
Great sales. For a change, let's download something different from Amazon. Here's a preorder report:
|
103
|
+
|
104
|
+
preorder_report = client.new_report(
|
105
|
+
:preorder,
|
106
|
+
:product_line => "Books",
|
107
|
+
:frequency => 2)
|
108
|
+
preorders = client.detab(preorder_report.body)
|
109
|
+
p preorders.size
|
110
|
+
=> 2000
|
111
|
+
p preorders[0].asin
|
112
|
+
=> "1234567890"
|
113
|
+
p preorders[0].average_asking_price
|
114
|
+
=> "100"
|
115
|
+
|
102
116
|
Run rdoc and check the source for more detailed info.
|
103
117
|
|
118
|
+
== Todos
|
119
|
+
|
120
|
+
* Replace Net::Http with a cURL-based client as former craps up with very large file downloads.
|
121
|
+
* Add some more parsers.
|
122
|
+
|
104
123
|
Copyright © 2009 Hakan Senol Ensari, released under the MIT license
|
data/VERSION.yml
CHANGED
data/lib/peddler/client.rb
CHANGED
@@ -23,15 +23,15 @@ module Peddler
|
|
23
23
|
self.transport.password = password
|
24
24
|
end
|
25
25
|
|
26
|
-
# Sets Amazon region.
|
26
|
+
# Sets Amazon region.
|
27
|
+
#
|
28
|
+
# Possible regions: ["us", "uk", "de", "ca", "fr", "jp"]
|
27
29
|
def region=(region)
|
28
30
|
self.transport.region = region
|
29
31
|
end
|
30
32
|
|
31
33
|
# Creates an inventory batch.
|
32
34
|
#
|
33
|
-
# A sample workflow:
|
34
|
-
#
|
35
35
|
# batch = client.new_inventory_batch
|
36
36
|
# book = new_inventory_item(
|
37
37
|
# :product_id => "1234567890",
|
@@ -40,16 +40,9 @@ module Peddler
|
|
40
40
|
# :quantity => 1)
|
41
41
|
# batch << book
|
42
42
|
# batch.upload
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
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"
|
43
|
+
# report = client.new_report :upload, :id => batch.id
|
44
|
+
# p report.body
|
45
|
+
# => "Feed Processing Summary:\n\tNumber of records processed\t\t1\n\tNumber of records successful\t\t1\n\n"
|
53
46
|
#
|
54
47
|
def new_inventory_batch
|
55
48
|
Peddler::Inventory::Batch.new(self.transport.dup)
|
@@ -68,8 +61,6 @@ module Peddler
|
|
68
61
|
|
69
62
|
# Creates an order fulfillment batch.
|
70
63
|
#
|
71
|
-
# A sample workflow:
|
72
|
-
#
|
73
64
|
# feed = client.new_order_fulfillment_feed
|
74
65
|
# fulfilled_order = new_fulfilled_order(
|
75
66
|
# :order_id => "123-1234567-1234567",
|
@@ -78,15 +69,10 @@ module Peddler
|
|
78
69
|
# feed.upload
|
79
70
|
# feed.status
|
80
71
|
# => "_SUBMITTED_"
|
81
|
-
#
|
82
|
-
# Now, refresh the status until you see:
|
83
|
-
#
|
72
|
+
# sleep(60)
|
84
73
|
# feed.status!
|
85
74
|
# => "_DONE_"
|
86
|
-
#
|
87
|
-
# Finally, check the processing report:
|
88
|
-
#
|
89
|
-
# feed.download.to_s
|
75
|
+
# p feed.download.to_s
|
90
76
|
#
|
91
77
|
def new_order_fulfillment_feed
|
92
78
|
Peddler::Feeds::OrderFulfillment::Batch.new(self.transport.dup)
|
@@ -100,24 +86,19 @@ module Peddler
|
|
100
86
|
|
101
87
|
# Creates an order cancellation batch.
|
102
88
|
#
|
103
|
-
# A sample workflow:
|
104
|
-
#
|
105
89
|
# feed = client.new_order_cancellation_feed
|
106
90
|
# cancelled_order = new_cancelled_order(
|
107
|
-
# :order_id => "123-1234567-1234567"
|
91
|
+
# :order_id => "123-1234567-1234567",
|
92
|
+
# :cancellation_reason_code => "NoInventory",
|
93
|
+
# :amazon_order_item_code => "12341234567890")
|
108
94
|
# feed << cancelled_order
|
109
95
|
# feed.upload
|
110
96
|
# feed.status
|
111
97
|
# => "_SUBMITTED_"
|
112
|
-
#
|
113
|
-
# Now, refresh the status until you see:
|
114
|
-
#
|
98
|
+
# sleep(60)
|
115
99
|
# feed.status!
|
116
100
|
# => "_DONE_"
|
117
|
-
#
|
118
|
-
# Finally, check the processing report:
|
119
|
-
#
|
120
|
-
# feed.download.to_s
|
101
|
+
# p feed.download.to_s
|
121
102
|
#
|
122
103
|
def new_order_cancellation_feed
|
123
104
|
Peddler::Feeds::OrderCancellation::Batch.new(self.transport.dup)
|
@@ -140,17 +121,13 @@ module Peddler
|
|
140
121
|
# :message => "With our apologies.")
|
141
122
|
# batch << refund
|
142
123
|
# batch.upload
|
143
|
-
#
|
144
|
-
# To follow up on the status of the upload a little while afterwards:
|
145
|
-
#
|
124
|
+
# sleep(60)
|
146
125
|
# status = client.latest_reports :batch_refund, :count => 1
|
147
126
|
# report = client.new_report(
|
148
127
|
# :batch_refund,
|
149
128
|
# :id => status[0].id)
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
# "123-1234567-1234567order-item-id: 12341234567890\tSUCCESS 10.00 is Refunded.\r\n"
|
129
|
+
# p report.body
|
130
|
+
# => "123-1234567-1234567order-item-id: 12341234567890\tSUCCESS 10.00 is Refunded.\r\n"
|
154
131
|
#
|
155
132
|
def new_refund_batch
|
156
133
|
Peddler::Refunds::Batch.new(self.transport.dup)
|
@@ -158,19 +135,21 @@ module Peddler
|
|
158
135
|
|
159
136
|
# Creates a refund item that can then be added to a refund batch.
|
160
137
|
#
|
161
|
-
#
|
138
|
+
# Possible reasons: ["GeneralAdjustment", "CouldNotShip", "DifferentItem", "MerchandiseNotReceived", "MerchandiseNotAsDescribed"]
|
162
139
|
def new_refund(params={})
|
163
140
|
Peddler::Refunds::Item.new(params)
|
164
141
|
end
|
165
142
|
|
166
143
|
# 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.
|
144
|
+
# anything that comes before section 7 in the API docs.
|
145
|
+
#
|
146
|
+
# Possible report names: [:upload, :order, :preorder, :batch_refund, :open_listings, :open_listings_lite, :open_listings_liter]
|
168
147
|
#
|
169
148
|
# You can download a specific report by using its ID. Otherwise, the instance will fetch the latest available report. One
|
170
149
|
# oddball exception: upload reports do require an ID and will return nil if you don't provide one.
|
171
150
|
#
|
172
151
|
# orders_report = client.new_report :order
|
173
|
-
# orders =
|
152
|
+
# orders = client.detab(orders_report.body)
|
174
153
|
# orders[0].buyer_name
|
175
154
|
# => "John Doe"
|
176
155
|
#
|
@@ -178,7 +157,7 @@ module Peddler
|
|
178
157
|
# :preorder,
|
179
158
|
# :product_line => "Books",
|
180
159
|
# :frequency => 2)
|
181
|
-
# preorders =
|
160
|
+
# preorders = client.detab(preorders_report.body)
|
182
161
|
# preorders[0].average_asking_price
|
183
162
|
# => "100"
|
184
163
|
#
|
@@ -186,14 +165,12 @@ module Peddler
|
|
186
165
|
Peddler::LegacyReports::Report.new(self.transport.dup, name, params)
|
187
166
|
end
|
188
167
|
|
189
|
-
# Requests a report. Returns true when successful.
|
168
|
+
# Requests a report. Returns true when successful.
|
190
169
|
#
|
191
|
-
#
|
170
|
+
# Possible report names: [:order, :open_listings, :open_listings_lite, :open_listings_liter]
|
192
171
|
#
|
193
172
|
# client.generate_report :order, :number_of_days => 15
|
194
173
|
#
|
195
|
-
# client.generate_report :open_listings
|
196
|
-
#
|
197
174
|
# A word of caution. Open listings may crap up with larger inventories. I will have to migrate to a cURL-based
|
198
175
|
# HTTP client to get that working again.
|
199
176
|
def generate_report(name,params={})
|
@@ -206,15 +183,10 @@ module Peddler
|
|
206
183
|
# report = client.new_unshipped_order_report
|
207
184
|
# report.status
|
208
185
|
# => "_SUBMITTED_"
|
209
|
-
#
|
210
|
-
# Now, refresh the status until you see:
|
211
|
-
#
|
186
|
+
# sleep(60)
|
212
187
|
# report.status!
|
213
188
|
# => "_DONE_"
|
214
|
-
#
|
215
|
-
# Once done, you'll get a nifty array of unshipped orders:
|
216
|
-
#
|
217
|
-
# report.unshipped_orders
|
189
|
+
# p report.unshipped_orders
|
218
190
|
#
|
219
191
|
def new_unshipped_orders_report(params={})
|
220
192
|
Peddler::Reports::UnshippedOrdersReport.new(self.transport.dup, params)
|
@@ -222,8 +194,6 @@ module Peddler
|
|
222
194
|
|
223
195
|
# 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
196
|
#
|
225
|
-
# Some sample usage:
|
226
|
-
#
|
227
197
|
# reports = client.latest_reports :order, :count => 1
|
228
198
|
# reports[0]
|
229
199
|
# => #<Peddler::LegacyReports::ReportStatus starts_at="07-29-2009:10-00-06" ...
|
@@ -232,6 +202,11 @@ module Peddler
|
|
232
202
|
Peddler::LegacyReports.latest(self.transport, name, params)
|
233
203
|
end
|
234
204
|
|
205
|
+
# Decodes tab-delimited content into an array of OpenStruct objects.
|
206
|
+
def detab(msg)
|
207
|
+
Peddler::Handlers::TabDelimitedHandler.decode_response(msg)
|
208
|
+
end
|
209
|
+
|
235
210
|
protected
|
236
211
|
def transport #:nodoc:all
|
237
212
|
@transport ||= Peddler::Transport.new
|
data/lib/peddler/feeds.rb
CHANGED
@@ -173,6 +173,9 @@ module Peddler
|
|
173
173
|
|
174
174
|
# Outputs a formatted line for the tab-delimited upload file.
|
175
175
|
def to_s
|
176
|
+
if @cancellation_reason_code.nil? != @amazon_order_item_code.nil?
|
177
|
+
raise PeddlerError.new("Provide codes for both cancellation reason and Amazon order item (or omit both).")
|
178
|
+
end
|
176
179
|
"#{@order_id}\t#{@cancellation_reason_code}\t#{@amazon_order_item_code}\r\n"
|
177
180
|
end
|
178
181
|
end
|
data/lib/peddler/handlers.rb
CHANGED
@@ -38,7 +38,7 @@ module Peddler
|
|
38
38
|
end
|
39
39
|
|
40
40
|
class TabDelimitedHandler
|
41
|
-
#
|
41
|
+
# Decodes tab-delimited content into an array of OpenStruct objects.
|
42
42
|
def self.decode_response(res)
|
43
43
|
lines = res.split("\n")
|
44
44
|
if lines.size > 1
|
data/peddler.gemspec
CHANGED
data/spec/peddler/feeds_spec.rb
CHANGED
@@ -64,6 +64,16 @@ module Peddler
|
|
64
64
|
@feed << @cancelled_order
|
65
65
|
@feed.file_content.should == "TemplateType=OrderCancellation Version=1.0/1.0.3 This row for Amazon.com use only. Do not modify or delete.\r\norder-id\tcancellation-reason-code\tamazon-order-item-code\r\n123-1234567-1234567\t\t\r\n"
|
66
66
|
end
|
67
|
+
|
68
|
+
it "should raise error if cancellation reason code is given but Amazon order item code is missing" do
|
69
|
+
@cancelled_order.cancellation_reason_code = "BuyerCanceled"
|
70
|
+
lambda { @cancelled_order.to_s }.should raise_error(PeddlerError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should raise error if Amazon order item code is given but cancellation reason code is missing" do
|
74
|
+
@cancelled_order.amazon_order_item_code = "111111111111"
|
75
|
+
lambda { @cancelled_order.to_s }.should raise_error(PeddlerError)
|
76
|
+
end
|
67
77
|
end
|
68
78
|
end
|
69
79
|
end
|