shopify_transporter 1.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.
- checksums.yaml +7 -0
- data/Gemfile +23 -0
- data/LICENSE +20 -0
- data/README.md +290 -0
- data/RELEASING +16 -0
- data/Rakefile +11 -0
- data/exe/shopify_transporter +47 -0
- data/lib/shopify_transporter/generators/base_group.rb +25 -0
- data/lib/shopify_transporter/generators/generate.rb +64 -0
- data/lib/shopify_transporter/generators/new.rb +23 -0
- data/lib/shopify_transporter/generators.rb +3 -0
- data/lib/shopify_transporter/pipeline/all_platforms/metafields.rb +61 -0
- data/lib/shopify_transporter/pipeline/magento/customer/addresses_attribute.rb +60 -0
- data/lib/shopify_transporter/pipeline/magento/customer/top_level_attributes.rb +47 -0
- data/lib/shopify_transporter/pipeline/magento/order/addresses_attribute.rb +46 -0
- data/lib/shopify_transporter/pipeline/magento/order/line_items.rb +55 -0
- data/lib/shopify_transporter/pipeline/magento/order/top_level_attributes.rb +39 -0
- data/lib/shopify_transporter/pipeline/magento/product/top_level_attributes.rb +36 -0
- data/lib/shopify_transporter/pipeline/stage.rb +16 -0
- data/lib/shopify_transporter/pipeline.rb +4 -0
- data/lib/shopify_transporter/record_builder.rb +51 -0
- data/lib/shopify_transporter/shopify/attributes_accumulator.rb +43 -0
- data/lib/shopify_transporter/shopify/attributes_helpers.rb +53 -0
- data/lib/shopify_transporter/shopify/customer.rb +79 -0
- data/lib/shopify_transporter/shopify/order.rb +107 -0
- data/lib/shopify_transporter/shopify/product.rb +118 -0
- data/lib/shopify_transporter/shopify/record.rb +60 -0
- data/lib/shopify_transporter/shopify.rb +7 -0
- data/lib/shopify_transporter/version.rb +4 -0
- data/lib/shopify_transporter.rb +247 -0
- data/lib/tasks/factory_bot.rake +9 -0
- data/lib/templates/custom_stage.tt +31 -0
- data/lib/templates/gemfile.tt +5 -0
- data/lib/templates/magento/config.tt +23 -0
- data/shopify_transporter.gemspec +36 -0
- metadata +152 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'shopify_transporter/pipeline/stage'
|
3
|
+
require 'shopify_transporter/shopify'
|
4
|
+
|
5
|
+
module ShopifyTransporter
|
6
|
+
module Pipeline
|
7
|
+
module Magento
|
8
|
+
module Customer
|
9
|
+
class TopLevelAttributes < Pipeline::Stage
|
10
|
+
def convert(hash, record)
|
11
|
+
accumulator = TopLevelAttributesAccumulator.new(record)
|
12
|
+
accumulator.accumulate(hash)
|
13
|
+
record.merge!(accumulator.output)
|
14
|
+
end
|
15
|
+
|
16
|
+
class TopLevelAttributesAccumulator < Shopify::AttributesAccumulator
|
17
|
+
COLUMN_MAPPING = {
|
18
|
+
'firstname' => 'first_name',
|
19
|
+
'lastname' => 'last_name',
|
20
|
+
'email' => 'email',
|
21
|
+
}
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def input_applies?(_input)
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def attributes_from(input)
|
30
|
+
attributes = COLUMN_MAPPING.each_with_object({}) do |(key, value), obj|
|
31
|
+
obj[value] = input[key] if input[key]
|
32
|
+
end
|
33
|
+
attributes['accepts_marketing'] = accepts_marketing(input)
|
34
|
+
attributes
|
35
|
+
end
|
36
|
+
|
37
|
+
def accepts_marketing(input)
|
38
|
+
value = input['is_subscribed']
|
39
|
+
return unless value.present?
|
40
|
+
(value == '1').to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'shopify_transporter/pipeline/stage'
|
3
|
+
require 'shopify_transporter/shopify'
|
4
|
+
module ShopifyTransporter
|
5
|
+
module Pipeline
|
6
|
+
module Magento
|
7
|
+
module Order
|
8
|
+
class AddressesAttribute < Pipeline::Stage
|
9
|
+
BILLING_PREFIX = 'billing_'
|
10
|
+
SHIPPING_PREFIX = 'shipping_'
|
11
|
+
|
12
|
+
def convert(input, record)
|
13
|
+
record['billing_address'] = address_attributes(input, BILLING_PREFIX)
|
14
|
+
record['shipping_address'] = address_attributes(input, SHIPPING_PREFIX)
|
15
|
+
record
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def get_nested_address(input, prefix)
|
21
|
+
items = input['items']
|
22
|
+
result = items && items['result']
|
23
|
+
address = result && result["#{prefix}address"]
|
24
|
+
address || []
|
25
|
+
end
|
26
|
+
|
27
|
+
def address_attributes(input, prefix)
|
28
|
+
address_attrs = get_nested_address(input, prefix)
|
29
|
+
return address_attrs unless address_attrs.present?
|
30
|
+
|
31
|
+
{
|
32
|
+
first_name: address_attrs['firstname'],
|
33
|
+
last_name: address_attrs['lastname'],
|
34
|
+
phone: address_attrs['telephone'],
|
35
|
+
address1: address_attrs['street'],
|
36
|
+
city: address_attrs['city'],
|
37
|
+
province_code: address_attrs['region'],
|
38
|
+
zip: address_attrs['postcode'],
|
39
|
+
country_code: address_attrs['country_id'],
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'shopify_transporter/pipeline/stage'
|
3
|
+
require 'shopify_transporter/shopify'
|
4
|
+
|
5
|
+
module ShopifyTransporter
|
6
|
+
module Pipeline
|
7
|
+
module Magento
|
8
|
+
module Order
|
9
|
+
class LineItems < Pipeline::Stage
|
10
|
+
def convert(input, record)
|
11
|
+
record.merge!(
|
12
|
+
{
|
13
|
+
line_items: line_items(input),
|
14
|
+
}.stringify_keys
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def line_items(input)
|
21
|
+
line_items = line_items_array(input)
|
22
|
+
line_items.map { |item| line_item(item) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def line_items_array(input)
|
26
|
+
items_1 = input['items']
|
27
|
+
result = items_1 && items_1['result']
|
28
|
+
items_2 = result && result['items']
|
29
|
+
item = items_2 && items_2['item']
|
30
|
+
return [] unless item
|
31
|
+
item.is_a?(Array) ? item : [item]
|
32
|
+
end
|
33
|
+
|
34
|
+
def line_item(item)
|
35
|
+
{
|
36
|
+
quantity: item['qty_ordered'],
|
37
|
+
sku: item['sku'],
|
38
|
+
name: item['name'],
|
39
|
+
price: item['price'],
|
40
|
+
tax_lines: tax_lines(item),
|
41
|
+
}.stringify_keys
|
42
|
+
end
|
43
|
+
|
44
|
+
def tax_lines(item)
|
45
|
+
{
|
46
|
+
title: 'Tax',
|
47
|
+
price: item['tax_amount'],
|
48
|
+
rate: item['tax_percent'],
|
49
|
+
}.stringify_keys
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'shopify_transporter/pipeline/stage'
|
3
|
+
require 'shopify_transporter/shopify'
|
4
|
+
|
5
|
+
module ShopifyTransporter
|
6
|
+
module Pipeline
|
7
|
+
module Magento
|
8
|
+
module Order
|
9
|
+
class TopLevelAttributes < Pipeline::Stage
|
10
|
+
def convert(hash, record)
|
11
|
+
record.merge!(
|
12
|
+
{
|
13
|
+
name: hash['increment_id'],
|
14
|
+
email: hash['customer_email'],
|
15
|
+
processed_at: hash['created_at'],
|
16
|
+
subtotal_price: hash['subtotal'],
|
17
|
+
total_tax: hash['tax_amount'],
|
18
|
+
total_price: hash['grand_total'],
|
19
|
+
}.stringify_keys
|
20
|
+
)
|
21
|
+
customer = build_customer(hash)
|
22
|
+
record['customer'] = customer unless customer.empty?
|
23
|
+
record
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_customer(hash)
|
29
|
+
{
|
30
|
+
email: hash['customer_email'],
|
31
|
+
first_name: hash['customer_firstname'],
|
32
|
+
last_name: hash['customer_lastname'],
|
33
|
+
}.stringify_keys
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'shopify_transporter/pipeline/stage'
|
3
|
+
require 'shopify_transporter/shopify'
|
4
|
+
|
5
|
+
module ShopifyTransporter
|
6
|
+
module Pipeline
|
7
|
+
module Magento
|
8
|
+
module Product
|
9
|
+
class TopLevelAttributes < Pipeline::Stage
|
10
|
+
def convert(hash, record)
|
11
|
+
accumulator = TopLevelAttributesAccumulator.new(record)
|
12
|
+
accumulator.accumulate(hash)
|
13
|
+
end
|
14
|
+
|
15
|
+
class TopLevelAttributesAccumulator < Shopify::AttributesAccumulator
|
16
|
+
COLUMN_MAPPING = {
|
17
|
+
'sku' => 'sku',
|
18
|
+
'name' => 'title',
|
19
|
+
'description' => 'body_html',
|
20
|
+
}
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def input_applies?(_input)
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def attributes_from(input)
|
29
|
+
map_from_key_to_val(COLUMN_MAPPING, input)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ShopifyTransporter
|
3
|
+
module Pipeline
|
4
|
+
class Stage
|
5
|
+
attr_reader :params
|
6
|
+
|
7
|
+
def initialize(params = nil)
|
8
|
+
@params = params
|
9
|
+
end
|
10
|
+
|
11
|
+
def convert(_hash, _record)
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyTransporter
|
4
|
+
class KeyMissing < StandardError
|
5
|
+
def initialize(key_name)
|
6
|
+
super("cannot process entry. Required field not found: '#{key_name}'")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class RequiredKeyMissing < KeyMissing; end
|
11
|
+
|
12
|
+
class MissingParentObject < KeyMissing; end
|
13
|
+
|
14
|
+
class RecordBuilder
|
15
|
+
attr_accessor :instances
|
16
|
+
|
17
|
+
def initialize(key_name, key_required)
|
18
|
+
@instances = {}
|
19
|
+
@key_name = key_name
|
20
|
+
@key_required = key_required
|
21
|
+
end
|
22
|
+
|
23
|
+
def build(input)
|
24
|
+
validate_related(input)
|
25
|
+
|
26
|
+
if key_of(input).nil?
|
27
|
+
yield @last_record
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
yield record_from(input)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def validate_related(input)
|
37
|
+
raise MissingParentObject, @key_name if key_of(input).nil? && @last_record.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def record_from(input)
|
41
|
+
record = @instances[key_of(input)] ||= {}
|
42
|
+
@last_record = record
|
43
|
+
end
|
44
|
+
|
45
|
+
def key_of(input)
|
46
|
+
record_key = input[@key_name]
|
47
|
+
raise RequiredKeyMissing, @key_name if @key_required && record_key.nil?
|
48
|
+
record_key
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'attributes_helpers'
|
3
|
+
|
4
|
+
module ShopifyTransporter
|
5
|
+
module Shopify
|
6
|
+
class AttributesAccumulator
|
7
|
+
include AttributesHelpers
|
8
|
+
|
9
|
+
attr_reader :output
|
10
|
+
|
11
|
+
def initialize(initial_value)
|
12
|
+
@output = initial_value
|
13
|
+
end
|
14
|
+
|
15
|
+
def accumulate(input)
|
16
|
+
return @output unless input_applies?(input)
|
17
|
+
attributes = attributes_from(input)
|
18
|
+
accumulate_attributes(attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def input_applies?(_input)
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
def attributes_from(_input)
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
def accumulate_attributes(attributes)
|
32
|
+
case @output
|
33
|
+
when Array
|
34
|
+
@output << attributes
|
35
|
+
when Hash
|
36
|
+
@output.merge!(attributes)
|
37
|
+
else
|
38
|
+
raise 'Unexpected initial value. Initial value must be an array or a hash.'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "active_support/core_ext/string"
|
3
|
+
module ShopifyTransporter
|
4
|
+
module Shopify
|
5
|
+
module AttributesHelpers
|
6
|
+
def attributes_present?(row, *attributes)
|
7
|
+
row.slice(*attributes).any? { |_, v| v.present? }
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_prefix(prefix, *attributes)
|
11
|
+
[*attributes].map { |attribute| "#{prefix}#{attribute}".to_sym }
|
12
|
+
end
|
13
|
+
|
14
|
+
def drop_prefix(row, prefix)
|
15
|
+
row.transform_keys { |key| key.to_s.remove(prefix).to_sym }
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete_empty_attributes(row)
|
19
|
+
row.delete_if { |_, v| v.respond_to?(:empty?) && v.empty? }
|
20
|
+
end
|
21
|
+
|
22
|
+
def normalize_keys(row)
|
23
|
+
row.compact.transform_keys { |key| normalize_string(key).to_sym }
|
24
|
+
end
|
25
|
+
|
26
|
+
def normalize_string(str)
|
27
|
+
str.to_s.parameterize.underscore
|
28
|
+
end
|
29
|
+
|
30
|
+
def rename_fields(row, field_map)
|
31
|
+
return row unless field_map.present?
|
32
|
+
row = row.dup
|
33
|
+
field_map.each { |from, to| row[to] = row.delete from if row[from].present? }
|
34
|
+
row
|
35
|
+
end
|
36
|
+
|
37
|
+
def map_from_key_to_val(mapper, input)
|
38
|
+
mapper.each_with_object({}) do |(key, value), attributes|
|
39
|
+
attributes[value] = input[key] if input[key]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def shopify_metafield_hash(key:, value:, value_type: 'string', namespace:)
|
44
|
+
{
|
45
|
+
'key' => key,
|
46
|
+
'value' => value,
|
47
|
+
'value_type' => value_type,
|
48
|
+
'namespace' => namespace,
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative 'record'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'csv'
|
5
|
+
|
6
|
+
module ShopifyTransporter
|
7
|
+
module Shopify
|
8
|
+
class Customer < Record
|
9
|
+
class << self
|
10
|
+
def header
|
11
|
+
columns.map(&:titleize).to_csv
|
12
|
+
end
|
13
|
+
|
14
|
+
def keys
|
15
|
+
%w(email phone).freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def columns
|
19
|
+
%w(
|
20
|
+
first_name last_name email phone accepts_marketing tags
|
21
|
+
note tax_exempt company address1 address2 city province
|
22
|
+
province_code zip country country_code metafield_namespace
|
23
|
+
metafield_key metafield_value metafield_value_type
|
24
|
+
).freeze
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_csv
|
29
|
+
CSV.generate do |csv|
|
30
|
+
csv << top_level_row_values
|
31
|
+
address_row_values.each { |row| csv << row }
|
32
|
+
metafield_row_values.each { |row| csv << row }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
TOP_LEVEL_ATTRIBUTES = %w(
|
39
|
+
first_name last_name email phone
|
40
|
+
accepts_marketing
|
41
|
+
tags
|
42
|
+
note
|
43
|
+
tax_exempt
|
44
|
+
).freeze
|
45
|
+
|
46
|
+
ADDRESS_ATTRIBUTES = %w(
|
47
|
+
first_name last_name phone
|
48
|
+
company
|
49
|
+
address1 address2
|
50
|
+
city
|
51
|
+
province province_code zip
|
52
|
+
country country_code
|
53
|
+
).freeze
|
54
|
+
|
55
|
+
SHARED_ADDRESS_ATTRIBUTES = %w(
|
56
|
+
first_name last_name phone
|
57
|
+
).freeze
|
58
|
+
|
59
|
+
def top_level_row_values
|
60
|
+
base_hash.merge(record_hash.slice(*TOP_LEVEL_ATTRIBUTES)).values
|
61
|
+
end
|
62
|
+
|
63
|
+
def address_row_values
|
64
|
+
return [] unless record_hash['addresses']
|
65
|
+
record_hash['addresses'].map do |address_hash|
|
66
|
+
address = address_hash.slice(*ADDRESS_ATTRIBUTES)
|
67
|
+
populate_missing_address_attributes!(address)
|
68
|
+
row_values_from(address) if self.class.has_values?(address)
|
69
|
+
end.compact
|
70
|
+
end
|
71
|
+
|
72
|
+
def populate_missing_address_attributes!(address)
|
73
|
+
SHARED_ADDRESS_ATTRIBUTES.each do |shared_attribute|
|
74
|
+
address[shared_attribute] = record_hash[shared_attribute] if address[shared_attribute].nil?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'csv'
|
4
|
+
require_relative 'attributes_helpers'
|
5
|
+
require_relative 'record'
|
6
|
+
|
7
|
+
module ShopifyTransporter
|
8
|
+
module Shopify
|
9
|
+
class Order < Record
|
10
|
+
class << self
|
11
|
+
include AttributesHelpers
|
12
|
+
|
13
|
+
def header
|
14
|
+
[
|
15
|
+
'Name', 'Email', 'Financial Status', 'Fulfillment Status', 'Currency',
|
16
|
+
'Buyer Accepts Marketing', 'Cancel Reason', 'Cancelled At', 'Closed At', 'Tags', 'Note',
|
17
|
+
'Phone', 'Referring Site', 'Processed At', 'Source name', 'Total discounts', 'Total weight',
|
18
|
+
'Total Tax', 'Shipping Company', 'Shipping Name', 'Shipping Phone', 'Shipping First Name',
|
19
|
+
'Shipping Last Name', 'Shipping Address1', 'Shipping Address2', 'Shipping City',
|
20
|
+
'Shipping Province', 'Shipping Province Code', 'Shipping Zip', 'Shipping Country',
|
21
|
+
'Shipping Country Code', 'Billing Company', 'Billing Name', 'Billing Phone',
|
22
|
+
'Billing First Name', 'Billing Last Name', 'Billing Address1', 'Billing Address2',
|
23
|
+
'Billing City', 'Billing Province', 'Billing Province Code', 'Billing Zip',
|
24
|
+
'Billing Country', 'Billing Country Code', 'Lineitem name', 'Lineitem quantity',
|
25
|
+
'Lineitem price', 'Lineitem discount', 'Lineitem compare at price', 'Lineitem sku',
|
26
|
+
'Lineitem requires shipping', 'Lineitem taxable', 'Lineitem fulfillment status',
|
27
|
+
'Tax 1 Title', 'Tax 1 Price', 'Tax 1 Rate', 'Tax 2 Title', 'Tax 2 Price', 'Tax 2 Rate',
|
28
|
+
'Tax 3 Title', 'Tax 3 Price', 'Tax 3 Rate', 'Metafield Namespace', 'Metafield Key',
|
29
|
+
'Metafield Value', 'Metafield Value Type'
|
30
|
+
].to_csv
|
31
|
+
end
|
32
|
+
|
33
|
+
def keys
|
34
|
+
%w(name).freeze
|
35
|
+
end
|
36
|
+
|
37
|
+
def columns
|
38
|
+
@columns ||= header.split(',').map do |header_column|
|
39
|
+
normalize_string(header_column)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_csv
|
45
|
+
CSV.generate do |csv|
|
46
|
+
csv << top_level_row_values
|
47
|
+
line_item_row_values.each { |row| csv << row }
|
48
|
+
metafield_row_values.each { |row| csv << row }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
TOP_LEVEL_ATTRIBUTES = %w(
|
55
|
+
name email financial_status fulfillment_status currency
|
56
|
+
buyer_accepts_marketing cancel_reason cancelled_at closed_at tags note
|
57
|
+
phone referring_site processed_at source_name total_discounts total_weight total_tax
|
58
|
+
)
|
59
|
+
|
60
|
+
ADDRESS_ATTRIBUTES = %w(
|
61
|
+
company name phone first_name last_name address1 address2 city province province_code zip country country_code
|
62
|
+
)
|
63
|
+
|
64
|
+
LINE_ITEM_PREFIX = "lineitem_"
|
65
|
+
|
66
|
+
LINE_ITEM_ATTRIBUTES = %w(
|
67
|
+
name quantity price discount compare_at_price sku requires_shipping taxable fulfillment_status
|
68
|
+
)
|
69
|
+
|
70
|
+
def address_hash_for(address_hash, prefix)
|
71
|
+
return {} if address_hash.blank?
|
72
|
+
|
73
|
+
address_hash.transform_keys { |k| "#{prefix}#{k}" }
|
74
|
+
end
|
75
|
+
|
76
|
+
def top_level_row_values
|
77
|
+
top_level_hash = record_hash
|
78
|
+
.slice(*TOP_LEVEL_ATTRIBUTES)
|
79
|
+
.merge(address_hash_for(record_hash['billing_address'], 'billing_'))
|
80
|
+
.merge(address_hash_for(record_hash['shipping_address'], 'shipping_'))
|
81
|
+
self.class.has_values?(top_level_hash) ? row_values_from(top_level_hash) : nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def tax_line_hash(line_item_hash)
|
85
|
+
return {} if line_item_hash['tax_lines'].blank?
|
86
|
+
|
87
|
+
line_item_hash['tax_lines'].each_with_index.map do |tax_line, index|
|
88
|
+
tax_line.each_with_object({}) do |(key, val), hash|
|
89
|
+
hash["tax_#{index + 1}_#{key}"] = val
|
90
|
+
end
|
91
|
+
end.reduce({}, :merge)
|
92
|
+
end
|
93
|
+
|
94
|
+
def line_item_row_values
|
95
|
+
return [] unless record_hash['line_items']
|
96
|
+
|
97
|
+
record_hash['line_items'].map do |line_item_hash|
|
98
|
+
line_item = line_item_hash.slice(*LINE_ITEM_ATTRIBUTES)
|
99
|
+
.transform_keys! { |k| "#{LINE_ITEM_PREFIX}#{k}" }
|
100
|
+
.merge(tax_line_hash(line_item_hash))
|
101
|
+
|
102
|
+
row_values_from(line_item) if self.class.has_values?(line_item)
|
103
|
+
end.compact
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|