flowcommerce_spree 0.0.4 → 0.0.9

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -6
  3. data/app/controllers/concerns/current_zone_loader_decorator.rb +7 -12
  4. data/app/controllers/flowcommerce_spree/orders_controller.rb +3 -1
  5. data/app/controllers/flowcommerce_spree/webhooks_controller.rb +16 -18
  6. data/app/models/flowcommerce_spree/settings.rb +1 -0
  7. data/app/models/spree/calculator/flow_io.rb +23 -11
  8. data/app/models/spree/calculator/shipping/flow_io.rb +5 -2
  9. data/app/models/spree/flow_io_order_decorator.rb +29 -58
  10. data/app/models/spree/flow_io_product_decorator.rb +5 -0
  11. data/app/models/spree/flow_io_variant_decorator.rb +16 -6
  12. data/app/models/spree/gateway/flow_io.rb +22 -11
  13. data/app/models/spree/zones/flow_io_product_zone_decorator.rb +4 -0
  14. data/app/overrides/spree/admin/order_sidebar_summary_flow_link.rb +13 -0
  15. data/app/overrides/spree/admin/products/order_price_flow_message.rb +9 -0
  16. data/app/services/flowcommerce_spree/import_experience_items.rb +0 -20
  17. data/app/services/flowcommerce_spree/import_item.rb +45 -0
  18. data/app/services/flowcommerce_spree/order_sync.rb +39 -82
  19. data/app/services/flowcommerce_spree/order_updater.rb +3 -1
  20. data/app/services/flowcommerce_spree/webhooks/capture_upserted_v2.rb +76 -0
  21. data/app/services/flowcommerce_spree/webhooks/card_authorization_upserted_v2.rb +66 -0
  22. data/app/services/flowcommerce_spree/webhooks/experience_upserted_v2.rb +25 -0
  23. data/app/services/flowcommerce_spree/webhooks/fraud_status_changed.rb +35 -0
  24. data/app/services/flowcommerce_spree/webhooks/local_item_upserted.rb +40 -0
  25. data/app/workers/flowcommerce_spree/import_item_worker.rb +24 -0
  26. data/config/routes.rb +1 -1
  27. data/lib/flowcommerce_spree.rb +3 -1
  28. data/lib/flowcommerce_spree/engine.rb +5 -0
  29. data/lib/flowcommerce_spree/experience_service.rb +1 -27
  30. data/lib/flowcommerce_spree/session.rb +5 -7
  31. data/lib/flowcommerce_spree/version.rb +1 -1
  32. data/lib/tasks/flowcommerce_spree.rake +4 -1
  33. metadata +74 -16
  34. data/app/mailers/spree/spree_order_mailer_decorator.rb +0 -24
  35. data/app/views/spree/order_mailer/confirm_email.html.erb +0 -86
  36. data/app/views/spree/order_mailer/confirm_email.text.erb +0 -38
  37. data/lib/flow/error.rb +0 -73
  38. data/lib/flow/pay_pal.rb +0 -25
  39. data/lib/flowcommerce_spree/webhook_service.rb +0 -154
  40. data/lib/simple_csv_writer.rb +0 -44
@@ -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
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ class ImportItemWorker
5
+ include Sidekiq::Worker
6
+ sidekiq_options retry: 3, queue: :flow_io
7
+
8
+ sidekiq_retries_exhausted do |message, exception|
9
+ Rails.logger.warn("[!] FlowcommerceSpree::ImportItemWorker max attempts reached: #{message} - #{exception}")
10
+ notification_setting = FlowcommerceSpree::Config.notification_setting
11
+ return unless notification_setting[:slack].present?
12
+
13
+ slack_message = "[#{Rails.env}] #{message}"
14
+ Slack_client.chat_postMessage(channel: notification_setting[:slack][:channel], text: slack_message)
15
+ end
16
+
17
+ def perform(variant_sku)
18
+ variant = Spree::Variant.find_by sku: variant_sku
19
+ return unless variant
20
+
21
+ FlowcommerceSpree::ImportItem.run(variant)
22
+ end
23
+ end
24
+ 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
@@ -5,16 +5,14 @@ module FlowcommerceSpree
5
5
  class Session
6
6
  attr_accessor :session, :localized, :visitor
7
7
 
8
- def self.create(ip:, visitor:, experience: nil)
9
- instance = new(ip: ip, visitor: visitor, experience: experience)
8
+ def self.create(country:, visitor:, experience: nil)
9
+ instance = new(country: country, visitor: visitor, experience: experience)
10
10
  instance.create
11
11
  instance
12
12
  end
13
13
 
14
- def initialize(ip:, visitor:, experience: nil)
15
- ip = '127.0.0.1' if ip == '::1'
16
-
17
- @ip = ip
14
+ def initialize(country:, visitor:, experience: nil)
15
+ @country = country
18
16
  @visitor = visitor
19
17
  @experience = experience
20
18
  end
@@ -22,7 +20,7 @@ module FlowcommerceSpree
22
20
  # create session without or with experience (the latter is useful for creating a new session with the order's
23
21
  # experience on refreshing the checkout_token)
24
22
  def create
25
- data = { ip: @ip,
23
+ data = { country: @country,
26
24
  visit: { id: @visitor,
27
25
  expires_at: (Time.now + 30.minutes).iso8601 } }
28
26
  data[:experience] = @experience if @experience
@@ -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.9'
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.9
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-06-30 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,7 +208,6 @@ 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
158
213
  - app/models/spree/calculator/flow_io.rb
@@ -170,27 +225,32 @@ files:
170
225
  - app/models/spree/zone_decorator.rb
171
226
  - app/models/spree/zones/flow_io_product_zone_decorator.rb
172
227
  - app/models/tracking/setup_decorator.rb
228
+ - app/overrides/spree/admin/order_sidebar_summary_flow_link.rb
229
+ - app/overrides/spree/admin/products/order_price_flow_message.rb
173
230
  - app/serializers/api/v2/order_serializer_decorator.rb
174
231
  - app/services/flowcommerce_spree/import_experience_items.rb
175
232
  - app/services/flowcommerce_spree/import_experiences.rb
233
+ - app/services/flowcommerce_spree/import_item.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
247
+ - app/workers/flowcommerce_spree/import_item_worker.rb
186
248
  - config/rails_best_practices.yml
187
249
  - config/routes.rb
188
250
  - db/migrate/20201021160159_add_type_and_meta_to_spree_zone.rb
189
251
  - db/migrate/20201021755957_add_meta_to_spree_tables.rb
190
252
  - db/migrate/20201022173210_add_zone_type_to_spree_zone_members.rb
191
253
  - db/migrate/20201022174252_add_kind_to_zone.rb
192
- - lib/flow/error.rb
193
- - lib/flow/pay_pal.rb
194
254
  - lib/flow/simple_gateway.rb
195
255
  - lib/flowcommerce_spree.rb
196
256
  - lib/flowcommerce_spree/api.rb
@@ -202,14 +262,12 @@ files:
202
262
  - lib/flowcommerce_spree/session.rb
203
263
  - lib/flowcommerce_spree/test_support.rb
204
264
  - lib/flowcommerce_spree/version.rb
205
- - lib/flowcommerce_spree/webhook_service.rb
206
- - lib/simple_csv_writer.rb
207
265
  - lib/tasks/flowcommerce_spree.rake
208
266
  homepage: https://github.com/mejuri-inc/flowcommerce_spree
209
267
  licenses:
210
268
  - MIT
211
269
  metadata: {}
212
- post_install_message:
270
+ post_install_message:
213
271
  rdoc_options: []
214
272
  require_paths:
215
273
  - lib
@@ -225,7 +283,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
283
  version: '0'
226
284
  requirements: []
227
285
  rubygems_version: 3.0.8
228
- signing_key:
286
+ signing_key:
229
287
  specification_version: 4
230
288
  summary: Integration of Spree with Flow API
231
289
  test_files: []