flowcommerce_spree 0.0.2 → 0.0.3
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 +13 -9
- data/SPREE_FLOW.md +6 -28
- data/app/controllers/concerns/current_zone_loader_decorator.rb +37 -23
- data/app/controllers/flowcommerce_spree/webhooks_controller.rb +15 -3
- data/app/controllers/users/sessions_controller_decorator.rb +11 -0
- data/app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb +19 -8
- data/app/models/spree/address_decorator.rb +19 -0
- data/app/models/spree/calculator/flow_io.rb +61 -0
- data/app/models/spree/calculator/shipping/flow_io.rb +37 -0
- data/app/models/spree/flow_io_variant_decorator.rb +2 -2
- data/app/models/spree/gateway/{spree_flow_gateway.rb → flow_io.rb} +2 -2
- data/app/models/spree/order_decorator.rb +75 -10
- data/app/models/spree/promotion_handler/coupon_decorator.rb +1 -1
- data/app/models/spree/zones/flow_io_product_zone_decorator.rb +4 -0
- data/app/models/tracking/setup_decorator.rb +40 -0
- data/app/services/flowcommerce_spree/order_sync.rb +137 -57
- data/config/rails_best_practices.yml +51 -0
- data/lib/flowcommerce_spree.rb +12 -2
- data/lib/flowcommerce_spree/engine.rb +28 -3
- data/lib/flowcommerce_spree/logging_http_client.rb +11 -9
- data/lib/flowcommerce_spree/session.rb +16 -11
- data/lib/flowcommerce_spree/test_support.rb +7 -0
- data/lib/flowcommerce_spree/version.rb +1 -1
- data/lib/flowcommerce_spree/webhook_service.rb +126 -40
- metadata +24 -4
- data/config/initializers/flowcommerce_spree.rb +0 -7
@@ -14,15 +14,12 @@ module FlowcommerceSpree
|
|
14
14
|
# original_read = client.read_timeout
|
15
15
|
|
16
16
|
start_time = Time.now.utc.round(10)
|
17
|
-
@logger.info "start #{request.method} #{request.path}"
|
18
|
-
@logger.info "body: #{request.instance_variable_get(:@header)}"
|
19
|
-
@logger.info "body: #{request.body}"
|
20
17
|
|
21
|
-
if request.path.start_with?('/organizations')
|
18
|
+
# if request.path.start_with?('/organizations')
|
22
19
|
# Contrived example to show how client settings can be adjusted
|
23
20
|
# client.open_timeout = 60
|
24
21
|
# client.read_timeout = 60
|
25
|
-
end
|
22
|
+
# end
|
26
23
|
|
27
24
|
begin
|
28
25
|
response = super
|
@@ -32,10 +29,15 @@ module FlowcommerceSpree
|
|
32
29
|
# client.open_timeout = original_open
|
33
30
|
# client.read_timeout = original_read
|
34
31
|
|
35
|
-
|
36
|
-
|
37
|
-
@logger.info
|
38
|
-
|
32
|
+
duration = ((Time.now.utc.round(10) - start_time) * 1000).round(0)
|
33
|
+
|
34
|
+
@logger.info(
|
35
|
+
"Started #{request.method} #{request.path}\n"\
|
36
|
+
"headers: #{request.instance_variable_get(:@header)}\nbody: #{request.body}\n"\
|
37
|
+
"response: #{response&.force_encoding('utf-8')}\n"\
|
38
|
+
"Completed #{request.method} #{request.path} #{duration} ms\n"
|
39
|
+
)
|
40
|
+
|
39
41
|
@logger.info "Error: #{e.inspect}" if e
|
40
42
|
end
|
41
43
|
end
|
@@ -5,25 +5,34 @@ module FlowcommerceSpree
|
|
5
5
|
class Session
|
6
6
|
attr_accessor :session, :localized, :visitor
|
7
7
|
|
8
|
-
def
|
8
|
+
def self.create(ip:, visitor:, experience: nil)
|
9
|
+
instance = new(ip: ip, visitor: visitor, experience: experience)
|
10
|
+
instance.create
|
11
|
+
instance
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(ip:, visitor:, experience: nil)
|
9
15
|
ip = '127.0.0.1' if ip == '::1'
|
10
16
|
|
11
17
|
@ip = ip
|
12
18
|
@visitor = visitor
|
19
|
+
@experience = experience
|
13
20
|
end
|
14
21
|
|
15
|
-
# create session with
|
22
|
+
# create session without or with experience (the latter is useful for creating a new session with the order's
|
23
|
+
# experience on refreshing the checkout_token)
|
16
24
|
def create
|
17
25
|
data = { ip: @ip,
|
18
26
|
visit: { id: @visitor,
|
19
27
|
expires_at: (Time.now + 30.minutes).iso8601 } }
|
28
|
+
data[:experience] = @experience if @experience
|
20
29
|
|
21
30
|
session_model = ::Io::Flow::V0::Models::SessionForm.new data
|
22
31
|
@session = FlowCommerce.instance(http_handler: LoggingHttpHandler.new)
|
23
32
|
.sessions.post_organizations_by_organization(ORGANIZATION, session_model)
|
24
33
|
end
|
25
34
|
|
26
|
-
# if we want to
|
35
|
+
# if we want to manually switch to specific country or experience
|
27
36
|
def update(data)
|
28
37
|
@session = FlowCommerce.instance.sessions.put_by_session(@session.id,
|
29
38
|
::Io::Flow::V0::Models::SessionPutForm.new(data))
|
@@ -34,6 +43,10 @@ module FlowcommerceSpree
|
|
34
43
|
@session.local&.experience
|
35
44
|
end
|
36
45
|
|
46
|
+
def expires_at
|
47
|
+
@session.visit.expires_at
|
48
|
+
end
|
49
|
+
|
37
50
|
def local
|
38
51
|
@session.local
|
39
52
|
end
|
@@ -42,14 +55,6 @@ module FlowcommerceSpree
|
|
42
55
|
@session.id
|
43
56
|
end
|
44
57
|
|
45
|
-
def localized?
|
46
|
-
# use flow if we are not in default country
|
47
|
-
return false unless local
|
48
|
-
return false if @localized.class == FalseClass
|
49
|
-
|
50
|
-
local.country.iso_3166_3 != ENV.fetch('FLOW_BASE_COUNTRY').upcase
|
51
|
-
end
|
52
|
-
|
53
58
|
# because we do not get full experience from session, we have to get from exp list
|
54
59
|
def delivered_duty_options
|
55
60
|
return nil unless experience
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module FlowcommerceSpree
|
4
4
|
# communicates with flow api, responds to webhook events
|
5
5
|
class WebhookService
|
6
|
-
attr_accessor :errors
|
6
|
+
attr_accessor :errors
|
7
7
|
alias full_messages errors
|
8
8
|
|
9
9
|
def self.process(data, opts = {})
|
@@ -17,72 +17,158 @@ module FlowcommerceSpree
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def process
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
else
|
24
|
-
|
25
|
-
hook_method = "hook_#{discriminator}"
|
26
|
-
# If hook processing method registered an error, a self.object of WebhookService with this error will be
|
27
|
-
# returned, else an ActiveRecord object will be returned
|
28
|
-
return __send__(hook_method) if respond_to?(hook_method, true)
|
29
|
-
|
30
|
-
errors << { message: "No hook for #{discriminator}" }
|
31
|
-
end
|
20
|
+
discriminator = @data['discriminator']
|
21
|
+
hook_method = "hook_#{discriminator}"
|
22
|
+
# If hook processing method registered an error, a self.object of WebhookService with this error will be
|
23
|
+
# returned, else an ActiveRecord object will be returned
|
24
|
+
return __send__(hook_method) if respond_to?(hook_method, true)
|
32
25
|
|
26
|
+
errors << { message: "No hook for #{discriminator}" }
|
33
27
|
self
|
34
28
|
end
|
35
29
|
|
36
30
|
private
|
37
31
|
|
32
|
+
def hook_capture_upserted_v2
|
33
|
+
capture = @data['capture']
|
34
|
+
order_number = capture.dig('authorization', 'order', 'number')
|
35
|
+
if (order = Spree::Order.find_by(number: order_number))
|
36
|
+
order.flow_data['captures'] ||= []
|
37
|
+
order_captures = order.flow_data['captures']
|
38
|
+
order_captures.delete_if do |c|
|
39
|
+
c['id'] == capture['id']
|
40
|
+
end
|
41
|
+
order_captures << capture
|
42
|
+
|
43
|
+
order.update_column(:meta, order.meta.to_json)
|
44
|
+
order
|
45
|
+
else
|
46
|
+
errors << { message: "Order #{order_number} not found" }
|
47
|
+
self
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
38
51
|
def hook_experience_upserted_v2
|
39
52
|
experience = @data['experience']
|
40
53
|
Spree::Zones::Product.find_or_initialize_by(name: experience['key'].titleize).store_flow_io_data(experience)
|
41
54
|
end
|
42
55
|
|
56
|
+
def hook_fraud_status_changed
|
57
|
+
if (order_number = @data.dig('order', 'number'))
|
58
|
+
if @data['status'] == 'declined'
|
59
|
+
if (order = Spree::Order.find_by(number: order_number))
|
60
|
+
order.update_columns(fraudulent: true)
|
61
|
+
order.cancel!
|
62
|
+
return order
|
63
|
+
else
|
64
|
+
errors << { message: "Order #{order_number} not found" }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
else
|
68
|
+
errors << { message: 'Order number param missing' }
|
69
|
+
end
|
70
|
+
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
43
74
|
def hook_local_item_upserted
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
75
|
+
errors << { message: 'Local item param missing' } && (return self) unless (local_item = @data['local_item'])
|
76
|
+
|
77
|
+
errors << { message: 'SKU param missing' } && (return self) unless (flow_sku = local_item.dig('item', 'number'))
|
78
|
+
|
79
|
+
if (variant = Spree::Variant.find_by(sku: flow_sku))
|
80
|
+
variant.add_flow_io_experience_data(
|
81
|
+
local_item.dig('experience', 'key'),
|
82
|
+
'prices' => [local_item.dig('pricing', 'price')], 'status' => local_item['status']
|
83
|
+
)
|
84
|
+
|
85
|
+
variant.update_column(:meta, variant.meta.to_json)
|
86
|
+
return variant
|
87
|
+
else
|
88
|
+
errors << { message: "Variant with sku [#{flow_sku}] not found!" }
|
89
|
+
end
|
90
|
+
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
def hook_order_placed_v2
|
95
|
+
order_placed = @data['order_placed']
|
96
|
+
flow_order = order_placed['order']
|
97
|
+
flow_allocation = order_placed['allocation']
|
98
|
+
|
99
|
+
errors << { message: 'Order number param missing' } && (return self) unless (order_number = flow_order['number'])
|
100
|
+
|
101
|
+
if (order = Spree::Order.find_by(number: order_number))
|
102
|
+
order.flow_data['order'] = flow_order.to_hash
|
103
|
+
order.flow_data['allocations'] = flow_allocation.to_hash
|
104
|
+
order_flow_data = order.flow_data['order']
|
105
|
+
attrs_to_update = { meta: order.meta.to_json }
|
106
|
+
flow_data_submitted = order_flow_data['submitted_at'].present?
|
107
|
+
if flow_data_submitted && !order.complete?
|
108
|
+
if order_flow_data['payments'].present? && (order_flow_data.dig('balance', 'amount')&.to_i == 0)
|
109
|
+
attrs_to_update[:state] = 'complete'
|
110
|
+
attrs_to_update[:payment_state] = 'paid'
|
111
|
+
attrs_to_update[:completed_at] = Time.zone.now.utc
|
112
|
+
attrs_to_update[:email] = order.flow_customer_email
|
54
113
|
else
|
55
|
-
|
114
|
+
attrs_to_update[:state] = 'confirmed'
|
56
115
|
end
|
57
|
-
else
|
58
|
-
errors << { message: 'SKU param missing' }
|
59
116
|
end
|
117
|
+
|
118
|
+
attrs_to_update.merge!(order.prepare_flow_addresses) if order.complete? || attrs_to_update[:state] == 'complete'
|
119
|
+
|
120
|
+
if flow_data_submitted
|
121
|
+
order.create_proposed_shipments
|
122
|
+
order.shipment.update_amounts
|
123
|
+
order.line_items.each(&:store_ets)
|
124
|
+
end
|
125
|
+
|
126
|
+
order.update_columns(attrs_to_update)
|
127
|
+
|
128
|
+
# TODO: To be refactored once we have the capture_upserted_v2 webhook configured
|
129
|
+
if flow_data_submitted
|
130
|
+
order.create_tax_charge!
|
131
|
+
order.finalize!
|
132
|
+
order.update_totals
|
133
|
+
order.save
|
134
|
+
end
|
135
|
+
|
136
|
+
return order
|
60
137
|
else
|
61
|
-
errors << { message:
|
138
|
+
errors << { message: "Order #{order_number} not found" }
|
62
139
|
end
|
63
140
|
|
64
141
|
self
|
65
142
|
end
|
66
143
|
|
67
144
|
def hook_order_upserted_v2
|
68
|
-
errors << { message: 'Order param missing' } unless (
|
145
|
+
errors << { message: 'Order param missing' } && (return self) unless (flow_order = @data['order'])
|
146
|
+
|
147
|
+
errors << { message: 'Order number param missing' } && (return self) unless (order_number = flow_order['number'])
|
69
148
|
|
70
|
-
if
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
149
|
+
if (order = Spree::Order.find_by(number: order_number))
|
150
|
+
order.flow_data['order'] = flow_order.to_hash
|
151
|
+
order_flow_data = order.flow_data['order']
|
152
|
+
attrs_to_update = { meta: order.meta.to_json }
|
153
|
+
flow_data_submitted = order_flow_data['submitted_at'].present?
|
154
|
+
if flow_data_submitted && !order.complete?
|
155
|
+
if order_flow_data['payments'].present? && (order_flow_data.dig('balance', 'amount')&.to_i == 0)
|
75
156
|
attrs_to_update[:state] = 'complete'
|
76
|
-
attrs_to_update[:
|
157
|
+
attrs_to_update[:payment_state] = 'paid'
|
158
|
+
attrs_to_update[:completed_at] = Time.zone.now.utc
|
159
|
+
attrs_to_update[:email] = order.flow_customer_email
|
160
|
+
else
|
161
|
+
attrs_to_update[:state] = 'confirmed'
|
77
162
|
end
|
78
|
-
|
79
|
-
order.update_columns(attrs_to_update)
|
80
|
-
return order
|
81
|
-
else
|
82
|
-
errors << { message: "Order #{order_number} not found" }
|
83
163
|
end
|
164
|
+
|
165
|
+
attrs_to_update.merge!(order.prepare_flow_addresses) if order.complete? || attrs_to_update[:state] == 'complete'
|
166
|
+
|
167
|
+
order.update_columns(attrs_to_update)
|
168
|
+
order.create_tax_charge! if flow_data_submitted
|
169
|
+
return order
|
84
170
|
else
|
85
|
-
errors << { message:
|
171
|
+
errors << { message: "Order #{order_number} not found" }
|
86
172
|
end
|
87
173
|
|
88
174
|
self
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flowcommerce_spree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aurel Branzeanu
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-02-
|
12
|
+
date: 2021-02-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: colorize
|
@@ -101,6 +101,20 @@ dependencies:
|
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0.21'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: request_store
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
type: :runtime
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
104
118
|
- !ruby/object:Gem::Dependency
|
105
119
|
name: spree_backend
|
106
120
|
requirement: !ruby/object:Gem::Requirement
|
@@ -146,15 +160,19 @@ files:
|
|
146
160
|
- app/assets/stylesheets/flowcommerce_spree/application.css
|
147
161
|
- app/controllers/concerns/current_zone_loader_decorator.rb
|
148
162
|
- app/controllers/flowcommerce_spree/webhooks_controller.rb
|
163
|
+
- app/controllers/users/sessions_controller_decorator.rb
|
149
164
|
- app/helpers/flowcommerce_spree/application_helper.rb
|
150
165
|
- app/helpers/spree/admin/orders_helper_decorator.rb
|
151
166
|
- app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb
|
152
167
|
- app/mailers/spree/spree_order_mailer_decorator.rb
|
153
168
|
- app/models/flowcommerce_spree/settings.rb
|
169
|
+
- app/models/spree/address_decorator.rb
|
170
|
+
- app/models/spree/calculator/flow_io.rb
|
171
|
+
- app/models/spree/calculator/shipping/flow_io.rb
|
154
172
|
- app/models/spree/credit_card_decorator.rb
|
155
173
|
- app/models/spree/flow_io_product_decorator.rb
|
156
174
|
- app/models/spree/flow_io_variant_decorator.rb
|
157
|
-
- app/models/spree/gateway/
|
175
|
+
- app/models/spree/gateway/flow_io.rb
|
158
176
|
- app/models/spree/line_item_decorator.rb
|
159
177
|
- app/models/spree/order_decorator.rb
|
160
178
|
- app/models/spree/promotion_decorator.rb
|
@@ -163,6 +181,7 @@ files:
|
|
163
181
|
- app/models/spree/taxon_decorator.rb
|
164
182
|
- app/models/spree/zone_decorator.rb
|
165
183
|
- app/models/spree/zones/flow_io_product_zone_decorator.rb
|
184
|
+
- app/models/tracking/setup_decorator.rb
|
166
185
|
- app/services/flowcommerce_spree/import_experience_items.rb
|
167
186
|
- app/services/flowcommerce_spree/import_experiences.rb
|
168
187
|
- app/services/flowcommerce_spree/order_sync.rb
|
@@ -173,7 +192,7 @@ files:
|
|
173
192
|
- app/views/spree/admin/shared/_order_summary_flow.html.erb
|
174
193
|
- app/views/spree/order_mailer/confirm_email.html.erb
|
175
194
|
- app/views/spree/order_mailer/confirm_email.text.erb
|
176
|
-
- config/
|
195
|
+
- config/rails_best_practices.yml
|
177
196
|
- config/routes.rb
|
178
197
|
- db/migrate/20201021160159_add_type_and_meta_to_spree_zone.rb
|
179
198
|
- db/migrate/20201021755957_add_meta_to_spree_tables.rb
|
@@ -190,6 +209,7 @@ files:
|
|
190
209
|
- lib/flowcommerce_spree/logging_http_handler.rb
|
191
210
|
- lib/flowcommerce_spree/refresher.rb
|
192
211
|
- lib/flowcommerce_spree/session.rb
|
212
|
+
- lib/flowcommerce_spree/test_support.rb
|
193
213
|
- lib/flowcommerce_spree/version.rb
|
194
214
|
- lib/flowcommerce_spree/webhook_service.rb
|
195
215
|
- lib/simple_csv_writer.rb
|