flowcommerce_spree 0.0.4 → 0.0.5

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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -6
  3. data/app/controllers/flowcommerce_spree/webhooks_controller.rb +16 -18
  4. data/app/models/spree/app_configuration_decorator.rb +7 -0
  5. data/app/models/spree/calculator/shipping/flow_io.rb +5 -2
  6. data/app/models/spree/flow_io_order_decorator.rb +11 -58
  7. data/app/models/spree/flow_io_variant_decorator.rb +2 -0
  8. data/app/overrides/spree/admin/order_sidebar_summary_flow_link.rb +13 -0
  9. data/app/overrides/spree/admin/products/order_price_flow_message.rb +9 -0
  10. data/app/services/flowcommerce_spree/order_sync.rb +38 -81
  11. data/app/services/flowcommerce_spree/webhooks/capture_upserted_v2.rb +76 -0
  12. data/app/services/flowcommerce_spree/webhooks/card_authorization_upserted_v2.rb +66 -0
  13. data/app/services/flowcommerce_spree/webhooks/experience_upserted_v2.rb +25 -0
  14. data/app/services/flowcommerce_spree/webhooks/fraud_status_changed.rb +35 -0
  15. data/app/services/flowcommerce_spree/webhooks/local_item_upserted.rb +40 -0
  16. data/config/routes.rb +1 -1
  17. data/lib/flowcommerce_spree.rb +3 -1
  18. data/lib/flowcommerce_spree/engine.rb +5 -0
  19. data/lib/flowcommerce_spree/experience_service.rb +1 -27
  20. data/lib/flowcommerce_spree/version.rb +1 -1
  21. data/lib/tasks/flowcommerce_spree.rake +4 -1
  22. metadata +74 -17
  23. data/app/mailers/spree/spree_order_mailer_decorator.rb +0 -24
  24. data/app/views/spree/order_mailer/confirm_email.html.erb +0 -86
  25. data/app/views/spree/order_mailer/confirm_email.text.erb +0 -38
  26. data/lib/flow/error.rb +0 -73
  27. data/lib/flow/pay_pal.rb +0 -25
  28. data/lib/flowcommerce_spree/webhook_service.rb +0 -154
  29. data/lib/simple_csv_writer.rb +0 -44
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ module Webhooks
5
+ class CaptureUpsertedV2
6
+ attr_reader :errors
7
+ alias full_messages errors
8
+
9
+ def self.process(data)
10
+ new(data).process
11
+ end
12
+
13
+ def initialize(data)
14
+ @data = data
15
+ @errors = []
16
+ end
17
+
18
+ def process
19
+ errors << { message: 'Capture param missing' } && (return self) unless (capture = @data['capture']&.to_hash)
20
+
21
+ order_number = capture.dig('authorization', 'order', 'number')
22
+ errors << { message: 'Order number param missing' } && (return self) unless order_number
23
+
24
+ if (order = Spree::Order.find_by(number: order_number))
25
+ upsert_order_captures(order, capture)
26
+ payments = order.flow_io_payments
27
+ map_payment_captures_to_spree(order, payments) if payments.present?
28
+ order
29
+ else
30
+ errors << { message: "Order #{order_number} not found" }
31
+ self
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def upsert_order_captures(order, capture)
38
+ order.flow_data ||= {}
39
+ order.flow_data['captures'] ||= []
40
+ order_captures = order.flow_data['captures']
41
+ order_captures.delete_if { |c| c['id'] == capture['id'] }
42
+ order_captures << capture
43
+ order.update_column(:meta, order.meta.to_json)
44
+ end
45
+
46
+ def map_payment_captures_to_spree(order, payments)
47
+ order.flow_data['captures']&.each do |c|
48
+ next unless (payment = captured_payment(payments, c))
49
+
50
+ payment.capture_events.create!(amount: c['amount'], meta: { 'flow_data' => { 'id' => c['id'] } })
51
+ return if payment.completed? || payment.capture_events.sum(:amount) < payment.amount
52
+
53
+ payment.complete
54
+ end
55
+
56
+ return if order.completed?
57
+ return unless order.flow_io_captures_sum >= order.flow_io_total_amount && order.flow_io_balance_amount <= 0
58
+
59
+ FlowcommerceSpree::OrderUpdater.new(order: order).finalize_order
60
+ end
61
+
62
+ def captured_payment(flow_order_payments, capture)
63
+ return unless capture['status'] == 'succeeded'
64
+
65
+ auth = capture.dig('authorization', 'id')
66
+ return unless flow_order_payments&.find { |p| p['reference'] == auth }
67
+
68
+ return unless (payment = Spree::Payment.find_by(response_code: auth))
69
+
70
+ return if Spree::PaymentCaptureEvent.where("meta -> 'flow_data' ->> 'id' = ?", capture['id']).exists?
71
+
72
+ payment
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ module Webhooks
5
+ class CardAuthorizationUpsertedV2
6
+ attr_reader :errors
7
+ alias full_messages errors
8
+
9
+ def self.process(data)
10
+ new(data).process
11
+ end
12
+
13
+ def initialize(data)
14
+ @data = data['authorization']&.to_hash
15
+ @data&.[]('method')&.delete('images')
16
+ @errors = []
17
+ end
18
+
19
+ def process
20
+ errors << { message: 'Authorization param missing' } && (return self) unless @data
21
+
22
+ errors << { message: 'Card param missing' } && (return self) unless (flow_io_card = @data.delete('card'))
23
+
24
+ if (order_number = @data.dig('order', 'number'))
25
+ if (order = Spree::Order.find_by(number: order_number))
26
+ card = upsert_card(flow_io_card, order)
27
+
28
+ order.payments.where(response_code: @data['id'])
29
+ .update_all(source_id: card.id, source_type: 'Spree::CreditCard')
30
+
31
+ return card
32
+ else
33
+ errors << { message: "Order #{order_number} not found" }
34
+ end
35
+ else
36
+ errors << { message: 'Order number param missing' }
37
+ end
38
+
39
+ self
40
+ end
41
+
42
+ private
43
+
44
+ def upsert_card(flow_io_card, order)
45
+ flow_io_card_expiration = flow_io_card.delete('expiration')
46
+
47
+ card = Spree::CreditCard.find_or_initialize_by(month: flow_io_card_expiration['month'].to_s,
48
+ year: flow_io_card_expiration['year'].to_s,
49
+ cc_type: flow_io_card.delete('type'),
50
+ last_digits: flow_io_card.delete('last4'),
51
+ name: flow_io_card.delete('name'),
52
+ user_id: order.user&.id)
53
+ card.flow_data ||= {}
54
+ if card.new_record?
55
+ card.flow_data.merge!(flow_io_card.except('discriminator'))
56
+ card.imported = true
57
+ end
58
+
59
+ card.push_authorization(@data.except('discriminator'))
60
+ card.new_record? ? card.save : card.update_column(:meta, card.meta.to_json)
61
+
62
+ card
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ module Webhooks
5
+ class ExperienceUpsertedV2
6
+ attr_accessor :errors
7
+ alias full_messages errors
8
+
9
+ def self.process(data, opts = {})
10
+ new(data, opts).process
11
+ end
12
+
13
+ def initialize(data, opts = {})
14
+ @data = data
15
+ @opts = opts
16
+ @errors = []
17
+ end
18
+
19
+ def process
20
+ experience = @data['experience']
21
+ Spree::Zones::Product.find_or_initialize_by(name: experience['key'].titleize).store_flow_io_data(experience)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ module Webhooks
5
+ class FraudStatusChanged
6
+ attr_accessor :errors
7
+ alias full_messages errors
8
+
9
+ def self.process(data, opts = {})
10
+ new(data, opts).process
11
+ end
12
+
13
+ def initialize(data, opts = {})
14
+ @data = data
15
+ @opts = opts
16
+ @errors = []
17
+ end
18
+
19
+ def process
20
+ order_number = @data.dig('order', 'number')
21
+ errors << { message: 'Order number param missing' } && (return self) unless order_number
22
+
23
+ order = Spree::Order.find_by(number: order_number)
24
+ errors << { message: "Order #{order_number} not found" } && (return self) unless order
25
+
26
+ if @data['status'] == 'declined'
27
+ order.update_columns(fraudulent: true)
28
+ order.cancel!
29
+ end
30
+
31
+ order
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ module Webhooks
5
+ class LocalItemUpserted
6
+ attr_accessor :errors
7
+ alias full_messages errors
8
+
9
+ def self.process(data, opts = {})
10
+ new(data, opts).process
11
+ end
12
+
13
+ def initialize(data, opts = {})
14
+ @data = data
15
+ @opts = opts
16
+ @errors = []
17
+ end
18
+
19
+ def process
20
+ errors << { message: 'Local item param missing' } && (return self) unless (local_item = @data['local_item'])
21
+
22
+ errors << { message: 'SKU param missing' } && (return self) unless (flow_sku = local_item.dig('item', 'number'))
23
+
24
+ if (variant = Spree::Variant.find_by(sku: flow_sku))
25
+ variant.add_flow_io_experience_data(
26
+ local_item.dig('experience', 'key'),
27
+ 'prices' => [local_item.dig('pricing', 'price')], 'status' => local_item['status']
28
+ )
29
+
30
+ variant.update_column(:meta, variant.meta.to_json)
31
+ return variant
32
+ else
33
+ errors << { message: "Variant with sku [#{flow_sku}] not found!" }
34
+ end
35
+
36
+ self
37
+ end
38
+ end
39
+ end
40
+ end
data/config/routes.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  FlowcommerceSpree::Engine.routes.draw do
4
- post '/event-target', to: 'webhooks#handle_flow_web_hook_event'
4
+ post '/event-target', to: 'webhooks#handle_flow_io_event'
5
5
  get '/order-completed', to: 'orders#order_completed'
6
6
  post '/online-stock-availability', to: 'inventory#online_stock_availability'
7
7
  end
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'activerecord-postgres-json'
4
+ require 'active_model_serializers'
3
5
  require 'flowcommerce'
4
6
  require 'flowcommerce_spree/api'
5
7
  require 'flowcommerce_spree/refresher'
6
8
  require 'flowcommerce_spree/engine'
7
9
  require 'flowcommerce_spree/logging_http_client'
8
10
  require 'flowcommerce_spree/logging_http_handler'
9
- require 'flowcommerce_spree/webhook_service'
10
11
  require 'flowcommerce_spree/session'
11
12
  require 'flow/simple_gateway'
13
+ require 'oj'
12
14
 
13
15
  module FlowcommerceSpree
14
16
  API_KEY = ENV.fetch('FLOW_TOKEN', 'test_key')
@@ -9,6 +9,8 @@ module FlowcommerceSpree
9
9
  FlowcommerceSpree::ORGANIZATION = ENV.fetch('FLOW_ORGANIZATION', 'flow.io')
10
10
  FlowcommerceSpree::BASE_COUNTRY = ENV.fetch('FLOW_BASE_COUNTRY', 'USA')
11
11
  FlowcommerceSpree::API_KEY = ENV.fetch('FLOW_TOKEN', 'test_key')
12
+ FlowcommerceSpree::FLOW_IO_WEBHOOK_USER = ENV.fetch('FLOW_IO_WEBHOOK_USER', 'test_user')
13
+ FlowcommerceSpree::FLOW_IO_WEBHOOK_PASSWORD = ENV.fetch('FLOW_IO_WEBHOOK_PASSWORD', 'test_password')
12
14
 
13
15
  FlowcommerceSpree::Config = FlowcommerceSpree::Settings.new
14
16
  end
@@ -40,6 +42,9 @@ module FlowcommerceSpree
40
42
  Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')).sort.each do |c|
41
43
  Rails.configuration.cache_classes ? require(c) : load(c)
42
44
  end
45
+ Dir.glob(File.join(File.dirname(__FILE__), '../app/overrides/*.rb')).sort.each do |c|
46
+ Rails.configuration.cache_classes ? require(c) : load(c)
47
+ end
43
48
  end
44
49
 
45
50
  config.to_prepare(&method(:activate).to_proc)
@@ -22,18 +22,6 @@ module FlowcommerceSpree
22
22
  nil
23
23
  end
24
24
 
25
- def get_by_subcatalog_id(subcatalog_id)
26
- fetch_from_flow.each do |experince|
27
- return experince if experince.subcatalog.id == subcatalog_id
28
- end
29
-
30
- nil
31
- end
32
-
33
- def compact
34
- all.map { |exp| [exp.country, exp.key, exp.name] }
35
- end
36
-
37
25
  def default
38
26
  FlowcommerceSpree::ExperienceService
39
27
  .all.select { |exp| exp.key.downcase == ENV.fetch('FLOW_BASE_COUNTRY').downcase }.first
@@ -42,24 +30,10 @@ module FlowcommerceSpree
42
30
  private
43
31
 
44
32
  def fetch_from_flow
45
- # return cached_experinces if cache_valid?
46
-
47
- experiences = FlowcommerceSpree.client.experiences.get ORGANIZATION
33
+ FlowcommerceSpree.client.experiences.get ORGANIZATION
48
34
 
49
35
  # work with active axperiences only
50
36
  # experiences = experiences.select { |it| it.status.value == 'active' }
51
-
52
- # @cache = [experiences, Time.now]
53
- experiences
54
- end
55
-
56
- def cache_valid?
57
- # cache experinces in worker memory for 1 minute
58
- @cache && @cache[1] > Time.now.ago(1.minute)
59
- end
60
-
61
- def cached_experinces
62
- @cache[0]
63
37
  end
64
38
  end
65
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FlowcommerceSpree
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end
@@ -47,8 +47,11 @@ namespace :flowcommerce_spree do
47
47
 
48
48
  while current_page == 0 || !variants.empty?
49
49
  current_page += 1
50
- variants = Spree::Variant.order('updated_at desc').page(current_page).per(100).all
51
50
 
51
+ products = Spree::Product.where.not(country_of_origin: nil)
52
+ .order('updated_at desc')
53
+ .page(current_page).per(50).includes(:variants_including_master)
54
+ variants = products.map(&:variants_including_master).flatten
52
55
  variants.each do |variant|
53
56
  total_sum += 1
54
57
  result = variant.sync_product_to_flow
metadata CHANGED
@@ -1,16 +1,44 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flowcommerce_spree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aurel Branzeanu
8
8
  - Sebastian De Luca
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-03-16 00:00:00.000000000 Z
12
+ date: 2021-04-07 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_model_serializers
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.10.2
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 0.10.2
28
+ - !ruby/object:Gem::Dependency
29
+ name: activerecord-postgres-json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.2.3
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 0.2.3
14
42
  - !ruby/object:Gem::Dependency
15
43
  name: colorize
16
44
  requirement: !ruby/object:Gem::Requirement
@@ -77,16 +105,16 @@ dependencies:
77
105
  name: oj
78
106
  requirement: !ruby/object:Gem::Requirement
79
107
  requirements:
80
- - - ">="
108
+ - - '='
81
109
  - !ruby/object:Gem::Version
82
- version: '0'
110
+ version: 3.7.12
83
111
  type: :runtime
84
112
  prerelease: false
85
113
  version_requirements: !ruby/object:Gem::Requirement
86
114
  requirements:
87
- - - ">="
115
+ - - '='
88
116
  - !ruby/object:Gem::Version
89
- version: '0'
117
+ version: 3.7.12
90
118
  - !ruby/object:Gem::Dependency
91
119
  name: pg
92
120
  requirement: !ruby/object:Gem::Requirement
@@ -115,6 +143,20 @@ dependencies:
115
143
  - - "~>"
116
144
  - !ruby/object:Gem::Version
117
145
  version: 2.3.0
146
+ - !ruby/object:Gem::Dependency
147
+ name: factory_bot_rails
148
+ requirement: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '4.0'
153
+ type: :development
154
+ prerelease: false
155
+ version_requirements: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '4.0'
118
160
  - !ruby/object:Gem::Dependency
119
161
  name: github_changelog_generator
120
162
  requirement: !ruby/object:Gem::Requirement
@@ -129,6 +171,20 @@ dependencies:
129
171
  - - ">="
130
172
  - !ruby/object:Gem::Version
131
173
  version: '0'
174
+ - !ruby/object:Gem::Dependency
175
+ name: rspec-rails
176
+ requirement: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '3.5'
181
+ type: :development
182
+ prerelease: false
183
+ version_requirements: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '3.5'
132
188
  description: Integration of popular Rails/Spree store framework with e-commerce Flow
133
189
  API
134
190
  email:
@@ -152,9 +208,9 @@ files:
152
208
  - app/helpers/flowcommerce_spree/application_helper.rb
153
209
  - app/helpers/spree/admin/orders_helper_decorator.rb
154
210
  - app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb
155
- - app/mailers/spree/spree_order_mailer_decorator.rb
156
211
  - app/models/flowcommerce_spree/settings.rb
157
212
  - app/models/spree/address_decorator.rb
213
+ - app/models/spree/app_configuration_decorator.rb
158
214
  - app/models/spree/calculator/flow_io.rb
159
215
  - app/models/spree/calculator/shipping/flow_io.rb
160
216
  - app/models/spree/flow_io_credit_card_decorator.rb
@@ -170,27 +226,30 @@ files:
170
226
  - app/models/spree/zone_decorator.rb
171
227
  - app/models/spree/zones/flow_io_product_zone_decorator.rb
172
228
  - app/models/tracking/setup_decorator.rb
229
+ - app/overrides/spree/admin/order_sidebar_summary_flow_link.rb
230
+ - app/overrides/spree/admin/products/order_price_flow_message.rb
173
231
  - app/serializers/api/v2/order_serializer_decorator.rb
174
232
  - app/services/flowcommerce_spree/import_experience_items.rb
175
233
  - app/services/flowcommerce_spree/import_experiences.rb
176
234
  - app/services/flowcommerce_spree/order_sync.rb
177
235
  - app/services/flowcommerce_spree/order_updater.rb
236
+ - app/services/flowcommerce_spree/webhooks/capture_upserted_v2.rb
237
+ - app/services/flowcommerce_spree/webhooks/card_authorization_upserted_v2.rb
238
+ - app/services/flowcommerce_spree/webhooks/experience_upserted_v2.rb
239
+ - app/services/flowcommerce_spree/webhooks/fraud_status_changed.rb
240
+ - app/services/flowcommerce_spree/webhooks/local_item_upserted.rb
178
241
  - app/views/layouts/flowcommerce_spree/application.html.erb
179
242
  - app/views/spree/admin/payments/index.html.erb
180
243
  - app/views/spree/admin/payments/source_views/_flow_io_gateway.html.erb
181
244
  - app/views/spree/admin/promotions/edit.html.erb
182
245
  - app/views/spree/admin/shared/_order_summary.html.erb
183
246
  - app/views/spree/admin/shared/_order_summary_flow.html.erb
184
- - app/views/spree/order_mailer/confirm_email.html.erb
185
- - app/views/spree/order_mailer/confirm_email.text.erb
186
247
  - config/rails_best_practices.yml
187
248
  - config/routes.rb
188
249
  - db/migrate/20201021160159_add_type_and_meta_to_spree_zone.rb
189
250
  - db/migrate/20201021755957_add_meta_to_spree_tables.rb
190
251
  - db/migrate/20201022173210_add_zone_type_to_spree_zone_members.rb
191
252
  - db/migrate/20201022174252_add_kind_to_zone.rb
192
- - lib/flow/error.rb
193
- - lib/flow/pay_pal.rb
194
253
  - lib/flow/simple_gateway.rb
195
254
  - lib/flowcommerce_spree.rb
196
255
  - lib/flowcommerce_spree/api.rb
@@ -202,14 +261,12 @@ files:
202
261
  - lib/flowcommerce_spree/session.rb
203
262
  - lib/flowcommerce_spree/test_support.rb
204
263
  - lib/flowcommerce_spree/version.rb
205
- - lib/flowcommerce_spree/webhook_service.rb
206
- - lib/simple_csv_writer.rb
207
264
  - lib/tasks/flowcommerce_spree.rake
208
265
  homepage: https://github.com/mejuri-inc/flowcommerce_spree
209
266
  licenses:
210
267
  - MIT
211
268
  metadata: {}
212
- post_install_message:
269
+ post_install_message:
213
270
  rdoc_options: []
214
271
  require_paths:
215
272
  - lib
@@ -224,8 +281,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
281
  - !ruby/object:Gem::Version
225
282
  version: '0'
226
283
  requirements: []
227
- rubygems_version: 3.0.8
228
- signing_key:
284
+ rubygems_version: 3.1.2
285
+ signing_key:
229
286
  specification_version: 4
230
287
  summary: Integration of Spree with Flow API
231
288
  test_files: []