snl-peddler 0.1.0 → 0.1.1
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.
- 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
|