mws-connect 0.0.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/.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
|