flowcommerce_spree 0.0.1 → 0.0.6
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 +101 -24
- data/SPREE_FLOW.md +6 -28
- data/app/controllers/concerns/current_zone_loader_decorator.rb +40 -25
- data/app/controllers/flowcommerce_spree/inventory_controller.rb +23 -0
- data/app/controllers/flowcommerce_spree/orders_controller.rb +20 -0
- data/app/controllers/flowcommerce_spree/webhooks_controller.rb +23 -13
- data/app/controllers/users/sessions_controller_decorator.rb +28 -0
- data/app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb +4 -9
- data/app/models/spree/address_decorator.rb +19 -0
- data/app/models/spree/app_configuration_decorator.rb +7 -0
- data/app/models/spree/calculator/flow_io.rb +61 -0
- data/app/models/spree/calculator/shipping/flow_io.rb +40 -0
- data/app/models/spree/flow_io_credit_card_decorator.rb +21 -0
- data/app/models/spree/flow_io_order_decorator.rb +163 -0
- data/app/models/spree/flow_io_product_decorator.rb +2 -2
- data/app/models/spree/flow_io_variant_decorator.rb +4 -2
- data/app/models/spree/gateway/flow_io.rb +153 -0
- data/app/models/spree/{credit_card_decorator.rb → payment_capture_event_decorator.rb} +1 -1
- data/app/models/spree/promotion_handler/coupon_decorator.rb +1 -1
- data/app/models/spree/zones/flow_io_product_zone_decorator.rb +8 -0
- data/app/models/tracking/setup_decorator.rb +40 -0
- data/app/overrides/spree/admin/order_sidebar_summary_flow_link.rb +13 -0
- data/app/overrides/spree/admin/products/order_price_flow_message.rb +9 -0
- data/app/serializers/api/v2/order_serializer_decorator.rb +20 -0
- data/app/services/flowcommerce_spree/import_experience_items.rb +1 -1
- data/app/services/flowcommerce_spree/order_sync.rb +81 -173
- data/app/services/flowcommerce_spree/order_updater.rb +78 -0
- data/app/services/flowcommerce_spree/webhooks/capture_upserted_v2.rb +76 -0
- data/app/services/flowcommerce_spree/webhooks/card_authorization_upserted_v2.rb +66 -0
- data/app/services/flowcommerce_spree/webhooks/experience_upserted_v2.rb +25 -0
- data/app/services/flowcommerce_spree/webhooks/fraud_status_changed.rb +35 -0
- data/app/services/flowcommerce_spree/webhooks/local_item_upserted.rb +40 -0
- data/app/views/spree/admin/payments/source_views/_flow_io_gateway.html.erb +21 -0
- data/config/rails_best_practices.yml +51 -0
- data/config/routes.rb +3 -1
- data/db/migrate/20201021755957_add_meta_to_spree_tables.rb +6 -4
- data/lib/flow/simple_gateway.rb +0 -36
- data/lib/flowcommerce_spree.rb +17 -3
- data/lib/flowcommerce_spree/engine.rb +33 -3
- data/lib/flowcommerce_spree/experience_service.rb +1 -27
- data/lib/flowcommerce_spree/logging_http_client.rb +33 -15
- data/lib/flowcommerce_spree/session.rb +16 -29
- data/lib/flowcommerce_spree/test_support.rb +7 -0
- data/lib/flowcommerce_spree/version.rb +1 -1
- data/lib/tasks/flowcommerce_spree.rake +4 -1
- metadata +90 -22
- data/app/mailers/spree/spree_order_mailer_decorator.rb +0 -24
- data/app/models/spree/gateway/spree_flow_gateway.rb +0 -116
- data/app/models/spree/line_item_decorator.rb +0 -15
- data/app/models/spree/order_decorator.rb +0 -179
- data/app/views/spree/order_mailer/confirm_email.html.erb +0 -86
- data/app/views/spree/order_mailer/confirm_email.text.erb +0 -38
- data/config/initializers/flowcommerce_spree.rb +0 -7
- data/lib/flow/error.rb +0 -73
- data/lib/flow/pay_pal.rb +0 -25
- data/lib/flowcommerce_spree/webhook_service.rb +0 -98
- data/lib/simple_csv_writer.rb +0 -44
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
Address.class_eval do
|
5
|
+
def prepare_from_flow_attributes(address_data)
|
6
|
+
self.attributes = {
|
7
|
+
first_name: address_data['first'],
|
8
|
+
last_name: address_data['last'],
|
9
|
+
phone: address_data['phone'],
|
10
|
+
address1: address_data['streets'][0],
|
11
|
+
address2: address_data['streets'][1],
|
12
|
+
zipcode: address_data['postal'],
|
13
|
+
city: address_data['city'],
|
14
|
+
state_name: address_data['province'],
|
15
|
+
country: Spree::Country.find_by(iso3: address_data['country'])
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class Calculator
|
5
|
+
class FlowIo < Calculator::DefaultTax
|
6
|
+
def self.description
|
7
|
+
'FlowIO Calculator'
|
8
|
+
end
|
9
|
+
|
10
|
+
def compute_shipment_or_line_item(item)
|
11
|
+
order = item.order
|
12
|
+
|
13
|
+
if can_calculate_tax?(order)
|
14
|
+
flow_response = get_flow_tax_data(order)
|
15
|
+
tax_for_item(item, flow_response)
|
16
|
+
else
|
17
|
+
prev_tax_amount(item)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
alias compute_shipment compute_shipment_or_line_item
|
21
|
+
alias compute_line_item compute_shipment_or_line_item
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def prev_tax_amount(item)
|
26
|
+
if rate.included_in_price
|
27
|
+
item.included_tax_total
|
28
|
+
else
|
29
|
+
item.additional_tax_total
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def can_calculate_tax?(order)
|
34
|
+
return false if order.flow_data.blank?
|
35
|
+
return false if %w[cart address].include?(order.state)
|
36
|
+
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_flow_tax_data(order)
|
41
|
+
flow_io_tax_response = Rails.cache.fetch(order.flow_tax_cache_key, time_to_idle: 5.minutes) do
|
42
|
+
FlowcommerceSpree.client.orders.get_allocations_by_number(FlowcommerceSpree::ORGANIZATION, order.number)
|
43
|
+
end
|
44
|
+
flow_io_tax_response
|
45
|
+
end
|
46
|
+
|
47
|
+
def tax_for_item(item, flow_response)
|
48
|
+
prev_tax_amount = prev_tax_amount(item)
|
49
|
+
return prev_tax_amount if flow_response.nil?
|
50
|
+
|
51
|
+
item_details = flow_response.details&.find do |el|
|
52
|
+
item.is_a?(Spree::LineItem) ? el.number == item.variant.sku : el.key.value == 'shipping'
|
53
|
+
end
|
54
|
+
price_components = rate.included_in_price ? item_details.included : item_details.not_included
|
55
|
+
|
56
|
+
amount = price_components&.find { |el| el.key.value == 'vat_item_price' }&.total&.amount
|
57
|
+
amount.present? && amount > 0 ? amount : prev_tax_amount
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class Calculator
|
5
|
+
module Shipping
|
6
|
+
class FlowIo < ShippingCalculator
|
7
|
+
preference :lower_boundary, :decimal, default: 100
|
8
|
+
preference :charge_default, :decimal, default: 15
|
9
|
+
|
10
|
+
def self.description
|
11
|
+
'FlowIO Calculator'
|
12
|
+
end
|
13
|
+
|
14
|
+
def compute_package(package)
|
15
|
+
flow_order = flow_order(package)
|
16
|
+
return unless flow_order
|
17
|
+
|
18
|
+
flow_order['prices'].find { |x| x['key'] == 'shipping' }['amount'] || 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_charge(_country)
|
22
|
+
preferred_charge_default
|
23
|
+
end
|
24
|
+
|
25
|
+
def threshold
|
26
|
+
preferred_lower_boundary
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def flow_order(package)
|
32
|
+
return @flow_order if defined?(@flow_order)
|
33
|
+
|
34
|
+
@flow_order = package.order.flow_data&.[]('order')
|
35
|
+
@flow_order
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module FlowIoCreditCardDecorator
|
5
|
+
def self.prepended(base)
|
6
|
+
base.serialize :meta, ActiveRecord::Coders::JSON.new(symbolize_keys: true)
|
7
|
+
|
8
|
+
base.store_accessor :meta, :flow_data
|
9
|
+
end
|
10
|
+
|
11
|
+
def push_authorization(auth_hash)
|
12
|
+
self.flow_data ||= {}
|
13
|
+
flow_data['authorizations'] ||= []
|
14
|
+
card_authorizations = flow_data['authorizations']
|
15
|
+
card_authorizations.delete_if { |ca| ca['id'] == auth_hash['id'] }
|
16
|
+
card_authorizations << auth_hash
|
17
|
+
end
|
18
|
+
|
19
|
+
Spree::CreditCard.prepend(self) if Spree::CreditCard.included_modules.exclude?(self)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
# Added flow specific methods to Spree::Order
|
5
|
+
module FlowIoOrderDecorator
|
6
|
+
def self.included(base)
|
7
|
+
base.serialize :meta, ActiveRecord::Coders::JSON.new(symbolize_keys: true)
|
8
|
+
|
9
|
+
base.store_accessor :meta, :flow_data
|
10
|
+
end
|
11
|
+
|
12
|
+
def flow_tax_cache_key
|
13
|
+
[number, 'flowcommerce', 'allocation', line_items.sum(:quantity)].join('-')
|
14
|
+
end
|
15
|
+
|
16
|
+
def display_total
|
17
|
+
return unless flow_data&.[]('order')
|
18
|
+
|
19
|
+
Spree::Money.new(flow_io_total_amount, currency: currency)
|
20
|
+
end
|
21
|
+
|
22
|
+
def flow_order
|
23
|
+
flow_data&.[]('order')
|
24
|
+
end
|
25
|
+
|
26
|
+
def flow_order_with_payments?
|
27
|
+
payment = payments.completed.first
|
28
|
+
|
29
|
+
payment&.payment_method&.type == 'Spree::Gateway::FlowIo'
|
30
|
+
end
|
31
|
+
|
32
|
+
# accepts line item, usually called from views
|
33
|
+
def flow_line_item_price(line_item, total = false)
|
34
|
+
result = if (order = flow_order)
|
35
|
+
item = order['lines']&.find { |el| el['item_number'] == line_item.variant.sku }
|
36
|
+
|
37
|
+
return 'n/a' unless item
|
38
|
+
|
39
|
+
total ? item['total']['label'] : item['price']['label']
|
40
|
+
else
|
41
|
+
FlowcommerceSpree::Api.format_default_price(line_item.price * (total ? line_item.quantity : 1))
|
42
|
+
end
|
43
|
+
|
44
|
+
# add line item promo
|
45
|
+
# promo_total, adjustment_total
|
46
|
+
result += " (#{FlowcommerceSpree::Api.format_default_price(line_item.promo_total)})" if line_item.promo_total > 0
|
47
|
+
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
# shows localized total, if possible. if not, fall back to Spree default
|
52
|
+
def flow_io_total_amount
|
53
|
+
flow_data&.dig('order', 'total', 'amount')&.to_d || 0
|
54
|
+
end
|
55
|
+
|
56
|
+
def flow_io_experience_key
|
57
|
+
flow_data&.[]('exp')
|
58
|
+
end
|
59
|
+
|
60
|
+
def flow_io_experience_from_zone
|
61
|
+
self.flow_data = (flow_data || {}).merge!('exp' => zone.flow_io_experience)
|
62
|
+
end
|
63
|
+
|
64
|
+
def flow_io_order_id
|
65
|
+
flow_data&.dig('order', 'id')
|
66
|
+
end
|
67
|
+
|
68
|
+
def flow_io_attributes
|
69
|
+
flow_data&.dig('order', 'attributes') || {}
|
70
|
+
end
|
71
|
+
|
72
|
+
def flow_io_attribute_add(attr_key, value)
|
73
|
+
self.flow_data['order'] ||= {}
|
74
|
+
self.flow_data['order']['attributes'] ||= {}
|
75
|
+
self.flow_data['order']['attributes'][attr_key] = value
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_user_uuid_to_flow_data
|
79
|
+
self.flow_data['order'] ||= {}
|
80
|
+
self.flow_data['order']['attributes'] ||= {}
|
81
|
+
self.flow_data['order']['attributes']['user_uuid'] = user&.uuid || ''
|
82
|
+
end
|
83
|
+
|
84
|
+
def flow_io_attr_user_uuid
|
85
|
+
flow_data&.dig('order', 'attributes', 'user_uuid')
|
86
|
+
end
|
87
|
+
|
88
|
+
def flow_io_captures
|
89
|
+
flow_data&.[]('captures')
|
90
|
+
end
|
91
|
+
|
92
|
+
def flow_io_captures_sum
|
93
|
+
captures_sum = 0
|
94
|
+
flow_data&.[]('captures')&.each do |c|
|
95
|
+
next if c['status'] != 'succeeded'
|
96
|
+
|
97
|
+
amount = c['amount']
|
98
|
+
amount = amount.to_d if amount.is_a?(String)
|
99
|
+
captures_sum += amount
|
100
|
+
end
|
101
|
+
captures_sum.to_d
|
102
|
+
end
|
103
|
+
|
104
|
+
def flow_io_balance_amount
|
105
|
+
flow_data&.dig('order', 'balance', 'amount')&.to_d || 0
|
106
|
+
end
|
107
|
+
|
108
|
+
def flow_io_payments
|
109
|
+
flow_data.dig('order', 'payments')
|
110
|
+
end
|
111
|
+
|
112
|
+
def flow_customer_email
|
113
|
+
flow_data.dig('order', 'customer', 'email')
|
114
|
+
end
|
115
|
+
|
116
|
+
def flow_ship_address
|
117
|
+
flow_destination = flow_data.dig('order', 'destination')
|
118
|
+
return unless flow_destination.present?
|
119
|
+
|
120
|
+
flow_destination['first'] = flow_destination.dig('contact', 'name', 'first')
|
121
|
+
flow_destination['last'] = flow_destination.dig('contact', 'name', 'last')
|
122
|
+
flow_destination['phone'] = flow_destination.dig('contact', 'phone')
|
123
|
+
|
124
|
+
s_address = ship_address || build_ship_address
|
125
|
+
s_address.prepare_from_flow_attributes(flow_destination)
|
126
|
+
s_address
|
127
|
+
end
|
128
|
+
|
129
|
+
def flow_bill_address
|
130
|
+
flow_payment_address = flow_data.dig('order', 'payments')&.last&.[]('address')
|
131
|
+
return unless flow_payment_address
|
132
|
+
|
133
|
+
flow_payment_address['first'] = flow_payment_address.dig('name', 'first')
|
134
|
+
flow_payment_address['last'] = flow_payment_address.dig('name', 'last')
|
135
|
+
flow_payment_address['phone'] = ship_address['phone']
|
136
|
+
|
137
|
+
b_address = bill_address || build_bill_address
|
138
|
+
b_address.prepare_from_flow_attributes(flow_payment_address)
|
139
|
+
b_address
|
140
|
+
end
|
141
|
+
|
142
|
+
def prepare_flow_addresses
|
143
|
+
address_attributes = {}
|
144
|
+
|
145
|
+
s_address = flow_ship_address
|
146
|
+
|
147
|
+
if s_address&.changes&.any?
|
148
|
+
s_address.save!
|
149
|
+
address_attributes[:ship_address_id] = s_address.id unless ship_address_id
|
150
|
+
end
|
151
|
+
|
152
|
+
b_address = flow_bill_address
|
153
|
+
if b_address&.changes&.any?
|
154
|
+
b_address.save!
|
155
|
+
address_attributes[:bill_address_id] = b_address.id unless bill_address_id
|
156
|
+
end
|
157
|
+
|
158
|
+
address_attributes
|
159
|
+
end
|
160
|
+
|
161
|
+
Spree::Order.include(self) if Spree::Order.included_modules.exclude?(self)
|
162
|
+
end
|
163
|
+
end
|
@@ -49,7 +49,7 @@ module Spree
|
|
49
49
|
rmin = min&.amount&.to_s(:rounded, precision: 0) || 0
|
50
50
|
rmax = max&.amount&.to_s(:rounded, precision: 0) || 0
|
51
51
|
|
52
|
-
prices[currency] =
|
52
|
+
prices[currency] = { min: rmin, max: rmax }
|
53
53
|
end
|
54
54
|
|
55
55
|
add_flow_price_range(prices, product_zone)
|
@@ -82,7 +82,7 @@ module Spree
|
|
82
82
|
rmin = min&.amount&.to_s(:rounded, precision: 0) || 0
|
83
83
|
rmax = max&.amount&.to_s(:rounded, precision: 0) || 0
|
84
84
|
|
85
|
-
prices[currency] =
|
85
|
+
prices[currency] = { min: rmin, max: rmax }
|
86
86
|
prices
|
87
87
|
end
|
88
88
|
|
@@ -22,8 +22,8 @@ module Spree
|
|
22
22
|
raise ArgumentError, 'Value should be a hash' unless value.is_a?(Hash)
|
23
23
|
|
24
24
|
self.flow_data = flow_data || {}
|
25
|
-
self.flow_data['exp'] ||= {}
|
26
|
-
self.flow_data['exp'][exp] = value
|
25
|
+
self.flow_data['exp'] ||= {} # rubocop:disable Style/RedundantSelf
|
26
|
+
self.flow_data['exp'][exp] = value # rubocop:disable Style/RedundantSelf
|
27
27
|
end
|
28
28
|
|
29
29
|
# clears flow_data from the records
|
@@ -58,6 +58,8 @@ module Spree
|
|
58
58
|
|
59
59
|
return { error: 'Price is 0' } if price == 0
|
60
60
|
|
61
|
+
return unless country_of_origin
|
62
|
+
|
61
63
|
additional_attrs = {}
|
62
64
|
attr_name = nil
|
63
65
|
export_required = false
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Flow.io (2017)
|
4
|
+
# adapter for Spree that talks to activemerchant_flow
|
5
|
+
module Spree
|
6
|
+
class Gateway
|
7
|
+
class FlowIo < Gateway
|
8
|
+
REFUND_SUCCESS = 'succeeded'
|
9
|
+
|
10
|
+
def provider_class
|
11
|
+
self.class
|
12
|
+
end
|
13
|
+
|
14
|
+
def actions
|
15
|
+
%w[capture authorize purchase refund void]
|
16
|
+
end
|
17
|
+
|
18
|
+
# if user wants to force auto capture
|
19
|
+
def auto_capture?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def payment_profiles_supported?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_type
|
28
|
+
'flow_io_gateway'
|
29
|
+
end
|
30
|
+
|
31
|
+
def preferences
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
|
35
|
+
def supports?(source)
|
36
|
+
# flow supports credit cards
|
37
|
+
source.class == Spree::CreditCard
|
38
|
+
end
|
39
|
+
|
40
|
+
def authorize(_amount, _payment_method, options = {})
|
41
|
+
order = load_order options
|
42
|
+
order.cc_authorization
|
43
|
+
end
|
44
|
+
|
45
|
+
def refund(payment, amount, _options = {})
|
46
|
+
request_refund_store_result(payment.order, amount)
|
47
|
+
rescue StandardError => e
|
48
|
+
ActiveMerchant::Billing::Response.new(false, e.to_s, {}, {})
|
49
|
+
end
|
50
|
+
|
51
|
+
def cancel(authorization)
|
52
|
+
original_payment = Spree::Payment.find_by(response_code: authorization)
|
53
|
+
request_refund_store_result(original_payment.order, original_payment.amount)
|
54
|
+
rescue StandardError => e
|
55
|
+
ActiveMerchant::Billing::Response.new(false, e.to_s, {}, {})
|
56
|
+
end
|
57
|
+
|
58
|
+
def void(authorization_id, _source, options = {})
|
59
|
+
amount = (options[:subtotal] + options[:shipping]) * 0.01
|
60
|
+
reversal_form = Io::Flow::V0::Models::ReversalForm.new(key: options[:order_id],
|
61
|
+
authorization_id: authorization_id,
|
62
|
+
amount: amount,
|
63
|
+
currency: options[:currency])
|
64
|
+
FlowcommerceSpree.client.reversals.post(FlowcommerceSpree::ORGANIZATION, reversal_form)
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_profile(payment)
|
68
|
+
# payment.order.state
|
69
|
+
@credit_card = payment.source
|
70
|
+
|
71
|
+
profile_ensure_payment_method_is_present!
|
72
|
+
create_flow_cc_profile!
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def request_refund_store_result(order, amount)
|
78
|
+
refund_form = Io::Flow::V0::Models::RefundForm.new(order_number: order.number,
|
79
|
+
amount: amount,
|
80
|
+
currency: order.currency)
|
81
|
+
response = FlowcommerceSpree.client.refunds.post(FlowcommerceSpree::ORGANIZATION, refund_form)
|
82
|
+
response_status = response.status.value
|
83
|
+
if response_status == REFUND_SUCCESS
|
84
|
+
add_refund_to_order(response, order)
|
85
|
+
map_refund_to_payment(response, order)
|
86
|
+
ActiveMerchant::Billing::Response.new(true, REFUND_SUCCESS, {}, {})
|
87
|
+
else
|
88
|
+
msg = "Partial refund fail. Details: #{response_status}"
|
89
|
+
ActiveMerchant::Billing::Response.new(false, msg, {}, {})
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_refund_to_order(response, order)
|
94
|
+
order.flow_data ||= {}
|
95
|
+
order.flow_data['refunds'] ||= []
|
96
|
+
order_refunds = order.flow_data['refunds']
|
97
|
+
order_refunds.delete_if { |r| r['id'] == response.id }
|
98
|
+
order_refunds << response.to_hash
|
99
|
+
order.update_column(:meta, order.meta.to_json)
|
100
|
+
end
|
101
|
+
|
102
|
+
def map_refund_to_payment(response, order)
|
103
|
+
original_payment = Spree::Payment.find_by(response_code: response.authorization.id)
|
104
|
+
payment = order.payments.create!(state: 'completed',
|
105
|
+
response_code: response.authorization.id,
|
106
|
+
payment_method_id: original_payment&.payment_method_id,
|
107
|
+
amount: - response.amount,
|
108
|
+
source_id: original_payment&.source_id,
|
109
|
+
source_type: original_payment&.source_type)
|
110
|
+
|
111
|
+
# For now this additional update is overwriting the generated identifier with flow.io payment identifier.
|
112
|
+
# TODO: Check and possibly refactor in Spree 3.0, where the `before_create :set_unique_identifier`
|
113
|
+
# has been removed.
|
114
|
+
payment.update_column(:identifier, response.id)
|
115
|
+
end
|
116
|
+
|
117
|
+
# hard inject Flow as payment method unless defined
|
118
|
+
def profile_ensure_payment_method_is_present!
|
119
|
+
return if @credit_card.payment_method_id
|
120
|
+
|
121
|
+
flow_payment_method = Spree::PaymentMethod.find_by(active: true, type: 'Spree::Gateway::FlowIo')
|
122
|
+
@credit_card.payment_method_id = flow_payment_method.id if flow_payment_method
|
123
|
+
end
|
124
|
+
|
125
|
+
# create payment profile with Flow and tokenize Credit Card
|
126
|
+
def create_flow_cc_profile!
|
127
|
+
return if @credit_card.gateway_customer_profile_id
|
128
|
+
return unless @credit_card.verification_value
|
129
|
+
|
130
|
+
# build credit card hash
|
131
|
+
data = {}
|
132
|
+
data[:number] = @credit_card.number
|
133
|
+
data[:name] = @credit_card.name
|
134
|
+
data[:cvv] = @credit_card.verification_value
|
135
|
+
data[:expiration_year] = @credit_card.year.to_i
|
136
|
+
data[:expiration_month] = @credit_card.month.to_i
|
137
|
+
|
138
|
+
# tokenize with Flow
|
139
|
+
# rescue Io::Flow::V0::HttpClient::ServerError
|
140
|
+
card_form = ::Io::Flow::V0::Models::CardForm.new(data)
|
141
|
+
result = FlowcommerceSpree.client.cards.post(::FlowcommerceSpree::ORGANIZATION, card_form)
|
142
|
+
|
143
|
+
@credit_card.update_column :gateway_customer_profile_id, result.token
|
144
|
+
end
|
145
|
+
|
146
|
+
def load_order(options)
|
147
|
+
order_number = options[:order_id].split('-').first
|
148
|
+
spree_order = Spree::Order.find_by number: order_number
|
149
|
+
::Flow::SimpleGateway.new spree_order
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|