shopify_transporter 2.0.1 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 409e6ea11b360d21895a05e2f8f37fa7f924f7e4
4
- data.tar.gz: 94c775ed84f0ecfbe3b8e7a5b084b0e990e5d4ff
3
+ metadata.gz: 6eda8c759a40e474719373d41d3554e10d43f5bf
4
+ data.tar.gz: baca1185566a388a56a725e80e641066b91a8b05
5
5
  SHA512:
6
- metadata.gz: 5eec50cdc6736cca34376105ecbfc8c3b954365a04c9224a112e64ace3f84ae98ccd320b5f09d75ecdc9a7d11e2c11e3384a1a53241c46e94c22f7341ed9a2f4
7
- data.tar.gz: bef84c59176901f9c10a0353f81a22dbcd62dd1865b7e539ce0d3c6ffbe0c0c79e3376c620e08c502b2ab381681bdddcce2bf4ba03e60bf60479a5e129c2260f
6
+ metadata.gz: 6589791c84651519d8b184ff6bb1dd077d08711fab9abd522884c8a74a677d57b034d7b23d9f809bc782142e3845825eefcd3f20e6d362669e166dcd6374ac00
7
+ data.tar.gz: db735a4ed6eba567b4e4a3ec65f8d2182a34bbe8371ec901ccd56252b3b84485bc6ddf5606d249e6577545cdcc1d5bbc8533e2cade66f59167cd1d8b603b24ef
@@ -15,7 +15,12 @@ module ShopifyTransporter
15
15
 
16
16
  def export
17
17
  base_customers.each do |customer|
18
- yield with_attributes(customer)
18
+ begin
19
+ yield with_attributes(customer)
20
+ rescue Savon::Error => e
21
+ print_customer_details_error(customer, e)
22
+ yield customer
23
+ end
19
24
  end
20
25
  end
21
26
 
@@ -38,6 +43,20 @@ module ShopifyTransporter
38
43
  def customer_address_list(customer_id)
39
44
  @client.call(:customer_address_list, customer_id: customer_id).body
40
45
  end
46
+
47
+ def print_customer_details_error(customer, e)
48
+ $stderr.puts '***'
49
+ $stderr.puts 'Warning:'
50
+ $stderr.puts "Encountered an error with fetching details for customer with id: #{customer[:customer_id]}"
51
+ $stderr.puts JSON.pretty_generate(customer)
52
+ $stderr.puts 'The exact error was:'
53
+ $stderr.puts "#{e.class}: "
54
+ $stderr.puts e.message
55
+ $stderr.puts '-'
56
+ $stderr.puts "Exporting the customer (#{customer[:customer_id]}) without its details."
57
+ $stderr.puts 'Continuing with the next customer.'
58
+ $stderr.puts '***'
59
+ end
41
60
  end
42
61
  end
43
62
  end
@@ -15,7 +15,12 @@ module ShopifyTransporter
15
15
 
16
16
  def export
17
17
  base_orders.each do |order|
18
- yield with_attributes(order)
18
+ begin
19
+ yield with_attributes(order)
20
+ rescue Savon::Error => e
21
+ print_order_details_error(order, e)
22
+ yield order
23
+ end
19
24
  end
20
25
  end
21
26
 
@@ -40,6 +45,20 @@ module ShopifyTransporter
40
45
  .call(:sales_order_info, order_increment_id: order_increment_id)
41
46
  .body[:sales_order_info_response]
42
47
  end
48
+
49
+ def print_order_details_error(order, e)
50
+ $stderr.puts '***'
51
+ $stderr.puts 'Warning:'
52
+ $stderr.puts "Encountered an error with fetching details for order with id: #{order[:order_id]}"
53
+ $stderr.puts JSON.pretty_generate(order)
54
+ $stderr.puts 'The exact error was:'
55
+ $stderr.puts "#{e.class}: "
56
+ $stderr.puts e.message
57
+ $stderr.puts '-'
58
+ $stderr.puts "Exporting the order (#{order[:order_id]}) without its details."
59
+ $stderr.puts 'Continuing with the next order.'
60
+ $stderr.puts '***'
61
+ end
43
62
  end
44
63
  end
45
64
  end
@@ -21,7 +21,12 @@ module ShopifyTransporter
21
21
 
22
22
  def export
23
23
  base_products.each do |product|
24
- yield with_attributes(product)
24
+ begin
25
+ yield with_attributes(product)
26
+ rescue Savon::Error => e
27
+ print_product_details_error(product, e)
28
+ yield product
29
+ end
25
30
  end
26
31
  end
27
32
 
@@ -123,6 +128,20 @@ module ShopifyTransporter
123
128
  .call(:catalog_product_tag_list, product_id: product_id.to_i)
124
129
  .body[:catalog_product_tag_list_response][:result][:item]
125
130
  end
131
+
132
+ def print_product_details_error(product, e)
133
+ $stderr.puts '***'
134
+ $stderr.puts 'Warning:'
135
+ $stderr.puts "Encountered an error with fetching details for product with id: #{product[:product_id]}"
136
+ $stderr.puts JSON.pretty_generate(product)
137
+ $stderr.puts 'The exact error was:'
138
+ $stderr.puts "#{e.class}: "
139
+ $stderr.puts e.message
140
+ $stderr.puts '-'
141
+ $stderr.puts "Exporting the product (#{product[:product_id]}) without its details."
142
+ $stderr.puts 'Continuing with the next product.'
143
+ $stderr.puts '***'
144
+ end
126
145
  end
127
146
  end
128
147
  end
@@ -33,10 +33,19 @@ module ShopifyTransporter
33
33
 
34
34
  $stderr.puts "Processing batch: #{current_id}..#{end_of_range}"
35
35
 
36
- enumerator << call(
37
- method,
38
- params.merge(batching_filter(current_id, end_of_range, batch_index_column)),
39
- )
36
+ begin
37
+ enumerator << call(
38
+ method,
39
+ params.merge(batching_filter(current_id, end_of_range, batch_index_column)),
40
+ )
41
+ rescue Savon::Error => e
42
+ output = 'Skipping batch: '\
43
+ "#{current_id}..#{end_of_range} after #{MAX_RETRIES} retries because of an error."
44
+ $stderr.puts output
45
+ $stderr.puts 'The exact error was:'
46
+ $stderr.puts "#{e.class}: "
47
+ $stderr.puts e.message
48
+ end
40
49
 
41
50
  current_id += batch_size
42
51
  end
@@ -31,14 +31,22 @@ module ShopifyTransporter
31
31
  {
32
32
  first_name: address_attrs['firstname'],
33
33
  last_name: address_attrs['lastname'],
34
+ name: name(address_attrs),
34
35
  phone: address_attrs['telephone'],
35
36
  address1: address_attrs['street'],
36
37
  city: address_attrs['city'],
37
38
  province_code: address_attrs['region'],
38
39
  zip: address_attrs['postcode'],
39
40
  country_code: address_attrs['country_id'],
41
+ company: address_attrs['company'],
40
42
  }
41
43
  end
44
+
45
+ def name(address_attrs)
46
+ if address_attrs['firstname'].present? && address_attrs['lastname'].present?
47
+ address_attrs['firstname'] + ' ' + address_attrs['lastname']
48
+ end
49
+ end
42
50
  end
43
51
  end
44
52
  end
@@ -42,6 +42,7 @@ module ShopifyTransporter
42
42
  end
43
43
 
44
44
  def tax_lines(item)
45
+ return unless tax_applied?(item)
45
46
  [
46
47
  {
47
48
  title: 'Tax',
@@ -50,6 +51,10 @@ module ShopifyTransporter
50
51
  }.stringify_keys,
51
52
  ]
52
53
  end
54
+
55
+ def tax_applied?(item)
56
+ item['tax_percent'].to_f > 0 && item['tax_amount'].to_f > 0
57
+ end
53
58
  end
54
59
  end
55
60
  end
@@ -12,10 +12,17 @@ module ShopifyTransporter
12
12
  {
13
13
  name: hash['increment_id'],
14
14
  email: hash['customer_email'],
15
+ currency: hash['order_currency_code'],
16
+ cancelled_at: cancelled_at(hash),
17
+ closed_at: closed_at(hash),
15
18
  processed_at: hash['created_at'],
16
19
  subtotal_price: hash['subtotal'],
17
20
  total_tax: hash['tax_amount'],
18
21
  total_price: hash['grand_total'],
22
+ source_name: ORDER_ORIGINATED_FROM,
23
+ total_weight: hash['weight'],
24
+ financial_status: financial_status(hash),
25
+ fulfillment_status: fulfillment_status(hash),
19
26
  }.stringify_keys
20
27
  )
21
28
  customer = build_customer(hash)
@@ -25,6 +32,8 @@ module ShopifyTransporter
25
32
 
26
33
  private
27
34
 
35
+ ORDER_ORIGINATED_FROM = 'Magento'
36
+
28
37
  def build_customer(hash)
29
38
  {
30
39
  email: hash['customer_email'],
@@ -32,6 +41,102 @@ module ShopifyTransporter
32
41
  last_name: hash['customer_lastname'],
33
42
  }.stringify_keys
34
43
  end
44
+
45
+ def financial_status(hash)
46
+ order_state = hash['state']
47
+ status = nil
48
+
49
+ if order_state == 'Pending Payment'
50
+ status = 'pending'
51
+ elsif paid?(hash)
52
+ status = 'paid'
53
+ elsif partially_paid?(hash)
54
+ status = 'partially_paid'
55
+ elsif partially_refunded?(hash)
56
+ status = 'partially_refunded'
57
+ elsif refunded?(hash)
58
+ status = 'refunded'
59
+ end
60
+ status
61
+ end
62
+
63
+ def fulfillment_status(hash)
64
+ total_qty_ordered = hash['total_qty_ordered'].to_i
65
+ total_qty_shipped = total_qty_shipped(hash)
66
+ status = nil
67
+
68
+ if total_qty_shipped == total_qty_ordered
69
+ status = 'fulfilled'
70
+ elsif total_qty_shipped > 0 && total_qty_shipped < total_qty_ordered
71
+ status = 'partial'
72
+ end
73
+ status
74
+ end
75
+
76
+ def cancelled_at(hash)
77
+ timestamp(hash, 'canceled') if cancelled?(hash)
78
+ end
79
+
80
+ def closed_at(hash)
81
+ timestamp(hash, 'closed') if closed?(hash)
82
+ end
83
+
84
+ def cancelled?(hash)
85
+ hash['state'] == 'canceled'
86
+ end
87
+
88
+ def closed?(hash)
89
+ hash['state'] == 'closed'
90
+ end
91
+
92
+ def total_price(hash)
93
+ hash['grand_total'].to_i
94
+ end
95
+
96
+ def total_paid(hash)
97
+ return hash['total_paid'].to_i if hash['total_paid'].present?
98
+ 0
99
+ end
100
+
101
+ def total_refunded(hash)
102
+ return hash['total_refunded'].to_i if hash['total_refunded'].present?
103
+ 0
104
+ end
105
+
106
+ def paid?(hash)
107
+ total_price(hash) == total_paid(hash) && total_refunded(hash) == 0
108
+ end
109
+
110
+ def partially_paid?(hash)
111
+ total_paid(hash) > 0 && total_paid(hash) < total_price(hash) && total_refunded(hash) == 0
112
+ end
113
+
114
+ def partially_refunded?(hash)
115
+ total_refunded(hash) > 0 && total_refunded(hash) < total_paid(hash)
116
+ end
117
+
118
+ def refunded?(hash)
119
+ total_refunded(hash) == total_paid(hash) && total_refunded(hash) != 0
120
+ end
121
+
122
+ def total_qty_shipped(hash)
123
+ return 0 unless hash.dig('items', 'result', 'items', 'item').present?
124
+ line_items = hash['items']['result']['items']['item']
125
+ return line_items['qty_shipped'].to_i if line_items.is_a?(Hash)
126
+ line_items.map { |line_item| line_item['qty_shipped'].to_i }.sum
127
+ end
128
+
129
+ def timestamp(hash, status)
130
+ return unless hash.dig('items', 'result', 'status_history', 'item').present?
131
+
132
+ history_items = hash['items']['result']['status_history']['item']
133
+ return history_items['created_at'] if history_items.is_a?(Hash) && history_items['status'] == status
134
+
135
+ last_applicable_history_item = history_items.select do |history|
136
+ history['status'] == status
137
+ end.last
138
+ last_applicable_history_item['created_at'] if last_applicable_history_item.present?
139
+ end
35
140
  end
36
141
  end
37
142
  end
@@ -0,0 +1,47 @@
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 Transactions < Pipeline::Stage
9
+ def convert(input, record)
10
+ record.merge!(
11
+ {
12
+ transactions: transactions(input),
13
+ }.stringify_keys
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def transactions(input)
20
+ [
21
+ sale_transaction(input),
22
+ refund_transaction(input),
23
+ ].compact
24
+ end
25
+
26
+ def sale_transaction(input)
27
+ return unless input['total_paid'].present?
28
+ {
29
+ amount: input['total_paid'].to_f,
30
+ kind: 'sale',
31
+ status: 'success',
32
+ }.stringify_keys
33
+ end
34
+
35
+ def refund_transaction(input)
36
+ return unless input['total_refunded'].present?
37
+ {
38
+ amount: input['total_refunded'].to_f,
39
+ kind: 'refund',
40
+ status: 'success',
41
+ }.stringify_keys
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -25,8 +25,8 @@ module ShopifyTransporter
25
25
  'Lineitem price', 'Lineitem discount', 'Lineitem compare at price', 'Lineitem sku',
26
26
  'Lineitem requires shipping', 'Lineitem taxable', 'Lineitem fulfillment status',
27
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'
28
+ 'Tax 3 Title', 'Tax 3 Price', 'Tax 3 Rate', 'Transaction amount', 'Transaction kind', 'Transaction status',
29
+ 'Metafield Namespace', 'Metafield Key', 'Metafield Value', 'Metafield Value Type'
30
30
  ].to_csv
31
31
  end
32
32
 
@@ -45,6 +45,7 @@ module ShopifyTransporter
45
45
  CSV.generate do |csv|
46
46
  csv << top_level_row_values
47
47
  line_item_row_values.each { |row| csv << row }
48
+ transaction_row_values.each { |row| csv << row }
48
49
  metafield_row_values.each { |row| csv << row }
49
50
  end
50
51
  end
@@ -67,6 +68,12 @@ module ShopifyTransporter
67
68
  name quantity price discount compare_at_price sku requires_shipping taxable fulfillment_status
68
69
  )
69
70
 
71
+ TRANSACTION_PREFIX = 'transaction_'
72
+
73
+ TRANSACTION_ATTRIBUTES = %w(
74
+ amount kind status
75
+ )
76
+
70
77
  def address_hash_for(address_hash, prefix)
71
78
  return {} if address_hash.blank?
72
79
 
@@ -102,6 +109,17 @@ module ShopifyTransporter
102
109
  row_values_from(line_item) if self.class.has_values?(line_item)
103
110
  end.compact
104
111
  end
112
+
113
+ def transaction_row_values
114
+ return [] unless record_hash['transactions']
115
+
116
+ record_hash['transactions'].map do |transaction_hash|
117
+ transaction = transaction_hash.slice(*TRANSACTION_ATTRIBUTES)
118
+ .transform_keys! { |k| "#{TRANSACTION_PREFIX}#{k}" }
119
+
120
+ row_values_from(transaction) if self.class.has_values?(transaction)
121
+ end.compact
122
+ end
105
123
  end
106
124
  end
107
125
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ShopifyTransporter
3
- VERSION = '2.0.1'
3
+ VERSION = '2.2.0'
4
4
  end
@@ -28,6 +28,7 @@ object_types:
28
28
  - TopLevelAttributes
29
29
  - LineItems
30
30
  - AddressesAttribute
31
+ - Transactions
31
32
 
32
33
  extract_configuration:
33
34
  soap:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify_transporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-04 00:00:00.000000000 Z
11
+ date: 2018-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -163,6 +163,7 @@ files:
163
163
  - lib/shopify_transporter/pipeline/magento/order/addresses_attribute.rb
164
164
  - lib/shopify_transporter/pipeline/magento/order/line_items.rb
165
165
  - lib/shopify_transporter/pipeline/magento/order/top_level_attributes.rb
166
+ - lib/shopify_transporter/pipeline/magento/order/transactions.rb
166
167
  - lib/shopify_transporter/pipeline/magento/product/top_level_attributes.rb
167
168
  - lib/shopify_transporter/pipeline/magento/product/top_level_variant_attributes.rb
168
169
  - lib/shopify_transporter/pipeline/magento/product/variant_attributes.rb