shopify_transporter 2.0.1 → 2.2.0

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: 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