peddler 4.2.0 → 4.3.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.
- checksums.yaml +4 -4
- data/README.md +116 -293
- data/lib/peddler/apis/catalog_items_v0.rb +0 -62
- data/lib/peddler/apis/seller_wallet_2024_03_01.rb +195 -0
- data/lib/peddler/parsers/openapi_parser_generator.rb +550 -0
- data/lib/peddler/parsers/smart_parser.rb +199 -0
- data/lib/peddler/version.rb +1 -1
- data/lib/peddler.rb +1 -0
- metadata +6 -3
@@ -0,0 +1,550 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "bigdecimal"
|
5
|
+
|
6
|
+
module Peddler
|
7
|
+
module Parsers
|
8
|
+
# Check if Money gem is available for handling monetary values
|
9
|
+
begin
|
10
|
+
require "money"
|
11
|
+
MONEY_GEM_AVAILABLE = true
|
12
|
+
|
13
|
+
# Configure Money to avoid issues
|
14
|
+
Money.rounding_mode = BigDecimal::ROUND_HALF_UP
|
15
|
+
|
16
|
+
# Avoid locale issues by using currency backend
|
17
|
+
if Money.respond_to?(:locale_backend=)
|
18
|
+
Money.locale_backend = :currency
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
MONEY_GEM_AVAILABLE = false
|
22
|
+
end
|
23
|
+
|
24
|
+
# Use Structs to represent structured data in responses
|
25
|
+
DATA_TYPES = {
|
26
|
+
# Common Amazon data types that will be converted to structured objects
|
27
|
+
money: Struct.new(:currency, :amount, keyword_init: true),
|
28
|
+
dimension: Struct.new(:value, :unit, keyword_init: true),
|
29
|
+
address: Struct.new(
|
30
|
+
:name,
|
31
|
+
:address_line1,
|
32
|
+
:address_line2,
|
33
|
+
:city,
|
34
|
+
:state_or_region,
|
35
|
+
:postal_code,
|
36
|
+
:country_code,
|
37
|
+
:phone,
|
38
|
+
keyword_init: true,
|
39
|
+
),
|
40
|
+
weight: Struct.new(:value, :unit, keyword_init: true),
|
41
|
+
daterange: Struct.new(:start, :end, keyword_init: true),
|
42
|
+
price: Struct.new(:currency_code, :amount, keyword_init: true),
|
43
|
+
}
|
44
|
+
|
45
|
+
# Generates response parsers based on Amazon's OpenAPI schemas
|
46
|
+
class OpenAPIParserGenerator
|
47
|
+
# OpenAPI Parser Generator error class
|
48
|
+
class Error < StandardError; end
|
49
|
+
|
50
|
+
# Error when schema cannot be parsed or is invalid
|
51
|
+
class InvalidSchemaError < Error; end
|
52
|
+
|
53
|
+
# Error when operation cannot be found
|
54
|
+
class OperationNotFoundError < Error; end
|
55
|
+
|
56
|
+
# Initialize the generator with an OpenAPI schema
|
57
|
+
#
|
58
|
+
# @param [String, Hash] schema The OpenAPI schema (file path or parsed hash)
|
59
|
+
# @raise [InvalidSchemaError] If the schema is invalid or cannot be parsed
|
60
|
+
def initialize(schema)
|
61
|
+
@schema = if schema.is_a?(String)
|
62
|
+
begin
|
63
|
+
JSON.parse(File.read(schema))
|
64
|
+
rescue JSON::ParserError => e
|
65
|
+
raise InvalidSchemaError, "Failed to parse schema JSON: #{e.message}"
|
66
|
+
rescue Errno::ENOENT => e
|
67
|
+
raise InvalidSchemaError, "Schema file not found: #{e.message}"
|
68
|
+
end
|
69
|
+
else
|
70
|
+
schema
|
71
|
+
end
|
72
|
+
|
73
|
+
# Basic validation of schema structure
|
74
|
+
unless @schema.is_a?(Hash) && @schema["paths"].is_a?(Hash)
|
75
|
+
raise InvalidSchemaError, "Invalid schema format: missing or invalid 'paths' property"
|
76
|
+
end
|
77
|
+
rescue NoMethodError => e
|
78
|
+
raise InvalidSchemaError, "Invalid schema structure: #{e.message}"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Generate a parser class for a specific API operation
|
82
|
+
#
|
83
|
+
# @param [String] operation_id The OpenAPI operationId to generate a parser for
|
84
|
+
# @return [Class] A parser class configured for the operation's response schema
|
85
|
+
def generate_parser_for_operation(operation_id)
|
86
|
+
operation_schema = find_operation_schema(operation_id)
|
87
|
+
return unless operation_schema
|
88
|
+
|
89
|
+
# Use the actual operationId from the schema
|
90
|
+
actual_operation_id = operation_schema["operationId"]
|
91
|
+
|
92
|
+
response_schema = extract_response_schema(operation_schema)
|
93
|
+
return unless response_schema
|
94
|
+
|
95
|
+
create_parser_class(actual_operation_id, response_schema)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Generate parsers for all operations in the schema
|
99
|
+
#
|
100
|
+
# @return [Hash<String, Class>] A map of operation IDs to parser classes
|
101
|
+
def generate_all_parsers
|
102
|
+
operations = find_all_operations
|
103
|
+
operations.each_with_object({}) do |(op_id, op_schema), parsers|
|
104
|
+
response_schema = extract_response_schema(op_schema)
|
105
|
+
next unless response_schema
|
106
|
+
|
107
|
+
parser_class = create_parser_class(op_id, response_schema)
|
108
|
+
parsers[op_id] = parser_class if parser_class
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
# Find the schema for a specific operation
|
115
|
+
#
|
116
|
+
# @param [String] operation_id The operation ID to find
|
117
|
+
# @return [Hash, nil] The operation schema if found
|
118
|
+
def find_operation_schema(operation_id)
|
119
|
+
return unless @schema["paths"]
|
120
|
+
|
121
|
+
@schema["paths"].each_value do |path_item|
|
122
|
+
["get", "post", "put", "delete", "patch"].each do |method|
|
123
|
+
next unless path_item[method]
|
124
|
+
|
125
|
+
# Amazon SP-API sometimes uses camelCase for operation IDs
|
126
|
+
op = path_item[method]
|
127
|
+
op_id = op["operationId"]
|
128
|
+
|
129
|
+
# Try exact match first
|
130
|
+
return op if op_id == operation_id
|
131
|
+
|
132
|
+
# Try case-insensitive match as fallback
|
133
|
+
return op if op_id.to_s.downcase == operation_id.to_s.downcase
|
134
|
+
|
135
|
+
# Try camelCase to snake_case conversion
|
136
|
+
snake_case_id = op_id.to_s.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, "")
|
137
|
+
return op if snake_case_id == operation_id.to_s.downcase
|
138
|
+
end
|
139
|
+
end
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
|
143
|
+
# Find all operations in the schema
|
144
|
+
#
|
145
|
+
# @return [Hash<String, Hash>] Map of operation IDs to operation schemas
|
146
|
+
def find_all_operations
|
147
|
+
result = {}
|
148
|
+
@schema["paths"].each_value do |path_item|
|
149
|
+
["get", "post", "put", "delete", "patch"].each do |method|
|
150
|
+
next unless path_item[method]
|
151
|
+
|
152
|
+
operation = path_item[method]
|
153
|
+
result[operation["operationId"]] = operation if operation["operationId"]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
result
|
157
|
+
end
|
158
|
+
|
159
|
+
# Extract the response schema from an operation
|
160
|
+
#
|
161
|
+
# @param [Hash] operation_schema The operation schema
|
162
|
+
# @return [Hash, nil] The response schema if found
|
163
|
+
def extract_response_schema(operation_schema)
|
164
|
+
return unless operation_schema["responses"]
|
165
|
+
|
166
|
+
# Try to get 200 response first, then any 2xx response
|
167
|
+
response = operation_schema["responses"]["200"] ||
|
168
|
+
operation_schema["responses"].find { |k, _| k.to_s.start_with?("2") }&.last
|
169
|
+
|
170
|
+
return unless response
|
171
|
+
|
172
|
+
# Amazon SP-API might have different formats
|
173
|
+
if response["content"] && response["content"]["application/json"]
|
174
|
+
# Standard OpenAPI 3.0 format
|
175
|
+
response["content"]["application/json"]["schema"]
|
176
|
+
elsif response["schema"]
|
177
|
+
# Some Amazon models use a direct schema property
|
178
|
+
response["schema"]
|
179
|
+
elsif response["$ref"]
|
180
|
+
# Some models use a reference
|
181
|
+
resolve_reference(response["$ref"])
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Resolve a JSON Schema reference
|
186
|
+
#
|
187
|
+
# @param [String] ref The reference string (e.g., "#/components/schemas/Order")
|
188
|
+
# @return [Hash, nil] The resolved schema or nil if not found
|
189
|
+
def resolve_reference(ref)
|
190
|
+
return unless ref.is_a?(String) && ref.start_with?("#/")
|
191
|
+
|
192
|
+
path = ref[2..-1].split("/")
|
193
|
+
current = @schema
|
194
|
+
|
195
|
+
path.each do |segment|
|
196
|
+
return nil unless current[segment]
|
197
|
+
|
198
|
+
current = current[segment]
|
199
|
+
end
|
200
|
+
|
201
|
+
current
|
202
|
+
end
|
203
|
+
|
204
|
+
# Create a parser class for a specific operation and schema
|
205
|
+
#
|
206
|
+
# @param [String] operation_id The operation ID
|
207
|
+
# @param [Hash] response_schema The response schema
|
208
|
+
# @return [Class] A parser class for the operation
|
209
|
+
def create_parser_class(operation_id, response_schema)
|
210
|
+
# Store a reference to the generator for resolving references
|
211
|
+
generator = self
|
212
|
+
|
213
|
+
Class.new do
|
214
|
+
# Store schema and operation ID as class methods
|
215
|
+
define_singleton_method(:schema) { response_schema }
|
216
|
+
define_singleton_method(:operation_id) { operation_id }
|
217
|
+
|
218
|
+
# Store a reference to the generator for resolving nested references
|
219
|
+
define_singleton_method(:generator) { generator }
|
220
|
+
|
221
|
+
# Initialize the parser
|
222
|
+
#
|
223
|
+
# @param [Hash] options Parser options
|
224
|
+
def initialize(options = {})
|
225
|
+
@options = options
|
226
|
+
@symbolize_keys = options.fetch(:symbolize_keys, false)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Parse the HTTP response
|
230
|
+
#
|
231
|
+
# @param [HTTP::Response] response The HTTP response
|
232
|
+
# @return [Hash] The parsed response
|
233
|
+
def call(response)
|
234
|
+
@parsed_response = JSON.parse(response.body.to_s)
|
235
|
+
transform_response(self.class.schema, @parsed_response)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Convert the response to a hash
|
239
|
+
#
|
240
|
+
# @return [Hash] The parsed response hash
|
241
|
+
def to_h
|
242
|
+
@parsed_response
|
243
|
+
end
|
244
|
+
|
245
|
+
private
|
246
|
+
|
247
|
+
# Transform the response based on the schema
|
248
|
+
#
|
249
|
+
# @param [Hash] schema The schema for the current part of the response
|
250
|
+
# @param [Hash, Array, Object] data The data to transform
|
251
|
+
# @return [Hash, Array, Object] The transformed data
|
252
|
+
def transform_response(schema, data)
|
253
|
+
case data
|
254
|
+
when Hash
|
255
|
+
transform_hash(schema, data)
|
256
|
+
when Array
|
257
|
+
transform_array(schema, data)
|
258
|
+
else
|
259
|
+
transform_primitive(schema, data)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Transform a hash based on its schema
|
264
|
+
#
|
265
|
+
# @param [Hash] schema The schema for the hash
|
266
|
+
# @param [Hash] hash The hash to transform
|
267
|
+
# @return [Hash, Data] The transformed hash or Data object
|
268
|
+
def transform_hash(schema, hash)
|
269
|
+
# Resolve schema reference if present
|
270
|
+
if schema["$ref"] && self.class.generator
|
271
|
+
ref_schema = self.class.generator.send(:resolve_reference, schema["$ref"])
|
272
|
+
schema = ref_schema if ref_schema
|
273
|
+
end
|
274
|
+
|
275
|
+
# First, check if this hash represents a known type that should be converted to a Data object
|
276
|
+
data_type = determine_data_type(schema, hash)
|
277
|
+
return transform_to_data_object(data_type, hash) if data_type
|
278
|
+
|
279
|
+
# Otherwise, process as a regular hash
|
280
|
+
result = @symbolize_keys ? {} : hash.class.new
|
281
|
+
|
282
|
+
hash.each do |k, v|
|
283
|
+
key = @symbolize_keys ? k.to_sym : k
|
284
|
+
|
285
|
+
# Get property schema, possibly resolving references
|
286
|
+
property_schema = nil
|
287
|
+
if schema["properties"] && schema["properties"][k]
|
288
|
+
property_schema = schema["properties"][k]
|
289
|
+
|
290
|
+
# Resolve property schema reference if present
|
291
|
+
if property_schema["$ref"] && self.class.generator
|
292
|
+
ref_schema = self.class.generator.send(:resolve_reference, property_schema["$ref"])
|
293
|
+
property_schema = ref_schema if ref_schema
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Special handling for known Amazon types
|
298
|
+
transformed = if money_type?(property_schema)
|
299
|
+
transform_money(v)
|
300
|
+
elsif datetime_type?(property_schema, k)
|
301
|
+
transform_datetime(v)
|
302
|
+
elsif dimension_type?(property_schema)
|
303
|
+
transform_dimension(v)
|
304
|
+
elsif address_type?(property_schema)
|
305
|
+
transform_address(v)
|
306
|
+
else
|
307
|
+
transform_response(property_schema || {}, v)
|
308
|
+
end
|
309
|
+
|
310
|
+
result[key] = transformed
|
311
|
+
end
|
312
|
+
|
313
|
+
result
|
314
|
+
end
|
315
|
+
|
316
|
+
# Determine if a hash should be converted to a Data object
|
317
|
+
#
|
318
|
+
# @param [Hash] schema The schema for the hash
|
319
|
+
# @param [Hash] hash The hash to transform
|
320
|
+
# @return [Symbol, nil] The Data type to use, or nil if not a recognized type
|
321
|
+
def determine_data_type(schema, hash)
|
322
|
+
return :money if money_type?(schema) ||
|
323
|
+
(hash.key?("CurrencyCode") && hash.key?("Amount"))
|
324
|
+
|
325
|
+
return :dimension if dimension_type?(schema) ||
|
326
|
+
(hash.key?("Value") && hash.key?("Unit"))
|
327
|
+
|
328
|
+
return :address if address_type?(schema) ||
|
329
|
+
(hash.key?("City") && hash.key?("PostalCode") &&
|
330
|
+
hash.key?("CountryCode"))
|
331
|
+
|
332
|
+
return :weight if hash.key?("Value") && hash.key?("Unit") &&
|
333
|
+
schema.dig("properties", "Unit", "enum")&.include?("pounds")
|
334
|
+
|
335
|
+
return :daterange if hash.key?("Start") && hash.key?("End") &&
|
336
|
+
schema.dig("properties", "Start", "type") == "string" &&
|
337
|
+
schema.dig("properties", "End", "type") == "string"
|
338
|
+
|
339
|
+
nil
|
340
|
+
end
|
341
|
+
|
342
|
+
# Transform a hash to a structured object
|
343
|
+
#
|
344
|
+
# @param [Symbol] data_type The type of structured object to create
|
345
|
+
# @param [Hash] hash The hash to transform
|
346
|
+
# @return [Struct] The structured object
|
347
|
+
def transform_to_data_object(data_type, hash)
|
348
|
+
data_class = DATA_TYPES[data_type]
|
349
|
+
return transform_response({}, hash) unless data_class
|
350
|
+
|
351
|
+
case data_type
|
352
|
+
when :money
|
353
|
+
if defined?(Money) && MONEY_GEM_AVAILABLE
|
354
|
+
# Use Money gem for monetary values if available
|
355
|
+
amount_cents = (BigDecimal(hash["Amount"]) * 100).to_i
|
356
|
+
Money.new(amount_cents, hash["CurrencyCode"])
|
357
|
+
else
|
358
|
+
# Use Struct as fallback
|
359
|
+
data_class.new(
|
360
|
+
currency: hash["CurrencyCode"],
|
361
|
+
amount: BigDecimal(hash["Amount"]),
|
362
|
+
)
|
363
|
+
end
|
364
|
+
when :dimension, :weight
|
365
|
+
data_class.new(
|
366
|
+
value: numeric_value(hash["Value"]),
|
367
|
+
unit: hash["Unit"],
|
368
|
+
)
|
369
|
+
when :address
|
370
|
+
data_class.new(
|
371
|
+
name: hash["Name"],
|
372
|
+
address_line1: hash["AddressLine1"],
|
373
|
+
address_line2: hash["AddressLine2"],
|
374
|
+
city: hash["City"],
|
375
|
+
state_or_region: hash["StateOrRegion"],
|
376
|
+
postal_code: hash["PostalCode"],
|
377
|
+
country_code: hash["CountryCode"],
|
378
|
+
phone: hash["Phone"],
|
379
|
+
)
|
380
|
+
when :daterange
|
381
|
+
start_date = transform_datetime(hash["Start"])
|
382
|
+
end_date = transform_datetime(hash["End"])
|
383
|
+
data_class.new(
|
384
|
+
start: start_date,
|
385
|
+
end: end_date,
|
386
|
+
)
|
387
|
+
when :price
|
388
|
+
data_class.new(
|
389
|
+
currency_code: hash["CurrencyCode"],
|
390
|
+
amount: numeric_value(hash["Amount"]),
|
391
|
+
)
|
392
|
+
else
|
393
|
+
# If we don't recognize the type, just process normally
|
394
|
+
transform_response({}, hash)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# Helper to convert string values to numeric when appropriate
|
399
|
+
#
|
400
|
+
# @param [String] value The value to convert
|
401
|
+
# @return [Numeric] The converted numeric value
|
402
|
+
def numeric_value(value)
|
403
|
+
return value if value.is_a?(Numeric)
|
404
|
+
|
405
|
+
value.to_f
|
406
|
+
end
|
407
|
+
|
408
|
+
# Transform an array based on its schema
|
409
|
+
#
|
410
|
+
# @param [Hash] schema The schema for the array
|
411
|
+
# @param [Array] array The array to transform
|
412
|
+
# @return [Array] The transformed array
|
413
|
+
def transform_array(schema, array)
|
414
|
+
items_schema = schema["items"] || {}
|
415
|
+
array.map { |item| transform_response(items_schema, item) }
|
416
|
+
end
|
417
|
+
|
418
|
+
# Transform a primitive value based on its schema
|
419
|
+
#
|
420
|
+
# @param [Hash] schema The schema for the value
|
421
|
+
# @param [Object] value The value to transform
|
422
|
+
# @return [Object] The transformed value
|
423
|
+
def transform_primitive(schema, value)
|
424
|
+
case schema["type"]
|
425
|
+
when "number", "integer"
|
426
|
+
value.to_f
|
427
|
+
when "boolean"
|
428
|
+
value == true || value == "true"
|
429
|
+
else
|
430
|
+
value
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
# Check if a schema represents a money type
|
435
|
+
#
|
436
|
+
# @param [Hash] schema The schema to check
|
437
|
+
# @return [Boolean] True if the schema represents money
|
438
|
+
def money_type?(schema)
|
439
|
+
return false unless schema && schema["properties"]
|
440
|
+
|
441
|
+
schema["properties"]["CurrencyCode"] &&
|
442
|
+
schema["properties"]["Amount"]
|
443
|
+
end
|
444
|
+
|
445
|
+
# Transform a money object
|
446
|
+
#
|
447
|
+
# @param [Hash] money The money hash to transform
|
448
|
+
# @return [Money, Hash] Money object if gem available, otherwise a hash
|
449
|
+
def transform_money(money)
|
450
|
+
currency_code = money["CurrencyCode"]
|
451
|
+
amount_str = money["Amount"]
|
452
|
+
|
453
|
+
if defined?(Money) && MONEY_GEM_AVAILABLE
|
454
|
+
# Convert to cents (Money uses cents as its base unit)
|
455
|
+
amount_cents = (BigDecimal(amount_str) * 100).to_i
|
456
|
+
|
457
|
+
# Create Money object with the specified currency
|
458
|
+
Money.new(amount_cents, currency_code)
|
459
|
+
else
|
460
|
+
# Fallback when Money gem is not available
|
461
|
+
amount = BigDecimal(amount_str)
|
462
|
+
keys = @symbolize_keys ? [:currency, :amount] : ["currency", "amount"]
|
463
|
+
{
|
464
|
+
keys[0] => currency_code,
|
465
|
+
keys[1] => amount,
|
466
|
+
}
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
# Check if a schema represents a datetime
|
471
|
+
#
|
472
|
+
# @param [Hash] schema The schema to check
|
473
|
+
# @param [String] key The key name
|
474
|
+
# @return [Boolean] True if the schema represents a datetime
|
475
|
+
def datetime_type?(schema, key)
|
476
|
+
return false unless schema && schema["type"] == "string"
|
477
|
+
|
478
|
+
schema["format"] == "date-time" ||
|
479
|
+
key.end_with?("Date", "Time", "At")
|
480
|
+
end
|
481
|
+
|
482
|
+
# Transform a datetime string
|
483
|
+
#
|
484
|
+
# @param [String] datetime The datetime string
|
485
|
+
# @return [DateTime] The parsed datetime
|
486
|
+
def transform_datetime(datetime)
|
487
|
+
# Convert to DateTime for consistent API usage
|
488
|
+
# even though RuboCop prefers Time
|
489
|
+
DateTime.parse(datetime)
|
490
|
+
rescue
|
491
|
+
datetime
|
492
|
+
end
|
493
|
+
|
494
|
+
# Check if a schema represents a dimension
|
495
|
+
#
|
496
|
+
# @param [Hash] schema The schema to check
|
497
|
+
# @return [Boolean] True if the schema represents a dimension
|
498
|
+
def dimension_type?(schema)
|
499
|
+
return false unless schema && schema["properties"]
|
500
|
+
|
501
|
+
schema["properties"]["Value"] &&
|
502
|
+
schema["properties"]["Unit"]
|
503
|
+
end
|
504
|
+
|
505
|
+
# Check if a schema represents an address
|
506
|
+
#
|
507
|
+
# @param [Hash] schema The schema to check
|
508
|
+
# @return [Boolean] True if the schema represents an address
|
509
|
+
def address_type?(schema)
|
510
|
+
return false unless schema && schema["properties"]
|
511
|
+
|
512
|
+
# Check for common address fields
|
513
|
+
address_fields = ["City", "PostalCode", "CountryCode"]
|
514
|
+
address_fields.all? { |field| schema["properties"][field] }
|
515
|
+
end
|
516
|
+
|
517
|
+
# Transform a dimension object
|
518
|
+
#
|
519
|
+
# @param [Hash] dimension The dimension hash to transform
|
520
|
+
# @return [Hash] The transformed dimension object
|
521
|
+
def transform_dimension(dimension)
|
522
|
+
keys = @symbolize_keys ? [:value, :unit] : ["value", "unit"]
|
523
|
+
{
|
524
|
+
keys[0] => dimension["Value"].to_f,
|
525
|
+
keys[1] => dimension["Unit"],
|
526
|
+
}
|
527
|
+
end
|
528
|
+
|
529
|
+
# Transform an address object
|
530
|
+
#
|
531
|
+
# @param [Hash] address The address hash to transform
|
532
|
+
# @return [Struct] A Struct representing the address
|
533
|
+
def transform_address(address)
|
534
|
+
# Create an Address Struct
|
535
|
+
DATA_TYPES[:address].new(
|
536
|
+
name: address["Name"],
|
537
|
+
address_line1: address["AddressLine1"],
|
538
|
+
address_line2: address["AddressLine2"],
|
539
|
+
city: address["City"],
|
540
|
+
state_or_region: address["StateOrRegion"],
|
541
|
+
postal_code: address["PostalCode"],
|
542
|
+
country_code: address["CountryCode"],
|
543
|
+
phone: address["Phone"],
|
544
|
+
)
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
end
|
550
|
+
end
|