sp_api_clients 2.0.0

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.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +161 -0
  3. data/LICENSE +21 -0
  4. data/README.md +284 -0
  5. data/lib/amazon_sp_clients/adapter_loader.rb +28 -0
  6. data/lib/amazon_sp_clients/api_client.rb +309 -0
  7. data/lib/amazon_sp_clients/api_error.rb +37 -0
  8. data/lib/amazon_sp_clients/api_response.rb +54 -0
  9. data/lib/amazon_sp_clients/configuration.rb +144 -0
  10. data/lib/amazon_sp_clients/marketplaces.rb +63 -0
  11. data/lib/amazon_sp_clients/middlewares/raise_error.rb +166 -0
  12. data/lib/amazon_sp_clients/session.rb +124 -0
  13. data/lib/amazon_sp_clients/sp_fba_inventory.rb +8 -0
  14. data/lib/amazon_sp_clients/sp_feeds_2021.rb +8 -0
  15. data/lib/amazon_sp_clients/sp_fulfillment_outbound_2020.rb +8 -0
  16. data/lib/amazon_sp_clients/sp_listings_items_2021.rb +8 -0
  17. data/lib/amazon_sp_clients/sp_orders_v0.rb +8 -0
  18. data/lib/amazon_sp_clients/sp_reports_2021.rb +8 -0
  19. data/lib/amazon_sp_clients/sp_tokens_2021.rb +8 -0
  20. data/lib/amazon_sp_clients/sp_vdf_inventory_v1.rb +8 -0
  21. data/lib/amazon_sp_clients/sp_vdf_orders_v1.rb +8 -0
  22. data/lib/amazon_sp_clients/sp_vdf_shipping_v1.rb +8 -0
  23. data/lib/amazon_sp_clients/sp_vendor_invoices.rb +8 -0
  24. data/lib/amazon_sp_clients/sp_vendor_orders.rb +8 -0
  25. data/lib/amazon_sp_clients/sp_vendor_transaction_status.rb +8 -0
  26. data/lib/amazon_sp_clients/sp_vendors_shipments.rb +8 -0
  27. data/lib/amazon_sp_clients/token_exchange_auth.rb +82 -0
  28. data/lib/amazon_sp_clients/uploader.rb +77 -0
  29. data/lib/amazon_sp_clients/v2/api.rb +43 -0
  30. data/lib/amazon_sp_clients/v2/apis/fba_inventory.rb +80 -0
  31. data/lib/amazon_sp_clients/v2/apis/feeds_2021.rb +86 -0
  32. data/lib/amazon_sp_clients/v2/apis/fulfillment_outbound_2020.rb +184 -0
  33. data/lib/amazon_sp_clients/v2/apis/listings_items_2021.rb +144 -0
  34. data/lib/amazon_sp_clients/v2/apis/orders_v0.rb +165 -0
  35. data/lib/amazon_sp_clients/v2/apis/reports_2021.rb +117 -0
  36. data/lib/amazon_sp_clients/v2/apis/tokens_2021.rb +25 -0
  37. data/lib/amazon_sp_clients/v2/apis/vdf_inventory_v1.rb +26 -0
  38. data/lib/amazon_sp_clients/v2/apis/vdf_orders_v1.rb +61 -0
  39. data/lib/amazon_sp_clients/v2/apis/vdf_shipping_v1.rb +139 -0
  40. data/lib/amazon_sp_clients/v2/apis/vendor_invoices.rb +25 -0
  41. data/lib/amazon_sp_clients/v2/apis/vendor_orders.rb +106 -0
  42. data/lib/amazon_sp_clients/v2/apis/vendor_transaction_status.rb +25 -0
  43. data/lib/amazon_sp_clients/v2/apis/vendors_shipments.rb +120 -0
  44. data/lib/amazon_sp_clients/v2/apis.rb +82 -0
  45. data/lib/amazon_sp_clients/v2/client.rb +198 -0
  46. data/lib/amazon_sp_clients/v2/config.rb +85 -0
  47. data/lib/amazon_sp_clients/v2/credentials.rb +91 -0
  48. data/lib/amazon_sp_clients/v2/documents.rb +115 -0
  49. data/lib/amazon_sp_clients/v2/error_mapper.rb +235 -0
  50. data/lib/amazon_sp_clients/v2/errors.rb +117 -0
  51. data/lib/amazon_sp_clients/v2/lwa.rb +100 -0
  52. data/lib/amazon_sp_clients/v2/rdt.rb +104 -0
  53. data/lib/amazon_sp_clients/v2/token.rb +39 -0
  54. data/lib/amazon_sp_clients/v2.rb +33 -0
  55. data/lib/amazon_sp_clients/version.rb +3 -0
  56. data/lib/amazon_sp_clients.rb +69 -0
  57. data/lib/sp_api_clients.rb +6 -0
  58. data/sp_api_clients.gemspec +53 -0
  59. data/vendor/fba_inventory/lib/sp_fba_inventory/api/fba_inventory_api.rb +289 -0
  60. data/vendor/fba_inventory/lib/sp_fba_inventory.rb +12 -0
  61. data/vendor/feeds_2021/lib/sp_feeds_2021/api/feeds_api.rb +367 -0
  62. data/vendor/feeds_2021/lib/sp_feeds_2021.rb +12 -0
  63. data/vendor/fulfillment_outbound_2020/lib/sp_fulfillment_outbound_2020/api/fba_outbound_api.rb +845 -0
  64. data/vendor/fulfillment_outbound_2020/lib/sp_fulfillment_outbound_2020.rb +12 -0
  65. data/vendor/listings_items_2021/lib/sp_listings_items_2021/api/listings_api.rb +480 -0
  66. data/vendor/listings_items_2021/lib/sp_listings_items_2021.rb +12 -0
  67. data/vendor/orders_v0/lib/sp_orders_v0/api/orders_v0_api.rb +593 -0
  68. data/vendor/orders_v0/lib/sp_orders_v0/api/shipment_api.rb +83 -0
  69. data/vendor/orders_v0/lib/sp_orders_v0.rb +13 -0
  70. data/vendor/reports_2021/lib/sp_reports_2021/api/reports_api.rb +530 -0
  71. data/vendor/reports_2021/lib/sp_reports_2021.rb +12 -0
  72. data/vendor/tokens_2021/lib/sp_tokens_2021/api/tokens_api.rb +77 -0
  73. data/vendor/tokens_2021/lib/sp_tokens_2021.rb +12 -0
  74. data/vendor/vdf_inventory_v1/lib/sp_vdf_inventory_v1/api/update_inventory_api.rb +83 -0
  75. data/vendor/vdf_inventory_v1/lib/sp_vdf_inventory_v1.rb +12 -0
  76. data/vendor/vdf_orders_v1/lib/sp_vdf_orders_v1/api/vendor_orders_api.rb +217 -0
  77. data/vendor/vdf_orders_v1/lib/sp_vdf_orders_v1.rb +12 -0
  78. data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1/api/customer_invoices_api.rb +152 -0
  79. data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1/api/vendor_shipping_api.rb +264 -0
  80. data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1/api/vendor_shipping_labels_api.rb +208 -0
  81. data/vendor/vdf_shipping_v1/lib/sp_vdf_shipping_v1.rb +14 -0
  82. data/vendor/vendor_invoices/lib/sp_vendor_invoices/api/vendor_payments_api.rb +77 -0
  83. data/vendor/vendor_invoices/lib/sp_vendor_invoices.rb +12 -0
  84. data/vendor/vendor_orders/lib/sp_vendor_orders/api/vendor_orders_api.rb +323 -0
  85. data/vendor/vendor_orders/lib/sp_vendor_orders.rb +12 -0
  86. data/vendor/vendor_transaction_status/lib/sp_vendor_transaction_status/api/vendor_transaction_api.rb +75 -0
  87. data/vendor/vendor_transaction_status/lib/sp_vendor_transaction_status.rb +12 -0
  88. data/vendor/vendors_shipments/lib/sp_vendors_shipments/api/vendor_shipping_api.rb +337 -0
  89. data/vendor/vendors_shipments/lib/sp_vendors_shipments.rb +12 -0
  90. metadata +321 -0
@@ -0,0 +1,309 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require 'json'
5
+ require 'faraday'
6
+ require 'amazon_sp_clients/adapter_loader'
7
+
8
+ module AmazonSpClients
9
+ class ApiClient
10
+ # The Configuration object holding settings to be used in the API client.
11
+ attr_accessor :config
12
+
13
+ attr_accessor :connection
14
+
15
+ # Defines the headers to be used in HTTP requests of all API calls by
16
+ # default.
17
+ #
18
+ # @return [Hash]
19
+ attr_accessor :default_headers
20
+
21
+ # Initializes the ApiClient
22
+ # @option config [Configuration] Configuration for initializing the object,
23
+ # default to Configuration.default
24
+ def initialize(session, config = Configuration.default)
25
+ @session = session
26
+
27
+ @config = config
28
+ @user_agent = "Dropstream/1.0 (Language=Ruby/#{RUBY_VERSION})"
29
+ @default_headers = { 'Content-Type' => 'application/json', 'User-Agent' => @user_agent }
30
+ @connection =
31
+ Faraday.new(
32
+ url: @config.base_url,
33
+ headers: @default_headers,
34
+ request: {
35
+ timeout: @config.timeout
36
+ }
37
+ ) do |conn|
38
+ conn.adapter Faraday::Adapter::HTTPClient
39
+
40
+ conn.use AmazonSpClients::Middlewares::RaiseError, { service: :spapi }
41
+ end
42
+ end
43
+
44
+ # Call an API with given options.
45
+ #
46
+ # @return [Array<(Object, Integer, Hash)>] an array of 3 elements: the data
47
+ # deserialized from response body (could be nil), response status code and
48
+ # response headers.
49
+ def call_api(http_method, path, opts = {})
50
+ # Non standard usage of auth_names to determine if this is restricted access data kind
51
+ # of request:
52
+ restricted_resource = (Array(opts.delete(:auth_names)).first if opts.has_key?(:auth_names))
53
+
54
+ url, req_opts = build_request(http_method, path, opts)
55
+
56
+ raise 'Ensure session is valid before calling API methods' if @session.nil?
57
+
58
+ access_token = ''
59
+ if restricted_resource
60
+ @session.ask_for_restricted_data_token(restricted_resource)
61
+ access_token = @session.restricted_data_token[restricted_resource]
62
+ else
63
+ @session.refresh
64
+ access_token = @session.access_token
65
+ end
66
+
67
+ # Query params go through the request object: Faraday's post/put/
68
+ # patch helpers take (url, body), so a positional params argument
69
+ # would be treated as the body there and lost.
70
+ response =
71
+ @connection.send(req_opts[:method], url) do |req|
72
+ req.params.update(req_opts[:params])
73
+ req.body = req_opts[:body]
74
+ req.headers.merge!(req_opts[:headers])
75
+ req.headers.merge!(
76
+ {
77
+ 'x-amz-date' => Time.now.utc.strftime('%Y%m%dT%H%M%SZ'),
78
+ 'x-amz-access-token' => access_token
79
+ }
80
+ )
81
+ end
82
+
83
+ # Skipping error check and raise (use middleware for that instead)
84
+
85
+ (deserialize(response, opts[:return_type]) if opts[:return_type])
86
+ end
87
+
88
+ # Builds the HTTP request
89
+ #
90
+ # @param [String] http_method HTTP method/verb (e.g. POST)
91
+ # @param [String] path URL path (e.g. /account/new)
92
+ # @option opts [Hash] :header_params Header parameters
93
+ # @option opts [Hash] :query_params Query parameters
94
+ # @option opts [Hash] :form_params Query parameters
95
+ # @option opts [Object] :body HTTP body (JSON/XML)
96
+ # @return [Array(String, Hash)] the request url and options
97
+ def build_request(http_method, path, opts = {})
98
+ url = build_request_url(path)
99
+ http_method = http_method.to_sym.downcase
100
+
101
+ header_params = @default_headers.merge(opts[:header_params] || {})
102
+ query_params = opts[:query_params] || {}
103
+ form_params = opts[:form_params] || {}
104
+
105
+ req_opts = {
106
+ method: http_method,
107
+ headers: header_params,
108
+ params: query_params
109
+ }
110
+
111
+ if %i[post patch put delete].include?(http_method)
112
+ req_body = build_request_body(header_params, form_params, opts[:body])
113
+ req_opts.update body: req_body
114
+ end
115
+
116
+ [url, req_opts]
117
+ end
118
+
119
+ # Builds the HTTP request body
120
+ #
121
+ # @param [Hash] header_params Header parameters
122
+ # @param [Hash] form_params Query parameters
123
+ # @param [Object] body HTTP body (JSON/XML)
124
+ # @return [String] HTTP body data in the form of string
125
+ def build_request_body(header_params, form_params, body)
126
+ # http form
127
+ if ['application/x-www-form-urlencoded',
128
+ 'multipart/form-data'].include?(header_params['Content-Type'])
129
+ data = {}
130
+ form_params.each do |key, value|
131
+ data[key] = case value
132
+ when ::File, ::Array, nil
133
+ # TODO: how does http lib support File and Array params?
134
+ value
135
+ else
136
+ value.to_s
137
+ end
138
+ end
139
+ elsif body
140
+ data = body.is_a?(String) ? body : body.to_json
141
+ else
142
+ data = nil
143
+ end
144
+ data
145
+ end
146
+
147
+ # Check if the given MIME is a JSON MIME.
148
+ # JSON MIME examples:
149
+ # application/json
150
+ # application/json; charset=UTF8
151
+ # APPLICATION/JSON
152
+ # */*
153
+ # @param [String] mime MIME
154
+ # @return [Boolean] True if the MIME is application/json
155
+ def json_mime?(mime)
156
+ (mime == '*/*') || !(mime =~ %r{Application/.*json(?!p)(;.*)?}i).nil?
157
+ end
158
+
159
+ # Deserialize the response to the given return type.
160
+ #
161
+ # @param [Response] response HTTP response
162
+ # @param [String] return_type some examples: "User", "Array<User>",
163
+ # "Hash<String, Integer>"
164
+ def deserialize(response, return_type)
165
+ body = response.body
166
+ body = JSON.parse(body, symbolize_names: true) if body.is_a?(String)
167
+
168
+ return nil if body.nil? || body.empty?
169
+
170
+ # return response body directly for String return type
171
+ return body if return_type == 'String'
172
+
173
+ # ensuring a default content type
174
+ content_type = response.headers['Content-Type'] || 'application/json'
175
+
176
+ raise "Content-Type is not supported: #{content_type}" unless json_mime?(content_type)
177
+
178
+ begin
179
+ data = if body.is_a?(String)
180
+ JSON.parse("[#{body}]", symbolize_names: true)[0]
181
+ else
182
+ body
183
+ end
184
+ rescue JSON::ParserError => e
185
+ raise e unless %w[String Date DateTime].include?(return_type)
186
+
187
+ data = body
188
+ end
189
+
190
+ convert_to_type(data, return_type, response)
191
+ end
192
+
193
+ # Convert data to the given return type.
194
+ # @param [Object] data Data to be converted
195
+ # @param [String] return_type Return type
196
+ # @return [Mixed] Data in a particular type
197
+ def convert_to_type(data, return_type, response)
198
+ return nil if data.nil?
199
+
200
+ case return_type
201
+ when 'String'
202
+ data.to_s
203
+ when 'Integer'
204
+ data.to_i
205
+ when 'Float'
206
+ data.to_f
207
+ when 'Boolean'
208
+ data == true
209
+ when 'DateTime'
210
+ # parse date time (expecting ISO 8601 format)
211
+ DateTime.parse data
212
+ when 'Date'
213
+ # parse date time (expecting ISO 8601 format)
214
+ Date.parse data
215
+ when 'Object'
216
+ # generic object (usually a Hash), return directly
217
+ data
218
+ when /\AArray<(.+)>\z/
219
+ # e.g. Array<Pet>
220
+ sub_type = ::Regexp.last_match(1)
221
+ data.map { |item| convert_to_type(item, sub_type, response) }
222
+ when /\AHash<String, (.+)>\z/
223
+ # e.g. Hash<String, Integer>
224
+ sub_type = ::Regexp.last_match(1)
225
+ {}.tap { |hash| data.each { |k, v| hash[k] = convert_to_type(v, sub_type, response) } }
226
+ else
227
+ AmazonSpClients::ApiResponse.build_from_hash(data, response)
228
+ end
229
+ end
230
+
231
+ def build_request_url(path)
232
+ # Add leading and trailing slashes to path
233
+ path = "/#{path}".gsub(%r{/+}, '/')
234
+ @config.base_url + path
235
+ end
236
+
237
+ # Sets user agent in HTTP header
238
+ #
239
+ # @param [String] user_agent User agent (e.g. swagger-codegen/ruby/1.0.0)
240
+ def user_agent=(user_agent)
241
+ @user_agent = user_agent
242
+ @default_headers['User-Agent'] = @user_agent
243
+ end
244
+
245
+ # Return Accept header based on an array of accepts provided.
246
+ # @param [Array] accepts array for Accept
247
+ # @return [String] the Accept header (e.g. application/json)
248
+ def select_header_accept(accepts)
249
+ return nil if accepts.nil? || accepts.empty?
250
+
251
+ # use JSON when present, otherwise use all of the provided
252
+ json_accept = accepts.find { |s| json_mime?(s) }
253
+ json_accept || accepts.join(',')
254
+ end
255
+
256
+ # Return Content-Type header based on an array of content types provided.
257
+ # @param [Array] content_types array for Content-Type
258
+ # @return [String] the Content-Type header (e.g. application/json)
259
+ def select_header_content_type(content_types)
260
+ # use application/json by default
261
+ return 'application/json' if content_types.nil? || content_types.empty?
262
+
263
+ # use JSON when present, otherwise use the first one
264
+ json_content_type = content_types.find { |s| json_mime?(s) }
265
+ json_content_type || content_types.first
266
+ end
267
+
268
+ # Convert object (array, hash, object, etc) to JSON string.
269
+ # @param [Object] model object to be converted into JSON string
270
+ # @return [String] JSON string representation of the object
271
+ def object_to_http_body(model)
272
+ return model if model.nil? || model.is_a?(String)
273
+
274
+ local_body = if model.is_a?(Array)
275
+ model.map { |m| object_to_hash(m) }
276
+ else
277
+ object_to_hash(model)
278
+ end
279
+ local_body.to_json
280
+ end
281
+
282
+ # Convert object(non-array) to hash.
283
+ # @param [Object] obj object to be converted into JSON string
284
+ # @return [String] JSON string representation of the object
285
+ def object_to_hash(obj)
286
+ obj.respond_to?(:to_hash) ? obj.to_hash : obj
287
+ end
288
+
289
+ # Build parameter value according to the given collection format.
290
+ # @param [String] collection_format one of :csv, :ssv, :tsv, :pipes and :multi
291
+ def build_collection_param(param, collection_format)
292
+ case collection_format
293
+ when :csv
294
+ param.join(',')
295
+ when :ssv
296
+ param.join(' ')
297
+ when :tsv
298
+ param.join("\t")
299
+ when :pipes
300
+ param.join('|')
301
+ when :multi
302
+ # return the array directly as typhoeus will handle it as expected
303
+ param
304
+ else
305
+ raise "unknown collection format: #{collection_format.inspect}"
306
+ end
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,37 @@
1
+ module AmazonSpClients
2
+ class ApiError
3
+ class Error < Struct.new(:code, :message, :details)
4
+ end
5
+
6
+ attr_reader :errors
7
+
8
+ # attr_reader :code, :response_headers, :errors
9
+
10
+ # SP API returns errors in this format:
11
+ #
12
+ # {"errors"=>[{"code"=>"InvalidInput", "message"=>"Invalid Input"}]}
13
+ #
14
+ def initialize(errors)
15
+ @errors = []
16
+
17
+ errors = errors[:errors] if errors.is_a?(Hash) && errors.key?(:errors)
18
+
19
+ return unless errors.is_a?(Array)
20
+
21
+ @errors =
22
+ errors.map do |h|
23
+ AmazonSpClients::ApiError::Error.new(
24
+ h[:code],
25
+ h[:message],
26
+ h[:details]
27
+ )
28
+ end
29
+ end
30
+
31
+ def full_messages
32
+ @errors.map do |err|
33
+ "#{err.code}: #{err.message}#{' - ' + err.details if err.details}"
34
+ end.join(', ')
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,54 @@
1
+ module AmazonSpClients
2
+ # The general response.
3
+ class ApiResponse
4
+ # Hash with response payload
5
+ attr_accessor :payload
6
+
7
+ # Hash with error response, nil otherwise
8
+ attr_accessor :errors
9
+
10
+ # Some APIs move :nextToken to separate top level key :pagination
11
+ attr_accessor :pagination
12
+
13
+ attr_reader :attributes, :response
14
+
15
+ # Initializes the object
16
+ # @param [Hash] attributes Model attributes in the form of hash
17
+ def initialize(attributes = {}, response = nil)
18
+ @attributes = attributes
19
+ @response = response
20
+
21
+ unless attributes.is_a?(Hash)
22
+ raise ArgumentError,
23
+ 'The input argument (attributes) must be a hash in `ApiResponse` initialize method'
24
+ end
25
+
26
+ # The envelope keys are always symbols: deserialize parses
27
+ # response bodies with symbolize_names.
28
+ if attributes.key?(:payload) || attributes.key?(:errors)
29
+ self.payload = attributes[:payload]
30
+ if attributes.key?(:errors)
31
+ self.errors = AmazonSpClients::ApiError.new(attributes.delete(:errors))
32
+ end
33
+ self.pagination = attributes[:pagination] if attributes.key?(:pagination)
34
+ else
35
+ self.payload = attributes
36
+ end
37
+ end
38
+
39
+ def reported_rate_limit
40
+ response_headers&.fetch('X-Amzn-Ratelimit-Limit', nil)&.to_f
41
+ end
42
+
43
+ def response_headers
44
+ @response&.headers
45
+ end
46
+
47
+ # Builds the object from hash
48
+ # @param [Hash] attributes Model attributes in the form of hash
49
+ # @return [Object] Returns the model itself
50
+ def self.build_from_hash(attributes, response = nil)
51
+ new(attributes, response)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmazonSpClients
4
+ class Configuration
5
+ # SP specific
6
+ attr_reader :marketplace_id
7
+ attr_reader :region
8
+
9
+ attr_reader :endpoint
10
+
11
+ # App credentials
12
+ attr_accessor :client_id
13
+ attr_accessor :client_secret
14
+
15
+ # Deprecated AWS/SigV4-era settings. Amazon dropped the SigV4
16
+ # requirement in October 2023. Accepted and ignored since 1.8.0;
17
+ # they go away together with the v1 API in a later major.
18
+ attr_accessor :credentials_provider
19
+ attr_accessor :access_key
20
+ attr_accessor :secret_key
21
+ attr_accessor :role_arn
22
+
23
+ # Defines url scheme
24
+ attr_accessor :scheme
25
+
26
+ # Defines url base path
27
+ attr_accessor :base_path
28
+
29
+ # Deprecated: the gem no longer logs. Accepted and ignored since 1.8.0;
30
+ # they go away together with the v1 API in a later major.
31
+ attr_accessor :debugging
32
+ attr_accessor :logger
33
+
34
+ # The time limit for HTTP request in seconds.
35
+ # Default to 0 (never times out).
36
+ attr_accessor :timeout
37
+
38
+ # Set this to false to skip client side validation in the operation.
39
+ # Default to true.
40
+ # @return [true, false]
41
+ attr_accessor :client_side_validation
42
+
43
+ def initialize
44
+ @sandbox_env = false
45
+
46
+ @credentials_provider = nil
47
+
48
+ @marketplace_id = nil
49
+
50
+ # iam
51
+ @role_arn = nil
52
+ @access_key = nil
53
+ @secret_key = nil
54
+
55
+ # app
56
+ @client_id = nil
57
+ @client_secret = nil
58
+
59
+ @endpoint = nil
60
+ @scheme = 'https'
61
+ @region = 'us-east-1'
62
+ @base_path = '/'
63
+ @timeout = 60
64
+ @client_side_validation = true
65
+ yield(self) if block_given?
66
+ end
67
+
68
+ # The default Configuration object.
69
+ def self.default
70
+ Thread.current[:amazon_sp_configuration] ||= Configuration.new
71
+ end
72
+
73
+ def configure
74
+ yield(self) if block_given?
75
+ end
76
+
77
+ def scheme=(scheme)
78
+ # remove :// from scheme
79
+ @scheme = scheme.sub(%r{://}, '')
80
+ end
81
+
82
+ def host
83
+ "#{'sandbox.' if @sandbox_env}#{AmazonSpClients::REGIONS.fetch(@region)}"
84
+ end
85
+
86
+ def base_path=(base_path)
87
+ # Add leading and trailing slashes to base_path
88
+ @base_path = "/#{base_path}".gsub(%r{/+}, '/')
89
+ @base_path = '' if @base_path == '/'
90
+ end
91
+
92
+ def base_url
93
+ "#{scheme}://#{[host, base_path].join('/').gsub(%r{/+}, '/')}".sub(%r{/+\z}, '')
94
+ end
95
+
96
+ def region=(region)
97
+ # The fetch validates the region; host is computed from it.
98
+ AmazonSpClients::REGIONS.fetch(region)
99
+ @region = region
100
+ end
101
+
102
+ # When sandbox mode is enabled, all requests will go to 'sandbox.' host.
103
+ def sandbox_env!
104
+ @sandbox_env = true
105
+ end
106
+
107
+ def disable_sandbox!
108
+ @sandbox_env = false
109
+ end
110
+
111
+ def set_endpoint_by_marketplace_id(marketplace_id)
112
+ # Validate before assigning so a bad id cannot corrupt state.
113
+ endpoint = AmazonSpClients::MARKETPLACE_ENDPOINT_MAP.fetch(marketplace_id)
114
+
115
+ @marketplace_id = marketplace_id
116
+ self.endpoint = endpoint
117
+ end
118
+
119
+ def endpoint=(str)
120
+ set_region_by_endpoint(str)
121
+ @endpoint = str
122
+ end
123
+
124
+ def set_region_by_endpoint(str)
125
+ self.region =
126
+ case str
127
+ when 'na'
128
+ AmazonSpClients::REGION_NA
129
+ when 'fe'
130
+ AmazonSpClients::REGION_FE
131
+ when 'eu'
132
+ AmazonSpClients::REGION_EU
133
+ when 'br', 'ca', 'mx', 'us'
134
+ AmazonSpClients::REGION_NA
135
+ when 'sg', 'au', 'jp'
136
+ AmazonSpClients::REGION_FE
137
+ when 'ae', 'de', 'eg', 'es', 'fr', 'gb', 'in', 'it', 'nl', 'sa', 'tr', 'pl', 'se'
138
+ AmazonSpClients::REGION_EU
139
+ else
140
+ raise ArgumentError, "unknown endpoint #{str.inspect}"
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Region and marketplace tables. Shared by v1 and V2; depends on nothing.
4
+ module AmazonSpClients
5
+ REGION_FE = 'us-west-2'
6
+ REGION_EU = 'eu-west-1'
7
+ REGION_NA = 'us-east-1'
8
+
9
+ REGIONS = {
10
+ REGION_NA => 'sellingpartnerapi-na.amazon.com',
11
+ REGION_EU => 'sellingpartnerapi-eu.amazon.com',
12
+ REGION_FE => 'sellingpartnerapi-fe.amazon.com'
13
+ }.freeze
14
+
15
+ MARKETPLACE_IDS = {
16
+ # NA
17
+ us: 'ATVPDKIKX0DER',
18
+ ca: 'A2EUQ1WTGCTBG2',
19
+ mx: 'A1AM78C64UM0Y8',
20
+ br: 'A2Q3Y263D00KWC',
21
+ # EU
22
+ es: 'A1RKKUPIHCS9HS',
23
+ gb: 'A1F83G8C2ARO7P',
24
+ fr: 'A13V1IB3VIYZZH',
25
+ nl: 'A1805IZSGTT6HS',
26
+ de: 'A1PA6795UKMFR9',
27
+ it: 'APJ6JRA9NG5V4',
28
+ se: 'A2NODRKZP88ZB9',
29
+ pl: 'A1C3SOZRARQ6R3',
30
+ eg: 'ARBP9OOSHTCHU',
31
+ tr: 'A33AVAJ2PDY3EV',
32
+ sa: 'A17E79C6D8DWNP',
33
+ ae: 'A2VIGQ35RCS4UG',
34
+ in: 'A21TJRUUN4KGV',
35
+ # FE
36
+ sg: 'A19VAU5U5O7RUS',
37
+ au: 'A39IBJ37TRP1C6',
38
+ jp: 'A1VC38T7YXB528'
39
+ }.freeze
40
+
41
+ MARKETPLACE_ENDPOINT_MAP = {
42
+ 'A2EUQ1WTGCTBG2' => 'na',
43
+ 'ATVPDKIKX0DER' => 'na',
44
+ 'A1AM78C64UM0Y8' => 'na',
45
+ 'A2Q3Y263D00KWC' => 'na',
46
+ 'A1RKKUPIHCS9HS' => 'eu',
47
+ 'A1F83G8C2ARO7P' => 'eu',
48
+ 'A13V1IB3VIYZZH' => 'eu',
49
+ 'A1805IZSGTT6HS' => 'eu',
50
+ 'A1PA6795UKMFR9' => 'eu',
51
+ 'APJ6JRA9NG5V4' => 'eu',
52
+ 'A2NODRKZP88ZB9' => 'eu',
53
+ 'A1C3SOZRARQ6R3' => 'eu',
54
+ 'ARBP9OOSHTCHU' => 'eu',
55
+ 'A33AVAJ2PDY3EV' => 'eu',
56
+ 'A17E79C6D8DWNP' => 'eu',
57
+ 'A2VIGQ35RCS4UG' => 'eu',
58
+ 'A21TJRUUN4KGV' => 'eu',
59
+ 'A19VAU5U5O7RUS' => 'fe',
60
+ 'A39IBJ37TRP1C6' => 'fe',
61
+ 'A1VC38T7YXB528' => 'fe'
62
+ }.freeze
63
+ end