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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3810faadd82b0d21c0bacaeaa6be61bfe314ddffe4f32a6805c05554c592a745
4
- data.tar.gz: 6d042ed69b193082492ac992ea3d4a9bd962e493ae49026a43c297492013b4ea
3
+ metadata.gz: f47f9a9debf77ea1ca7d10d8a2661a4abac350f3602b98a50686919476038187
4
+ data.tar.gz: '04964f886f5dab774f4e1631a5ab9c0bda612e35599ad4c639dc7dcee8d7396b'
5
5
  SHA512:
6
- metadata.gz: 6bd6d8e87e8f5d8c5d30d9f4366bc0e6d06dc95504d6f8cd3fc8916c752478123e80671ac5da4063a02c6051eb56d95f14ef97d782249a7fa9cb1df4e983829f
7
- data.tar.gz: 260d3b14add605bc114bd561a39f7376a88850d4aea95a98339db5461a9845463a87da1cd845cf68a6b8732a88d7f445a8961fb4f5a0847c282130efeb247083
6
+ metadata.gz: fc5929eff62c6c11b58eed26b580d0cc34c3c51e5a4a81869773a115e5210ac9808e740fb00112de84f5fcc6afc63db404bd97960398bf09d021d588f2624520
7
+ data.tar.gz: 9311543f7e2b18e55326f1826d7240b6315efed2ac7f81c94c60d4c8236f5d4e5381cbb5e7e956880723d76384cf89b23e8306ac8026c14af36ad16344b8bd56
data/README.md CHANGED
@@ -20,8 +20,15 @@ All flowcommerce_spree code is located in the ./app and ./lib folders.
20
20
 
21
21
  - Run `bundle install`.
22
22
 
23
- - Define this additional ENV variables. You will find all of them, except FLOW_MOUNT_PATH in
24
- [Flow console](https://console.flow.io/org_account_name/organization/integrations):
23
+ - Define these additional ENV variables.
24
+ - You will find FLOW_TOKEN, FLOW_ORGANIZATION and FLOW_BASE_COUNTRY in [Flow
25
+ console](https://console.flow.io/org_account_name/organization/integrations)
26
+ - To enable HTTP Basic authentication for securing the FlowcommerceSpree::WebhooksController, prepend
27
+ username:password@ to the hostname in your webhook URL.
28
+ By doing so, the credentials needed for authentication will be sent in the HTTP header.
29
+ For example: https://username:password@www.mywebhookurl.com
30
+ On the main app's backend side, the `username` and `password` values should be defined in the
31
+ FLOW_IO_WEBHOOK_USER and FLOW_IO_WEBHOOK_PASSWORD environment variables
25
32
 
26
33
  ```
27
34
  FLOW_TOKEN='SUPERsecretTOKEN' # API_KEY
@@ -29,7 +36,10 @@ All flowcommerce_spree code is located in the ./app and ./lib folders.
29
36
  FLOW_BASE_COUNTRY='usa'
30
37
  # The path to which the FlowcommerceSpree engine will be mounted (default, if this variable is missing, will be the
31
38
  # '/flow' path)
32
- FLOW_MOUNT_PATH='/flow'
39
+ FLOW_MOUNT_PATH='/flow'
40
+ # The following variables should be set for securing the FlowcommerceSpree::WebhooksControler
41
+ FLOW_IO_WEBHOOK_USER
42
+ FLOW_IO_WEBHOOK_PASSWORD
33
43
  ```
34
44
 
35
45
  - To enable payments with the FlowCommerce engine, the payment method `flow.io` with `Spree::Gateway::FlowIo` should be
@@ -86,7 +96,9 @@ being used, depending on the level of modification.
86
96
 
87
97
  ### Spree::Gateway::FlowIo
88
98
 
89
- Adapter for Spree, that allows using [Flow.io](https://www.flow.io) as payment gateway. Flow is PCI compliant payment processor.
99
+ Adapter for Spree, that allows using [Flow.io](https://www.flow.io) as payment gateway.
100
+ Flow is PCI compliant payment processor.
101
+
90
102
 
91
103
  ## Gem Maintenance
92
104
 
@@ -129,11 +141,28 @@ by the following command:
129
141
  gem build flowcommerce_spree.gemspec
130
142
  ```
131
143
 
132
- Asuming the version was set to `0.0.1`, a `flowcommerce_spree-0.0.1.gem` will be generated at the root of the app
133
- (repo).
144
+ Assuming the version was set to `0.0.1`,
145
+ a `flowcommerce_spree-0.0.1.gem` binary file will be generated at the root of the app (repo).
146
+
147
+ - The binary file shouldn't be added into the `git` tree, it will be pushed into the RubyGems and to the GitHub releases
134
148
 
135
149
  ### Pushing a new gem release to RubyGems
136
150
 
137
151
  ```
138
152
  gem push flowcommerce_spree-0.0.1.gem # don't forget to specify the correct version number
139
153
  ```
154
+
155
+ ### Crafting the new release on GitHub
156
+
157
+ On the [Releases page](https://github.com/mejuri-inc/flowcommerce_spree/releases) push the `Draft a new release` button.
158
+
159
+ The new release editing page opens, on which the following actions could be taken:
160
+
161
+ - Choose the repo branch (default is `main`)
162
+ - Insert a tag version (usually, the tag should correspond to the gem's new version, v0.0.1, for example)
163
+ - the tag will be created by GitHub on the last commit into the chosen branch
164
+ - Fill the release Title and Description
165
+ - Attach the binary file with the generated gem version
166
+ - If the release is not yet ready for production, mark the `This is a pre-release` checkbox
167
+ - Press either the `Publish release`, or the `Save draft button` if you want to publish it later
168
+ - After publishing the release, the the binary gem file will be available on GitHub and could be removed locally
@@ -7,12 +7,14 @@ CurrentZoneLoader.module_eval do
7
7
  return @current_zone if defined?(@current_zone)
8
8
 
9
9
  @current_zone = if (session_region_name = session['region']&.[]('name'))
10
- Spree::Zones::Product.find_by(name: session_region_name)
11
- elsif request_iso_code.present?
12
- @current_zone = flow_zone
13
- @current_zone ||= Spree::Country.find_by(iso: request_iso_code)&.product_zones&.active&.first
10
+ Spree::Zones::Product.find_by(name: session_region_name, status: 'active')
14
11
  end
15
12
 
13
+ @current_zone ||= if request_iso_code.present?
14
+ @current_zone = flow_zone
15
+ @current_zone ||= Spree::Country.find_by(iso: request_iso_code)&.product_zones&.active&.first
16
+ end
17
+
16
18
  @current_zone ||= Spree::Zones::Product.find_by(name: 'International') ||
17
19
  Spree::Zones::Product.new(name: 'International', taxon_ids: [], currencies: %w[USD CAD])
18
20
 
@@ -29,16 +31,9 @@ CurrentZoneLoader.module_eval do
29
31
  .where("meta -> 'flow_data' ->> 'country' = ?",
30
32
  ISO3166::Country[request_iso_code]&.alpha3).exists?
31
33
 
32
- request_ip = if Rails.env.production?
33
- request.ip
34
- else
35
- Spree::Config[:debug_request_ip_address] || request.ip
36
- # Germany ip: 85.214.132.117, Sweden ip: 62.20.0.196, Moldova ip: 89.41.76.29
37
- end
38
-
39
34
  # This will issue a session creation request to flow.io. The response will contain the Flow Experience key and
40
35
  # the session_id
41
- flow_io_session = FlowcommerceSpree::Session.create(ip: request_ip, visitor: visitor_id_for_flow_io)
36
+ flow_io_session = FlowcommerceSpree::Session.create(country: request_iso_code, visitor: visitor_id_for_flow_io)
42
37
 
43
38
  if (zone = Spree::Zones::Product.active.find_by(name: flow_io_session.experience&.key&.titleize))
44
39
  session['flow_session_id'] = flow_io_session.id
@@ -9,7 +9,9 @@ module FlowcommerceSpree
9
9
  # proxy enpoint between flow and thankyou page.
10
10
  # /flow/order_completed endpoint
11
11
  def order_completed
12
- flow_updater = FlowcommerceSpree::OrderUpdater.new(order: current_order)
12
+ order = Spree::Order.find_by number: params[:order], guest_token: params[:t]
13
+
14
+ flow_updater = FlowcommerceSpree::OrderUpdater.new(order: order)
13
15
  flow_updater.complete_checkout
14
16
 
15
17
  redirect_to "/thankyou?order=#{params[:order]}&t=#{params[:t]}"
@@ -4,34 +4,32 @@ module FlowcommerceSpree
4
4
  class WebhooksController < ActionController::Base
5
5
  wrap_parameters false
6
6
  respond_to :json
7
+ http_basic_authenticate_with name: FLOW_IO_WEBHOOK_USER, password: FLOW_IO_WEBHOOK_PASSWORD
7
8
 
8
- # forward all incoming requests to Flow WebhookService object
9
+ # forward incoming requests to respective Flow Webhooks Service objects
9
10
  # /flow/event-target endpoint
10
- def handle_flow_web_hook_event
11
- result = check_organization
12
- if result.blank?
13
- webhook_result = WebhookService.process(params)
14
- result[:error] = webhook_result.full_messages.join("\n") if webhook_result.errors.any?
15
- end
11
+ def handle_flow_io_event
12
+ %i[event_id organization discriminator].each_with_object(params) { |key, obj| obj.require(key) }
13
+ return unless organization_valid?
14
+
15
+ webhook_result = "FlowcommerceSpree::Webhooks::#{params['discriminator'].classify}".constantize.process(params)
16
+ @result = {}
17
+ @result[:error] = webhook_result.full_messages.join("\n") if webhook_result.errors.any?
16
18
  rescue StandardError => e
17
- result = { error: e.class.to_s, message: e.message, backtrace: e.backtrace }
19
+ @result = { error: e.class.to_s, message: e.message, backtrace: e.backtrace }
18
20
  ensure
19
- response_status = if result[:error]
20
- logger.info(result)
21
- :unprocessable_entity
22
- else
23
- :ok
24
- end
25
- render json: result.except(:backtrace), status: response_status
21
+ logger.info(@result) if (error = @result[:error])
22
+ render json: @result.except(:backtrace), status: error ? :unprocessable_entity : :ok
26
23
  end
27
24
 
28
25
  private
29
26
 
30
- def check_organization
27
+ def organization_valid?
31
28
  org = params[:organization]
32
- return {} if org == FlowcommerceSpree::ORGANIZATION
29
+ return true if org == FlowcommerceSpree::ORGANIZATION
33
30
 
34
- { error: 'InvalidParam', message: "Organization '#{org}' is invalid!" }
31
+ @result = { error: 'InvalidParam', message: "Organization '#{org}' is invalid!" }
32
+ false
35
33
  end
36
34
  end
37
35
  end
@@ -4,5 +4,6 @@ module FlowcommerceSpree
4
4
  class Settings < Spree::Preferences::Configuration
5
5
  preference :additional_attributes, :hash, default: {}
6
6
  preference :product_catalog_upload, :hash, default: {}
7
+ preference :notification_setting, :hash, default: {}
7
8
  end
8
9
  end
@@ -11,8 +11,8 @@ module Spree
11
11
  order = item.order
12
12
 
13
13
  if can_calculate_tax?(order)
14
- flow_response = get_flow_tax_data(order)
15
- tax_for_item(item, flow_response)
14
+ get_flow_tax_data(order)
15
+ tax_for_item(item)
16
16
  else
17
17
  prev_tax_amount(item)
18
18
  end
@@ -20,6 +20,13 @@ module Spree
20
20
  alias compute_shipment compute_shipment_or_line_item
21
21
  alias compute_line_item compute_shipment_or_line_item
22
22
 
23
+ def get_tax_rate(taxable)
24
+ order = taxable.class.to_s == 'Spree::Order' ? taxable : taxable.order
25
+ get_flow_tax_data(order) if order.flow_allocations.empty?
26
+ response = order.flow_tax_for_item(taxable.adjustable, 'vat_item_price', rate.included_in_price)
27
+ response.nil? ? 0 : response['rate']&.to_f
28
+ end
29
+
23
30
  private
24
31
 
25
32
  def prev_tax_amount(item)
@@ -39,21 +46,26 @@ module Spree
39
46
 
40
47
  def get_flow_tax_data(order)
41
48
  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)
49
+ response = FlowcommerceSpree.client.orders
50
+ .get_allocations_by_number(FlowcommerceSpree::ORGANIZATION, order.number)
51
+ return nil unless response.present?
52
+
53
+ order.flow_order['allocations'] = response.to_hash
54
+ order.update_column(:meta, order.meta.to_json)
55
+ response
43
56
  end
44
57
  flow_io_tax_response
45
58
  end
46
59
 
47
- def tax_for_item(item, flow_response)
60
+ def tax_for_item(item)
61
+ order = item.order
48
62
  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
63
+ tax_data = order.flow_tax_for_item(item, 'vat_item_price', rate.included_in_price)
64
+ return prev_tax_amount if tax_data.blank?
55
65
 
56
- amount = price_components&.find { |el| el.key.value == 'vat_item_price' }&.total&.amount
66
+ subsidy_data = order.flow_tax_for_item(item, 'vat_subsidy', rate.included_in_price)
67
+ amount = tax_data.dig('total', 'amount')
68
+ amount += subsidy_data.dig('total', 'amount') if subsidy_data.present?
57
69
  amount.present? && amount > 0 ? amount : prev_tax_amount
58
70
  end
59
71
  end
@@ -4,6 +4,9 @@ module Spree
4
4
  class Calculator
5
5
  module Shipping
6
6
  class FlowIo < ShippingCalculator
7
+ preference :lower_boundary, :decimal, default: 100
8
+ preference :charge_default, :decimal, default: 15
9
+
7
10
  def self.description
8
11
  'FlowIO Calculator'
9
12
  end
@@ -16,11 +19,11 @@ module Spree
16
19
  end
17
20
 
18
21
  def default_charge(_country)
19
- 0
22
+ preferred_charge_default
20
23
  end
21
24
 
22
25
  def threshold
23
- 0
26
+ preferred_lower_boundary
24
27
  end
25
28
 
26
29
  private
@@ -23,6 +23,12 @@ module Spree
23
23
  flow_data&.[]('order')
24
24
  end
25
25
 
26
+ def flow_order_with_payments?
27
+ payment = payments.completed.first
28
+
29
+ payment&.payment_method&.type == 'Spree::Gateway::FlowIo'
30
+ end
31
+
26
32
  # accepts line item, usually called from views
27
33
  def flow_line_item_price(line_item, total = false)
28
34
  result = if (order = flow_order)
@@ -42,56 +48,9 @@ module Spree
42
48
  result
43
49
  end
44
50
 
45
- # prepares array of prices that can be easily renderd in templates
46
- def flow_cart_breakdown
47
- prices = []
48
-
49
- price_model = Struct.new(:name, :label)
50
-
51
- if flow_order
52
- # duty, vat, ...
53
- unless flow_order.prices
54
- message = Flow::Error.format_order_message flow_order
55
- raise Flow::Error, message
56
- end
57
-
58
- flow_order.prices.each do |price|
59
- prices.push price_model.new(price['name'], price['label'])
60
- end
61
- else
62
- price_elements =
63
- %i[item_total adjustment_total included_tax_total additional_tax_total tax_total shipment_total promo_total]
64
- price_elements.each do |el|
65
- price = send(el)
66
- if price > 0
67
- label = FlowcommerceSpree::Api.format_default_price price
68
- prices.push price_model.new(el.to_s.humanize.capitalize, label)
69
- end
70
- end
71
-
72
- # discount is applied and we allways show it in default currency
73
- if adjustment_total != 0
74
- formated_discounted_price = FlowcommerceSpree::Api.format_default_price adjustment_total
75
- prices.push price_model.new('Discount', formated_discounted_price)
76
- end
77
- end
78
-
79
- # total
80
- prices.push price_model.new(Spree.t(:total), flow_total)
81
-
82
- prices
83
- end
84
-
85
51
  # shows localized total, if possible. if not, fall back to Spree default
86
52
  def flow_io_total_amount
87
- flow_data&.dig('order', 'total', 'amount')&.to_d
88
- end
89
-
90
- def flow_experience
91
- model = Struct.new(:key)
92
- model.new flow_order.experience.key
93
- rescue StandardError => _e
94
- model.new ENV.fetch('FLOW_BASE_COUNTRY')
53
+ flow_data&.dig('order', 'total', 'amount')&.to_d || 0
95
54
  end
96
55
 
97
56
  def flow_io_experience_key
@@ -135,27 +94,21 @@ module Spree
135
94
  flow_data&.[]('captures')&.each do |c|
136
95
  next if c['status'] != 'succeeded'
137
96
 
138
- captures_sum += c['amount']
97
+ amount = c['amount']
98
+ amount = amount.to_d if amount.is_a?(String)
99
+ captures_sum += amount
139
100
  end
140
101
  captures_sum.to_d
141
102
  end
142
103
 
143
104
  def flow_io_balance_amount
144
- flow_data&.dig('order', 'balance', 'amount')&.to_d
105
+ flow_data&.dig('order', 'balance', 'amount')&.to_d || 0
145
106
  end
146
107
 
147
108
  def flow_io_payments
148
109
  flow_data.dig('order', 'payments')
149
110
  end
150
111
 
151
- def flow_payment_method
152
- if flow_data['payment_type'] == 'paypal'
153
- 'paypal'
154
- else
155
- 'cc' # creait card is default
156
- end
157
- end
158
-
159
112
  def flow_customer_email
160
113
  flow_data.dig('order', 'customer', 'email')
161
114
  end
@@ -205,6 +158,24 @@ module Spree
205
158
  address_attributes
206
159
  end
207
160
 
161
+ def flow_allocations
162
+ return @flow_allocations if @flow_allocations
163
+
164
+ @flow_allocations = flow_order&.[]('allocations')
165
+ end
166
+
167
+ def flow_tax_for_item(item, tax_key, included_in_price = true)
168
+ return {} if flow_allocations.blank?
169
+
170
+ item_details = flow_allocations['details']&.find do |el|
171
+ item.is_a?(Spree::LineItem) ? el['number'] == item.variant.sku : el['key'] == 'shipping'
172
+ end
173
+ return {} if item_details.blank?
174
+
175
+ price_components = included_in_price ? item_details['included'] : item_details['not_included']
176
+ price_components&.find { |el| el['key'] == tax_key }
177
+ end
178
+
208
179
  Spree::Order.include(self) if Spree::Order.included_modules.exclude?(self)
209
180
  end
210
181
  end
@@ -7,6 +7,7 @@ module Spree
7
7
  base.serialize :meta, ActiveRecord::Coders::JSON.new(symbolize_keys: true)
8
8
 
9
9
  base.store_accessor :meta, :flow_data, :zone_ids
10
+ base.after_save :sync_variants_with_flow
10
11
  end
11
12
 
12
13
  def price_in_zone(currency, product_zone)
@@ -86,6 +87,10 @@ module Spree
86
87
  prices
87
88
  end
88
89
 
90
+ def sync_variants_with_flow
91
+ variants_including_master.each(&:sync_product_to_flow)
92
+ end
93
+
89
94
  Spree::Product.prepend(self) if Spree::Product.included_modules.exclude?(self)
90
95
  end
91
96
  end
@@ -49,15 +49,23 @@ module Spree
49
49
  product.update_columns(meta: product.meta.to_json)
50
50
  end
51
51
 
52
+ def sync_flow_info?
53
+ if FlowcommerceSpree::API_KEY.blank? || FlowcommerceSpree::API_KEY == 'test_key'
54
+ return { error: 'Api Keys not configured' }
55
+ end
56
+ return { error: 'Price is 0' } if price == 0
57
+ return { error: 'Country of Origin is empty.' } unless country_of_origin
58
+ end
59
+
52
60
  # upload product variant to Flow's Product Catalog
53
61
  def sync_product_to_flow
54
- # initial Spree seed will fail, so skip unless we have Flow data field
55
- return unless respond_to?(:flow_data)
62
+ error = sync_flow_info?
63
+ return error if error.present?
56
64
 
57
- return if FlowcommerceSpree::API_KEY.blank? || FlowcommerceSpree::API_KEY == 'test_key'
58
-
59
- return { error: 'Price is 0' } if price == 0
65
+ update_flow_data
66
+ end
60
67
 
68
+ def update_flow_data
61
69
  additional_attrs = {}
62
70
  attr_name = nil
63
71
  export_required = false
@@ -82,7 +90,7 @@ module Spree
82
90
  flow_item_sh1 = Digest::SHA1.hexdigest(flow_item.to_json)
83
91
 
84
92
  # skip if sync not needed
85
- return nil if flow_data&.[](:last_sync_sh1) == flow_item_sh1
93
+ return { error: 'Synchronization not needed' } if flow_data&.[](:last_sync_sh1) == flow_item_sh1
86
94
 
87
95
  response = FlowcommerceSpree.client.items.put_by_number(FlowcommerceSpree::ORGANIZATION, sku, flow_item)
88
96
  self.flow_data ||= {}
@@ -91,6 +99,8 @@ module Spree
91
99
  # after successful put, write cache
92
100
  update_column(:meta, meta.to_json)
93
101
 
102
+ FlowcommerceSpree::ImportItemWorker.perform_async(sku)
103
+
94
104
  response
95
105
  rescue Net::OpenTimeout => e
96
106
  { error: e.message }