peddler 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: feb811340d856df7c73b3ea07afd4532892500c8
4
- data.tar.gz: 537798c7e2eff288ac0d8e16094a8a295f9e2daf
3
+ metadata.gz: 0ebc3731112b872c4fd188f5f2a670906d306deb
4
+ data.tar.gz: 6dd3f8389d2ab5837fd6a614da7f005fc74f35f9
5
5
  SHA512:
6
- metadata.gz: ab7bc5600b29e18fe0968cd9dc874b9982ab50e4e6636b3390b0b46125b2e13eb1a1476e6064bdc2b4f889ede22fa97cd3d57c427530edc0e87c7d770e729594
7
- data.tar.gz: 9a013902b6900d5e9cf6f0615a008816ec60e4761c758b8f8ba0ba10e3ec8e56547d8ad2f343695b38ab0cbb279ba03856364d2389bfbf9f77168d8a13128f7c
6
+ metadata.gz: bb1753e3b07215bc3749d7a49cca3441d7149b61bb1b76f024b0d938553c9a30d90129cfa785ad831b243637b6c4a32c79c1c4b1a72d24ab15b449baa0d92e61
7
+ data.tar.gz: d08981d7ee8b42ab481983ae999671619517be7d7e0df8e23c17731a62bbca01001c167943845cbcc8705e645c5527d2619f2b5aa030af4fec37625e0cc3c5ee
data/README.md CHANGED
@@ -41,36 +41,38 @@ export AWS_SECRET_ACCESS_KEY=qux
41
41
  You can now instantiate a client.
42
42
 
43
43
  ```ruby
44
- client = MWS::Orders::Client.new
44
+ client = MWS.orders
45
45
  ```
46
46
 
47
47
  Alternatively, you can set some or all credentials when or after creating the client.
48
48
 
49
49
  ```ruby
50
- client = MWS::Orders::Client.new(
50
+ client = MWS.orders(
51
51
  primary_marketplace_id: "foo",
52
52
  merchant_id: "bar",
53
53
  aws_access_key_id: "baz",
54
54
  aws_secret_access_key: "qux"
55
55
  )
56
+ client.primary_marketplace_id = "bar"
56
57
  ```
57
58
 
58
59
  If you are creating a client for another seller, pass the latter's `MWSAuthToken` to the client.
59
60
 
60
61
  ```ruby
62
+ client = MWS.orders
61
63
  client.auth_token = "corge"
62
64
  ```
63
65
 
64
- Once you have a client with valid credentials, you should be able to make requests to the API.
66
+ Once you have a client with valid credentials, you should be able to make requests to the API. Clients map operation names in a flat structure. Methods have positional arguments for required input and keyword arguments for optional parameters. Both method and argument names are underscored but otherwise identical to the names of the corresponding operations and parameters documented in the API.
65
67
 
66
- Peddler returns the response wrapped in a parser that handles both XML documents and flat files.
68
+ Peddler wraps successful responses in a parser that handles both XML documents and flat files.
67
69
 
68
70
  ```ruby
69
71
  parser = client.get_service_status
70
72
  parser.parse # will return a Hash or CSV object
71
73
  ```
72
74
 
73
- You can swap the default parser with a purpose-built one.
75
+ You can swap the default parser with a purpose-built abstraction.
74
76
 
75
77
  ```ruby
76
78
  MWS::Orders::Client.parser = MyParser
@@ -27,7 +27,7 @@ module MWS
27
27
  run
28
28
  end
29
29
 
30
- # List feed submissions
30
+ # Lists feed submissions
31
31
  #
32
32
  # @see http://docs.developer.amazonservices.com/en_US/feeds/Feeds_GetFeedSubmissionList.html
33
33
  # @see http://docs.developer.amazonservices.com/en_US/feeds/Feeds_FeedType.html
@@ -49,7 +49,7 @@ module MWS
49
49
  run
50
50
  end
51
51
 
52
- # List the next page of feed submissions
52
+ # Lists the next page of feed submissions
53
53
  #
54
54
  # @see http://docs.developer.amazonservices.com/en_US/feeds/Feeds_GetFeedSubmissionListByNextToken.html
55
55
  # @param next_token [String]
@@ -80,7 +80,7 @@ module MWS
80
80
  run
81
81
  end
82
82
 
83
- # Cancel one or more feed submissions
83
+ # Cancels one or more feed submissions
84
84
  #
85
85
  # @see http://docs.developer.amazonservices.com/en_US/feeds/Feeds_CancelFeedSubmissions.html
86
86
  # @see http://docs.developer.amazonservices.com/en_US/feeds/Feeds_FeedType.html
@@ -93,6 +93,8 @@ module MWS
93
93
  def cancel_feed_submissions(opts = {})
94
94
  operation('CancelFeedSubmissions')
95
95
  .add(opts)
96
+ .structure!('FeedSubmissionIdList', 'Id')
97
+ .structure!('FeedTypeList', 'Type')
96
98
 
97
99
  run
98
100
  end
@@ -11,7 +11,8 @@ module MWS
11
11
  # Lists orders
12
12
  #
13
13
  # @note When calling this operation, you must specify a time frame using
14
- # either created_after or last_updated_after.
14
+ # either created_after or last_updated_after. When requesting orders by
15
+ # "Unshipped" status you must also request "PartiallyShipped" orders.
15
16
  # @see http://docs.developer.amazonservices.com/en_US/orders/2013-09-01/Orders_ListOrders.html
16
17
  # @param opts [Hash]
17
18
  # @option opts [String, #iso8601] :created_after
@@ -170,7 +170,7 @@ module MWS
170
170
  run
171
171
  end
172
172
 
173
- # List scheduled reports
173
+ # Lists scheduled reports
174
174
  #
175
175
  # @see http://docs.developer.amazonservices.com/en_US/reports/Reports_GetReportScheduleList.html
176
176
  # @param report_type_list [*Array<String>]
@@ -183,7 +183,7 @@ module MWS
183
183
  run
184
184
  end
185
185
 
186
- # List next page of scheduled reports
186
+ # Lists next page of scheduled reports
187
187
  #
188
188
  # @see http://docs.developer.amazonservices.com/en_US/reports/Reports_GetReportScheduleListByNextToken.html
189
189
  # @raise [NotImplementedError]
@@ -191,7 +191,7 @@ module MWS
191
191
  fail NotImplementedError
192
192
  end
193
193
 
194
- # Count scheduled reports
194
+ # Counts scheduled reports
195
195
  #
196
196
  # @see http://docs.developer.amazonservices.com/en_US/reports/Reports_GetReportScheduleCount.html
197
197
  # @param report_type_list [Array<String>]
@@ -204,7 +204,7 @@ module MWS
204
204
  run
205
205
  end
206
206
 
207
- # Update acknowledged status of one or more reports
207
+ # Updates acknowledged status of one or more reports
208
208
  #
209
209
  # @see http://docs.developer.amazonservices.com/en_US/reports/Reports_UpdateReportAcknowledgements.html
210
210
  # @param acknowledged [Boolean]
@@ -133,7 +133,12 @@ module Peddler
133
133
 
134
134
  # @!parse attr_writer :body
135
135
  def body=(str)
136
- headers['Content-Type'] = content_type(str)
136
+ if str
137
+ headers['Content-Type'] = content_type(str)
138
+ else
139
+ headers.delete('Content-Type')
140
+ end
141
+
137
142
  @body = str
138
143
  end
139
144
 
@@ -39,7 +39,9 @@ module Peddler
39
39
  end
40
40
 
41
41
  def scrub_content
42
- content.force_encoding(encoding).encode('UTF-8')
42
+ content
43
+ .force_encoding(encoding)
44
+ .encode('UTF-8', undef: :replace, replace: '?')
43
45
  end
44
46
 
45
47
  def summary?
@@ -27,15 +27,17 @@ module Peddler
27
27
  @host ||= find_host
28
28
  end
29
29
 
30
+ # Caveat: We use the supersets Windows-31J and CP1252 in place of Shift_JIS
31
+ # and ISO 8859-1 respectively to handle edge cases where latter will not
32
+ # support some characters. The supersets should be safe to use as drop-in
33
+ # replacements.
30
34
  def encoding
31
35
  if japanese?
32
- # Caveat: I've had one instance in the past where Shift_JIS didn't
33
- # work but Windows-31J did when parsing a report.
34
- 'Shift_JIS'
36
+ 'Windows-31J'
35
37
  elsif chinese?
36
38
  'UTF-16'
37
39
  else
38
- 'ISO-8859-1'
40
+ 'CP1252'
39
41
  end
40
42
  end
41
43
 
@@ -8,7 +8,7 @@ module Peddler
8
8
  class << self
9
9
  # The inevitable-seeming messiness of massaging data produced by a motley
10
10
  # army of Amazon developers
11
- def new(res, encoding = 'ISO-8859-1')
11
+ def new(res, encoding)
12
12
  # Don't parse if there's no body
13
13
  return res unless res.body
14
14
 
@@ -22,15 +22,22 @@ module Peddler
22
22
  private
23
23
 
24
24
  def compare_uri
25
- req_1.uri == req_2.uri
25
+ uri_1 = URI.parse(req_1.uri)
26
+ uri_2 = URI.parse(req_2.uri)
27
+
28
+ uri_1.host == uri_2.host &&
29
+ uri_1.path == uri_2.path &&
30
+ extract_params(uri_1.query) == extract_params(uri_2.query)
26
31
  end
27
32
 
28
33
  def compare_body
29
34
  extract_params(req_1.body) == extract_params(req_2.body)
30
35
  end
31
36
 
32
- def extract_params(body)
33
- params = ::CGI.parse(body)
37
+ def extract_params(string)
38
+ return {} unless string
39
+
40
+ params = ::CGI.parse(string)
34
41
  TRANSIENT_PARAMS.each do |k|
35
42
  params.delete(k)
36
43
  end
@@ -1,3 +1,3 @@
1
1
  module Peddler
2
- VERSION = '1.1.0'
2
+ VERSION = '1.1.1'
3
3
  end
@@ -10,10 +10,11 @@ module Peddler
10
10
  private
11
11
 
12
12
  def find_data
13
- results = xml.values.first.find { |k, _| k.include?('Result') } ||
14
- xml.values.first.find { |k, _| k == 'Message' }
13
+ payload = xml.values.first
14
+ found = payload.find { |k, _| k.include?('Result') } ||
15
+ payload.find { |k, _| k == 'Message' }
15
16
 
16
- results ? results.last : nil
17
+ found.last if found
17
18
  end
18
19
  end
19
20
  end
@@ -15,4 +15,22 @@ class TestFeeds < IntegrationTest
15
15
  refute_empty res.parse
16
16
  end
17
17
  end
18
+
19
+ def test_submits_feeds
20
+ content = "sku\tprice\tquantity\nwidget\t\t0\n"
21
+ type = '_POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_'
22
+
23
+ clients.each do |client|
24
+ res = client.submit_feed(content, type)
25
+ id = res.parse['FeedSubmissionInfo']['FeedSubmissionId']
26
+ refute_nil id
27
+
28
+ # Clean up
29
+ client.body = nil
30
+ client.cancel_feed_submissions(
31
+ feed_submission_id: id,
32
+ feed_type_list: type
33
+ )
34
+ end
35
+ end
18
36
  end
@@ -43,4 +43,13 @@ class TestReports < IntegrationTest
43
43
  refute_empty res.parse
44
44
  end
45
45
  end
46
+
47
+ def test_gets_report
48
+ clients.each do |client|
49
+ res = client.get_report_list(max_count: 1)
50
+ id = res.parse['ReportInfo']['ReportId']
51
+ res = client.get_report(id)
52
+ refute_empty res.parse || res.records_count
53
+ end
54
+ end
46
55
  end
@@ -73,11 +73,16 @@ class TestMWSFeedsClient < MiniTest::Test
73
73
 
74
74
  def test_cancels_feed_submissions
75
75
  operation = {
76
- 'Action' => 'CancelFeedSubmissions'
76
+ 'Action' => 'CancelFeedSubmissions',
77
+ 'FeedTypeList.Type.1' => '1',
78
+ 'FeedSubmissionIdList.Id.1' => '2'
77
79
  }
78
80
 
79
81
  @client.stub(:run, nil) do
80
- @client.cancel_feed_submissions
82
+ @client.cancel_feed_submissions(
83
+ feed_type_list: '1',
84
+ feed_submission_id_list: '2'
85
+ )
81
86
  end
82
87
 
83
88
  assert_equal operation, @client.operation
@@ -78,7 +78,7 @@ class TestPeddlerClient < MiniTest::Test
78
78
  @client.body = 'foo'
79
79
  content_type = @client.headers.fetch('Content-Type')
80
80
 
81
- assert_equal 'text/tab-separated-values; charset=ISO-8859-1', content_type
81
+ assert_equal 'text/tab-separated-values; charset=CP1252', content_type
82
82
  end
83
83
 
84
84
  def test_sets_content_type_header_for_chinese_flat_file_body
@@ -94,7 +94,7 @@ class TestPeddlerClient < MiniTest::Test
94
94
  @client.body = 'foo'
95
95
  content_type = @client.headers.fetch('Content-Type')
96
96
 
97
- assert_equal 'text/tab-separated-values; charset=Shift_JIS', content_type
97
+ assert_equal 'text/tab-separated-values; charset=Windows-31J', content_type
98
98
  end
99
99
 
100
100
  def test_sets_content_type_header_for_xml_body
@@ -41,8 +41,37 @@ class TestPeddlerFlatFileParser < MiniTest::Test
41
41
  body.encode!('SHIFT_JIS')
42
42
  body.force_encoding('ASCII-8BIT')
43
43
  res = OpenStruct.new(body: body)
44
- parser = Peddler::FlatFileParser.new(res, 'SHIFT_JIS')
44
+ parser = Peddler::FlatFileParser.new(res, 'Windows-31J')
45
45
 
46
46
  assert_equal 'こんにちは', parser.parse[0]['Foo']
47
47
  end
48
+
49
+ def test_handles_japanese_curly_braces
50
+ body = "Foo\n〝\n"
51
+ body.encode!('Windows-31J')
52
+ body.force_encoding('ASCII-8BIT')
53
+ res = OpenStruct.new(body: body)
54
+ parser = Peddler::FlatFileParser.new(res, 'Windows-31J')
55
+
56
+ assert_equal '〝', parser.parse[0]['Foo']
57
+ end
58
+
59
+ def test_handles_latin_1_flat_files
60
+ body = "Foo\n™\n"
61
+ body.encode!('Cp1252')
62
+ body.force_encoding('ASCII-8BIT')
63
+ res = OpenStruct.new(body: body)
64
+ parser = Peddler::FlatFileParser.new(res, 'Cp1252')
65
+
66
+ assert_equal '™', parser.parse['Foo'][0]
67
+ end
68
+
69
+ def test_handles_undefined_characters
70
+ body = "Foo\n\xFF\n"
71
+ body.force_encoding('ASCII-8BIT')
72
+ res = OpenStruct.new(body: body)
73
+ parser = Peddler::FlatFileParser.new(res, 'ASCII-8BIT')
74
+
75
+ assert_equal '?', parser.parse['Foo'][0]
76
+ end
48
77
  end
@@ -8,7 +8,7 @@ class TestPeddlerParser < MiniTest::Test
8
8
  headers: { 'Content-Type' => content_type },
9
9
  body: body
10
10
  )
11
- parser = Peddler::Parser.new(res)
11
+ parser = Peddler::Parser.new(res, 'Cp1252')
12
12
 
13
13
  assert_kind_of klass, parser
14
14
  end