mws-connect 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.sublime-project +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +111 -0
- data/Rakefile +1 -0
- data/lib/mws.rb +34 -0
- data/lib/mws/apis.rb +6 -0
- data/lib/mws/apis/feeds.rb +20 -0
- data/lib/mws/apis/feeds/api.rb +103 -0
- data/lib/mws/apis/feeds/distance.rb +23 -0
- data/lib/mws/apis/feeds/feed.rb +114 -0
- data/lib/mws/apis/feeds/image_listing.rb +44 -0
- data/lib/mws/apis/feeds/inventory.rb +77 -0
- data/lib/mws/apis/feeds/measurement.rb +32 -0
- data/lib/mws/apis/feeds/money.rb +31 -0
- data/lib/mws/apis/feeds/price_listing.rb +48 -0
- data/lib/mws/apis/feeds/product.rb +173 -0
- data/lib/mws/apis/feeds/sale_price.rb +31 -0
- data/lib/mws/apis/feeds/shipping.rb +160 -0
- data/lib/mws/apis/feeds/submission_info.rb +45 -0
- data/lib/mws/apis/feeds/submission_result.rb +87 -0
- data/lib/mws/apis/feeds/transaction.rb +37 -0
- data/lib/mws/apis/feeds/weight.rb +19 -0
- data/lib/mws/apis/orders.rb +23 -0
- data/lib/mws/connection.rb +84 -0
- data/lib/mws/enum.rb +81 -0
- data/lib/mws/errors.rb +32 -0
- data/lib/mws/query.rb +45 -0
- data/lib/mws/serializer.rb +81 -0
- data/lib/mws/signer.rb +20 -0
- data/lib/mws/utils.rb +50 -0
- data/mws.gemspec +25 -0
- data/scripts/catalog-workflow +136 -0
- data/spec/mws/apis/feeds/api_spec.rb +229 -0
- data/spec/mws/apis/feeds/distance_spec.rb +43 -0
- data/spec/mws/apis/feeds/feed_spec.rb +92 -0
- data/spec/mws/apis/feeds/image_listing_spec.rb +109 -0
- data/spec/mws/apis/feeds/inventory_spec.rb +135 -0
- data/spec/mws/apis/feeds/measurement_spec.rb +84 -0
- data/spec/mws/apis/feeds/money_spec.rb +43 -0
- data/spec/mws/apis/feeds/price_listing_spec.rb +90 -0
- data/spec/mws/apis/feeds/product_spec.rb +264 -0
- data/spec/mws/apis/feeds/shipping_spec.rb +78 -0
- data/spec/mws/apis/feeds/submission_info_spec.rb +111 -0
- data/spec/mws/apis/feeds/submission_result_spec.rb +157 -0
- data/spec/mws/apis/feeds/transaction_spec.rb +64 -0
- data/spec/mws/apis/feeds/weight_spec.rb +43 -0
- data/spec/mws/apis/orders_spec.rb +9 -0
- data/spec/mws/connection_spec.rb +331 -0
- data/spec/mws/enum_spec.rb +166 -0
- data/spec/mws/query_spec.rb +104 -0
- data/spec/mws/serializer_spec.rb +187 -0
- data/spec/mws/signer_spec.rb +67 -0
- data/spec/mws/utils_spec.rb +147 -0
- data/spec/spec_helper.rb +10 -0
- metadata +220 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Mws::Apis::Feeds
|
4
|
+
|
5
|
+
describe Money do
|
6
|
+
|
7
|
+
context '.new' do
|
8
|
+
|
9
|
+
it 'should default to usd' do
|
10
|
+
money = Money.new 40
|
11
|
+
money.amount.should == 40
|
12
|
+
money.currency.should == :usd
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should accept a valid currency override' do
|
16
|
+
money = Money.new 0, :eur
|
17
|
+
money.amount.should == 0
|
18
|
+
money.currency.should == :eur
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should validate the currency override' do
|
22
|
+
expect {
|
23
|
+
Money.new 40, :acres
|
24
|
+
}.to raise_error Mws::Errors::ValidationError, "Invalid currency 'acres'"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#to_xml' do
|
30
|
+
|
31
|
+
it 'should properly serialize to XML' do
|
32
|
+
money = Money.new 25, :cad
|
33
|
+
expected = Nokogiri::XML::Builder.new do
|
34
|
+
Price '25.00', currency: 'CAD'
|
35
|
+
end.doc.root.to_xml
|
36
|
+
money.to_xml.should == expected
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Mws::Apis::Feeds
|
4
|
+
|
5
|
+
describe PriceListing do
|
6
|
+
|
7
|
+
context '.new' do
|
8
|
+
|
9
|
+
it 'should be able to construct a price with only sku and base price' do
|
10
|
+
price = PriceListing.new('987612345', 14.99)
|
11
|
+
price.sku.should == '987612345'
|
12
|
+
price.currency.should == :usd
|
13
|
+
price.base.should == Money.new(14.99, :usd)
|
14
|
+
price.min.should be nil
|
15
|
+
price.sale.should be nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be able to construct a price with custom currency code' do
|
19
|
+
price = PriceListing.new('9876123456', 14.99, currency: :eur)
|
20
|
+
price.currency.should == :eur
|
21
|
+
price.base.should == Money.new(14.99, :eur)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should be able to construct a price with custom minimum advertised price' do
|
25
|
+
price = PriceListing.new('987612345', 14.99, min: 11.99)
|
26
|
+
price.min.should == Money.new(11.99, :usd)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should be able to construct a new price with custom sale price' do
|
30
|
+
from = 1.day.ago
|
31
|
+
to = 4.months.from_now
|
32
|
+
price = PriceListing.new('987612345', 14.99, sale: {
|
33
|
+
amount: 12.99,
|
34
|
+
from: from,
|
35
|
+
to: to
|
36
|
+
})
|
37
|
+
price.sale.should == SalePrice.new(Money.new(12.99, :usd), from, to)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should validate that the base price is less than the minimum advertised price' do
|
41
|
+
expect {
|
42
|
+
PriceListing.new('987612345', 9.99, min: 10.00)
|
43
|
+
}.to raise_error Mws::Errors::ValidationError, "'Base Price' must be greater than 'Minimum Advertised Price'."
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should validate that the sale price is less than the minimum advertised price' do
|
47
|
+
expect {
|
48
|
+
PriceListing.new('987612345', 14.99, min: 10.00).on_sale(9.99, 1.day.ago, 4.months.from_now)
|
49
|
+
}.to raise_error Mws::Errors::ValidationError, "'Sale Price' must be greater than 'Minimum Advertised Price'."
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
context '#on_sale' do
|
55
|
+
|
56
|
+
it 'should provide a nicer syntax for specifying the sale price' do
|
57
|
+
from = 1.day.ago
|
58
|
+
to = 4.months.from_now
|
59
|
+
price = PriceListing.new('987612345', 14.99).on_sale(12.99, from, to)
|
60
|
+
price.sale.should == SalePrice.new(Money.new(12.99, :usd) , from, to)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
context '#to_xml' do
|
66
|
+
|
67
|
+
it 'should properly serialize to XML' do
|
68
|
+
from = 1.day.ago
|
69
|
+
to = 4.months.from_now
|
70
|
+
price = PriceListing.new('987612345', 14.99, currency: :eur, min: 10.99).on_sale(12.99, from, to)
|
71
|
+
expected = Nokogiri::XML::Builder.new do
|
72
|
+
Price {
|
73
|
+
SKU '987612345'
|
74
|
+
StandardPrice '14.99', currency: 'EUR'
|
75
|
+
MAP '10.99', currency: 'EUR'
|
76
|
+
Sale {
|
77
|
+
StartDate from.iso8601
|
78
|
+
EndDate to.iso8601
|
79
|
+
SalePrice '12.99', currency: 'EUR'
|
80
|
+
}
|
81
|
+
}
|
82
|
+
end.doc.root.to_xml
|
83
|
+
price.to_xml.should == expected
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,264 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module Mws::Apis::Feeds
|
5
|
+
|
6
|
+
describe Product do
|
7
|
+
|
8
|
+
context '.new' do
|
9
|
+
|
10
|
+
it 'should require a sku' do
|
11
|
+
expect { Product.new }.to raise_error ArgumentError
|
12
|
+
|
13
|
+
sku = '12343533'
|
14
|
+
Product.new(sku).sku.should == sku
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should support product builder block initialization' do
|
18
|
+
capture = nil
|
19
|
+
product = Product.new('123431') do
|
20
|
+
capture = self
|
21
|
+
end
|
22
|
+
capture.should be_an_instance_of Product::ProductBuilder
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should support building with upc, tax code, brand, manufacture and name' do
|
26
|
+
product = Product.new('12324') do
|
27
|
+
upc '4321'
|
28
|
+
tax_code 'GEN_TAX_CODE'
|
29
|
+
brand 'Test Brand'
|
30
|
+
manufacturer 'Test manufacture'
|
31
|
+
name 'Test Product'
|
32
|
+
end
|
33
|
+
|
34
|
+
product.upc.should == '4321'
|
35
|
+
product.tax_code.should == 'GEN_TAX_CODE'
|
36
|
+
product.brand.should == 'Test Brand'
|
37
|
+
product.manufacturer.should == 'Test manufacture'
|
38
|
+
product.name.should == 'Test Product'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should support building with msrp' do
|
42
|
+
product = Product.new('12324') do
|
43
|
+
msrp 10.99, :usd
|
44
|
+
end
|
45
|
+
|
46
|
+
product.msrp.amount.should == 10.99
|
47
|
+
product.msrp.currency.should == :usd
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should support building with item dimensions' do
|
51
|
+
product = Product.new('12324') do
|
52
|
+
item_dimensions {
|
53
|
+
length 2, :feet
|
54
|
+
width 3, :inches
|
55
|
+
height 1, :meters
|
56
|
+
weight 4, :pounds
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
product.item_dimensions.length.should == Distance.new(2, :feet)
|
61
|
+
product.item_dimensions.width.should == Distance.new(3, :inches)
|
62
|
+
product.item_dimensions.height.should == Distance.new(1, :meters)
|
63
|
+
product.item_dimensions.weight.should == Weight.new(4, :pounds)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should support building with package dimensions' do
|
67
|
+
product = Product.new('12324') do
|
68
|
+
package_dimensions {
|
69
|
+
length 2, :feet
|
70
|
+
width 3, :inches
|
71
|
+
height 1, :meters
|
72
|
+
weight 4, :pounds
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
product.package_dimensions.length.should == Distance.new(2, :feet)
|
77
|
+
product.package_dimensions.width.should == Distance.new(3, :inches)
|
78
|
+
product.package_dimensions.height.should == Distance.new(1, :meters)
|
79
|
+
product.package_dimensions.weight.should == Weight.new(4, :pounds)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should require valid package and shipping dimensions' do
|
83
|
+
capture = self
|
84
|
+
product = Product.new('12324') do
|
85
|
+
package_dimensions {
|
86
|
+
capture.expect { length 2, :foots }.to capture.raise_error Mws::Errors::ValidationError
|
87
|
+
capture.expect { width 2, :decades }.to capture.raise_error Mws::Errors::ValidationError
|
88
|
+
capture.expect { height 1, :miles }.to capture.raise_error Mws::Errors::ValidationError
|
89
|
+
capture.expect { weight 1, :stone }.to capture.raise_error Mws::Errors::ValidationError
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should support building with description and bullet points' do
|
95
|
+
product = Product.new('12343') do
|
96
|
+
description 'This is a test product description.'
|
97
|
+
bullet_point 'Bullet Point 1'
|
98
|
+
bullet_point 'Bullet Point 2'
|
99
|
+
bullet_point 'Bullet Point 3'
|
100
|
+
bullet_point 'Bullet Point 4'
|
101
|
+
end
|
102
|
+
product.description.should == 'This is a test product description.'
|
103
|
+
product.bullet_points.length.should == 4
|
104
|
+
product.bullet_points[0].should == 'Bullet Point 1'
|
105
|
+
product.bullet_points[1].should == 'Bullet Point 2'
|
106
|
+
product.bullet_points[2].should == 'Bullet Point 3'
|
107
|
+
product.bullet_points[3].should == 'Bullet Point 4'
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
it 'should support building with package and shipping weight' do
|
112
|
+
product = Product.new('12343') do
|
113
|
+
package_weight 3, :pounds
|
114
|
+
shipping_weight 4, :ounces
|
115
|
+
end
|
116
|
+
|
117
|
+
product.package_weight.should == Weight.new(3, :pounds)
|
118
|
+
product.shipping_weight.should == Weight.new(4, :ounces)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should support building with product details' do
|
122
|
+
product = Product.new '12343' do
|
123
|
+
category :ce
|
124
|
+
details {
|
125
|
+
value 'some value'
|
126
|
+
nested {
|
127
|
+
foo 'bar'
|
128
|
+
nested {
|
129
|
+
baz 'bahhh'
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
product.details.should_not be nil
|
136
|
+
product.details[:value].should == 'some value'
|
137
|
+
product.details[:nested][:foo].should == 'bar'
|
138
|
+
product.details[:nested][:nested][:baz].should == 'bahhh'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should require a category when product details are specified' do
|
142
|
+
expect {
|
143
|
+
Product.new '12343' do
|
144
|
+
details {
|
145
|
+
value 'some value'
|
146
|
+
nested {
|
147
|
+
foo 'bar'
|
148
|
+
nested {
|
149
|
+
baz 'bahhh'
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
end
|
154
|
+
}.to raise_error Mws::Errors::ValidationError, 'Product must have a category when details are specified.'
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
context '#to_xml' do
|
160
|
+
|
161
|
+
it 'should create xml for standard attributes' do
|
162
|
+
|
163
|
+
expected = Nokogiri::XML::Builder.new do
|
164
|
+
Product {
|
165
|
+
SKU '12343'
|
166
|
+
StandardProductID {
|
167
|
+
Type 'UPC'
|
168
|
+
Value '432154321'
|
169
|
+
}
|
170
|
+
ProductTaxCode 'GEN_TAX_CODE'
|
171
|
+
DescriptionData {
|
172
|
+
Title 'Test Product'
|
173
|
+
Brand 'Test Brand'
|
174
|
+
Description 'Some product'
|
175
|
+
BulletPoint 'Bullet Point 1'
|
176
|
+
BulletPoint 'Bullet Point 2'
|
177
|
+
BulletPoint 'Bullet Point 3'
|
178
|
+
BulletPoint 'Bullet Point 4'
|
179
|
+
ItemDimensions {
|
180
|
+
Length 2, unitOfMeasure: 'feet'
|
181
|
+
Width 3, unitOfMeasure: 'inches'
|
182
|
+
Height 1, unitOfMeasure: 'meters'
|
183
|
+
Weight 4, unitOfMeasure: 'LB'
|
184
|
+
}
|
185
|
+
PackageDimensions {
|
186
|
+
Length 2, unitOfMeasure: 'feet'
|
187
|
+
Width 3, unitOfMeasure: 'inches'
|
188
|
+
Height 1, unitOfMeasure: 'meters'
|
189
|
+
Weight 4, unitOfMeasure: 'LB'
|
190
|
+
}
|
191
|
+
PackageWeight 2, unitOfMeasure: 'LB'
|
192
|
+
ShippingWeight 3, unitOfMeasure: 'MG'
|
193
|
+
MSRP 19.99, currency: 'USD'
|
194
|
+
Manufacturer 'Test manufacture'
|
195
|
+
}
|
196
|
+
}
|
197
|
+
end.doc.root.to_xml
|
198
|
+
|
199
|
+
expected.should == Product.new('12343') do
|
200
|
+
upc '432154321'
|
201
|
+
tax_code 'GEN_TAX_CODE'
|
202
|
+
brand 'Test Brand'
|
203
|
+
name 'Test Product'
|
204
|
+
description 'Some product'
|
205
|
+
msrp 19.99, 'USD'
|
206
|
+
manufacturer 'Test manufacture'
|
207
|
+
bullet_point 'Bullet Point 1'
|
208
|
+
bullet_point 'Bullet Point 2'
|
209
|
+
bullet_point 'Bullet Point 3'
|
210
|
+
bullet_point 'Bullet Point 4'
|
211
|
+
item_dimensions {
|
212
|
+
length 2, :feet
|
213
|
+
width 3, :inches
|
214
|
+
height 1, :meters
|
215
|
+
weight 4, :pounds
|
216
|
+
}
|
217
|
+
package_dimensions {
|
218
|
+
length 2, :feet
|
219
|
+
width 3, :inches
|
220
|
+
height 1, :meters
|
221
|
+
weight 4, :pounds
|
222
|
+
}
|
223
|
+
package_weight 2, :pounds
|
224
|
+
shipping_weight 3, :miligrams
|
225
|
+
end.to_xml
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should create xml for product details' do
|
230
|
+
expected = Nokogiri::XML::Builder.new do
|
231
|
+
Product {
|
232
|
+
SKU '12343'
|
233
|
+
DescriptionData {}
|
234
|
+
ProductData {
|
235
|
+
CE {
|
236
|
+
ProductType {
|
237
|
+
CableOrAdapter {
|
238
|
+
CableLength 6, unitOfMeasure: 'feet'
|
239
|
+
CableWeight 6, unitOfMeasure: 'OZ'
|
240
|
+
CostSavings '6.99', currency: 'USD'
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
}
|
246
|
+
end.doc.root.to_xml
|
247
|
+
|
248
|
+
expected.should == Product.new('12343') do
|
249
|
+
category :ce
|
250
|
+
details {
|
251
|
+
cable_or_adapter {
|
252
|
+
cable_length as_distance 6, :feet
|
253
|
+
cable_weight as_weight 6, :ounces
|
254
|
+
cost_savings as_money 6.99, :usd
|
255
|
+
}
|
256
|
+
}
|
257
|
+
end.to_xml
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Mws::Apis::Feeds
|
4
|
+
|
5
|
+
describe Shipping do
|
6
|
+
|
7
|
+
context '.new' do
|
8
|
+
|
9
|
+
it 'should require non-nil sku' do
|
10
|
+
expect { Shipping.new(nil) }.to raise_error Mws::Errors::ValidationError,
|
11
|
+
'SKU is required.'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should require a non-empty sku' do
|
15
|
+
expect { Shipping.new('') }.to raise_error Mws::Errors::ValidationError,
|
16
|
+
'SKU is required.'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should require a sku that is not all whitespace' do
|
20
|
+
expect { Shipping.new(' ') }.to raise_error Mws::Errors::ValidationError,
|
21
|
+
'SKU is required.'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should accept a valid value for sku' do
|
25
|
+
Shipping.new('987612345').sku.should == '987612345'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should accept a block to associate shipping option overrides' do
|
29
|
+
shipping = Shipping.new('987612345') do
|
30
|
+
replace 4.99, :usd, :continental_us, :standard, :street
|
31
|
+
end
|
32
|
+
shipping.sku.should == '987612345'
|
33
|
+
shipping.options.size.should == 1
|
34
|
+
override = shipping.options.first
|
35
|
+
override.amount.should == Money.new(4.99, :usd)
|
36
|
+
override.option.region.should == :continental_us
|
37
|
+
override.option.speed.should == :standard
|
38
|
+
override.option.variant.should == :street
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
context '#to_xml' do
|
44
|
+
shipping = Shipping.new('987612345') do
|
45
|
+
unrestricted :continental_us, :standard
|
46
|
+
restricted :continental_us, :expedited
|
47
|
+
adjust 19.99, :usd, :continental_us, :two_day, :street
|
48
|
+
replace 29.99, :usd, :continental_us, :one_day, :street
|
49
|
+
end
|
50
|
+
expected = Nokogiri::XML::Builder.new do
|
51
|
+
Override {
|
52
|
+
SKU '987612345'
|
53
|
+
ShippingOverride {
|
54
|
+
ShipOption 'Std Cont US Street Addr'
|
55
|
+
IsShippingRestricted 'false'
|
56
|
+
}
|
57
|
+
ShippingOverride {
|
58
|
+
ShipOption 'Exp Cont US Street Addr'
|
59
|
+
IsShippingRestricted 'true'
|
60
|
+
}
|
61
|
+
ShippingOverride {
|
62
|
+
ShipOption 'Second'
|
63
|
+
Type 'Additive'
|
64
|
+
ShipAmount '19.99', currency: 'USD'
|
65
|
+
}
|
66
|
+
ShippingOverride {
|
67
|
+
ShipOption 'Next'
|
68
|
+
Type 'Exclusive'
|
69
|
+
ShipAmount '29.99', currency: 'USD'
|
70
|
+
}
|
71
|
+
}
|
72
|
+
end.doc.root.to_xml
|
73
|
+
shipping.to_xml.should == expected
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|