flowcommerce_spree 0.0.4 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
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: []