flowcommerce_spree 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +46 -13
  3. data/SPREE_FLOW.md +6 -28
  4. data/app/controllers/concerns/current_zone_loader_decorator.rb +33 -25
  5. data/app/controllers/flowcommerce_spree/inventory_controller.rb +23 -0
  6. data/app/controllers/flowcommerce_spree/orders_controller.rb +20 -0
  7. data/app/controllers/flowcommerce_spree/webhooks_controller.rb +23 -13
  8. data/app/controllers/users/sessions_controller_decorator.rb +28 -0
  9. data/app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb +4 -9
  10. data/app/models/spree/address_decorator.rb +19 -0
  11. data/app/models/spree/calculator/flow_io.rb +61 -0
  12. data/app/models/spree/calculator/shipping/flow_io.rb +40 -0
  13. data/app/models/spree/flow_io_credit_card_decorator.rb +21 -0
  14. data/app/models/spree/flow_io_order_decorator.rb +163 -0
  15. data/app/models/spree/flow_io_variant_decorator.rb +4 -2
  16. data/app/models/spree/gateway/flow_io.rb +153 -0
  17. data/app/models/spree/{credit_card_decorator.rb → payment_capture_event_decorator.rb} +1 -1
  18. data/app/models/spree/promotion_handler/coupon_decorator.rb +1 -1
  19. data/app/models/spree/zones/flow_io_product_zone_decorator.rb +8 -0
  20. data/app/models/tracking/setup_decorator.rb +40 -0
  21. data/app/overrides/spree/admin/order_sidebar_summary_flow_link.rb +13 -0
  22. data/app/overrides/spree/admin/products/order_price_flow_message.rb +9 -0
  23. data/app/serializers/api/v2/order_serializer_decorator.rb +20 -0
  24. data/app/services/flowcommerce_spree/import_experience_items.rb +1 -1
  25. data/app/services/flowcommerce_spree/order_sync.rb +81 -173
  26. data/app/services/flowcommerce_spree/order_updater.rb +78 -0
  27. data/app/services/flowcommerce_spree/webhooks/capture_upserted_v2.rb +76 -0
  28. data/app/services/flowcommerce_spree/webhooks/card_authorization_upserted_v2.rb +66 -0
  29. data/app/services/flowcommerce_spree/webhooks/experience_upserted_v2.rb +25 -0
  30. data/app/services/flowcommerce_spree/webhooks/fraud_status_changed.rb +35 -0
  31. data/app/services/flowcommerce_spree/webhooks/local_item_upserted.rb +40 -0
  32. data/app/views/spree/admin/payments/source_views/_flow_io_gateway.html.erb +21 -0
  33. data/config/rails_best_practices.yml +51 -0
  34. data/config/routes.rb +3 -1
  35. data/db/migrate/20201021755957_add_meta_to_spree_tables.rb +6 -4
  36. data/lib/flow/simple_gateway.rb +0 -36
  37. data/lib/flowcommerce_spree.rb +17 -3
  38. data/lib/flowcommerce_spree/engine.rb +33 -3
  39. data/lib/flowcommerce_spree/experience_service.rb +1 -27
  40. data/lib/flowcommerce_spree/logging_http_client.rb +33 -15
  41. data/lib/flowcommerce_spree/session.rb +17 -32
  42. data/lib/flowcommerce_spree/test_support.rb +7 -0
  43. data/lib/flowcommerce_spree/version.rb +1 -1
  44. data/lib/tasks/flowcommerce_spree.rake +4 -1
  45. metadata +88 -21
  46. data/app/mailers/spree/spree_order_mailer_decorator.rb +0 -24
  47. data/app/models/spree/gateway/spree_flow_gateway.rb +0 -116
  48. data/app/models/spree/line_item_decorator.rb +0 -15
  49. data/app/models/spree/order_decorator.rb +0 -179
  50. data/app/views/spree/order_mailer/confirm_email.html.erb +0 -86
  51. data/app/views/spree/order_mailer/confirm_email.text.erb +0 -38
  52. data/config/initializers/flowcommerce_spree.rb +0 -7
  53. data/lib/flow/error.rb +0 -73
  54. data/lib/flow/pay_pal.rb +0 -25
  55. data/lib/flowcommerce_spree/webhook_service.rb +0 -98
  56. data/lib/simple_csv_writer.rb +0 -44
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 679a3d268ba2e06caff2460bcfd86b671630de034567017f5a9b8f51a6c20d4b
4
- data.tar.gz: 6c95ee74d3783dbb01f1aa1ae9107b386b75de5de9f298d9ea65270ed5a43ffa
3
+ metadata.gz: 6aa92dd937ce7ff2ac430c684e76eaf18f80dc165191b5452407b73a51f6cc59
4
+ data.tar.gz: 83270c61b581abf426a1e19d65c63d6c43ea4c766ba3bf67c3fc334cb234e6f6
5
5
  SHA512:
6
- metadata.gz: af6dba3c9673dbedf2b3d3672c9dc7a09375a7bc12581393ec4173df0cefe2157d2d4022bcf3b0ac0ceeedf87b91fd6e71558d296d1d848d60abac18de9de47a
7
- data.tar.gz: 9ad313a9ab18cb88bb9fe68dff643933bf2b940613ca1a11fd5014c51cfa26bf911443074254c719d393cb1671ef36819b3e292730d677622135bf94a464c83e
6
+ metadata.gz: c45520286feb21871014953ccaa0dd8d18d27520db9b31f05ef062f2e45d3d9b7b4de98807f46d3b4e0ec6acf63ed98e472fe0d37d4290f1b9bcd36ec21363db
7
+ data.tar.gz: 37f630c22db5e978c4325ee6a5029cfe5c45940d817b537fd80f3bb750e63fd50d235796d078b0a6ac028136ab3075703b78030edd3a392c35f87e8bd2327740
data/README.md CHANGED
@@ -11,32 +11,46 @@ All flowcommerce_spree code is located in the ./app and ./lib folders.
11
11
  gem 'flowcommerce_spree', git: 'https://github.com/mejuri-inc/flowcommerce_spree'
12
12
  ```
13
13
 
14
- - If the main application's Rails version is less than 4.2, add also to main application's Gemfile the `activerecord
15
- -postgres-json` gem (the mejuri-inc fork allows using a recent Rake version:
14
+ - If the main application's Rails version is less than 4.2, add also to main application's Gemfile the `activerecord
15
+ -postgres-json` gem (at least version 0.2.3):
16
16
 
17
17
  ```
18
- gem 'activerecord-postgres-json', git: 'https://github.com/mejuri-inc/activerecord-postgres-json'
18
+ gem 'activerecord-postgres-json', '>= 0.2.3'
19
19
  ```
20
-
21
20
 
22
21
  - Run `bundle install`.
23
22
 
24
- - Define this additional ENV variables. You will find them in
25
- [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
26
32
 
27
33
  ```
28
34
  FLOW_TOKEN='SUPERsecretTOKEN' # API_KEY
29
35
  FLOW_ORGANIZATION='spree-app-sandbox'
30
36
  FLOW_BASE_COUNTRY='usa'
37
+ # The path to which the FlowcommerceSpree engine will be mounted (default, if this variable is missing, will be the
38
+ # '/flow' path)
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
31
43
  ```
32
44
 
33
- - The only piece of code that is needed to enable payments with the FlowCommerce engine
45
+ - To enable payments with the FlowCommerce engine, the payment method `flow.io` with `Spree::Gateway::FlowIo` should be
46
+ added in the Spree Admin. This payment method is automatically registered in the gem in an after_initialize Rails
47
+ engine callback:
34
48
 
35
49
  ```
36
- # config/application.rb
50
+ # lib/flowcommerce_spree/engine.rb
37
51
  config.after_initialize do |app|
38
52
  # init Flow payments as an option
39
- app.config.spree.payment_methods << Spree::Gateway::Flow
53
+ app.config.spree.payment_methods << Spree::Gateway::FlowIo
40
54
  end
41
55
  ```
42
56
 
@@ -80,9 +94,11 @@ Decorators are used extensively across the gem to modify or add behaviour of sev
80
94
  properly deal with the precedence in the Ruby ancestor chain, the `class_eval`, `include` and `prepend` methods are
81
95
  being used, depending on the level of modification.
82
96
 
83
- ### Spree::Flow::Gateway
97
+ ### Spree::Gateway::FlowIo
98
+
99
+ Adapter for Spree, that allows using [Flow.io](https://www.flow.io) as payment gateway.
100
+ Flow is PCI compliant payment processor.
84
101
 
85
- Adapter for Spree, that allows using [Flow.io](https://www.flow.io) as payment gateway. Flow is PCI compliant payment processor.
86
102
 
87
103
  ## Gem Maintenance
88
104
 
@@ -125,11 +141,28 @@ by the following command:
125
141
  gem build flowcommerce_spree.gemspec
126
142
  ```
127
143
 
128
- 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
129
- (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
130
148
 
131
149
  ### Pushing a new gem release to RubyGems
132
150
 
133
151
  ```
134
152
  gem push flowcommerce_spree-0.0.1.gem # don't forget to specify the correct version number
135
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
data/SPREE_FLOW.md CHANGED
@@ -2,40 +2,19 @@
2
2
 
3
3
  Integration of Spree with Flow, how it is done.
4
4
 
5
- I plan to be concise as possible, but cover all important topics.
5
+ ## Installation
6
6
 
7
- ## Instalation
8
-
9
- Add the following lines to `./config/application.rb` :
10
-
11
- ```
12
- config.to_prepare do
13
- # add all flow libs
14
- overload = Dir.glob('./app/flow/**/*.rb')
15
- overload.reverse.each { |c| require(c) }
16
- end
17
-
18
- config.after_initialize do |app|
19
- # init Flow payments as an option
20
- app.config.spree.payment_methods << Spree::Gateway::Flow
21
- end
22
- ```
23
-
24
- Additional configuration could be adjusted in the gem's initializer. For example, the following file could be created in the main application:
7
+ Additional configuration could be adjusted in the gem's initializer. For example, the following file could be created
8
+ in the main application, which would add additional attributes of spree_variants to be imported/exported to flow.io:
25
9
 
26
10
  ```
27
11
  # ./config/initializers/flowcommerce_spree.rb
28
12
 
29
- FlowcommerceSpree.configure do |c|
30
- c.experience_associator = FlowcommerceSpree::ExperienceAssociator
31
- end
13
+ FlowcommerceSpree::Config.additional_attributes =
14
+ { spree_variants: { country_of_origin: { import: true, export: :optional },
15
+ customs_description: { import: true, export: :optional, export_name: 'materials' } } }
32
16
  ```
33
17
 
34
- ### Configurable settings
35
-
36
- 1. experience_associator - this attribute could be assigned, if necessary, a service object to perform some
37
- additional association actions when upserting a FlowcommerceSpree::Experience model
38
-
39
18
  ## Things to take into account
40
19
 
41
20
  ActiveMerchant is not supporting sessions and orders, natively. If one wants
@@ -131,4 +110,3 @@ By default Flow Admin (on /admin/flow) is anybody that is Spree admin.
131
110
 
132
111
  This way we provide good frontend info, some integration notes in realtime as opposed to running
133
112
  rake tests to check for integrity of Flow integration.
134
-
@@ -3,29 +3,46 @@
3
3
  CurrentZoneLoader.module_eval do
4
4
  extend ActiveSupport::Concern
5
5
 
6
- def flow_zone # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
6
+ def current_zone
7
+ return @current_zone if defined?(@current_zone)
8
+
9
+ @current_zone = if (session_region_name = session['region']&.[]('name'))
10
+ Spree::Zones::Product.find_by(name: session_region_name, status: 'active')
11
+ end
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
+
18
+ @current_zone ||= Spree::Zones::Product.find_by(name: 'International') ||
19
+ Spree::Zones::Product.new(name: 'International', taxon_ids: [], currencies: %w[USD CAD])
20
+
21
+ current_zone_name = @current_zone.name
22
+ session['region'] = { name: current_zone_name, available_currencies: @current_zone.available_currencies,
23
+ request_iso_code: request_iso_code }
24
+
25
+ Rails.logger.debug("Using product zone: #{current_zone_name}")
26
+ @current_zone
27
+ end
28
+
29
+ def flow_zone
7
30
  return unless Spree::Zones::Product.active
8
31
  .where("meta -> 'flow_data' ->> 'country' = ?",
9
32
  ISO3166::Country[request_iso_code]&.alpha3).exists?
10
33
 
11
- request_ip =
12
- if Rails.env.production?
13
- request.ip
14
- else
15
- Spree::Config[:debug_request_ip_address] || request.ip
16
- # Germany ip: 85.214.132.117, Sweden ip: 62.20.0.196, Moldova ip: 89.41.76.29
17
- end
18
- flow_io_session = FlowcommerceSpree::Session
19
- .new(ip: request_ip, visitor: visitor_id_for_flow_io)
20
- # :create method will issue a request to flow.io. The experience, contained in the
21
- # response, will be available in the session object - flow_io_session.experience
22
- flow_io_session.create
23
- zone = Spree::Zones::Product.active.find_by(name: flow_io_session.experience&.key&.titleize)
24
- session['_f60_session'] = flow_io_session.id if zone
34
+ # This will issue a session creation request to flow.io. The response will contain the Flow Experience key and
35
+ # the session_id
36
+ flow_io_session = FlowcommerceSpree::Session.create(country: request_iso_code, visitor: visitor_id_for_flow_io)
37
+
38
+ if (zone = Spree::Zones::Product.active.find_by(name: flow_io_session.experience&.key&.titleize))
39
+ session['flow_session_id'] = flow_io_session.id
40
+ end
41
+
25
42
  zone
26
43
  end
27
44
 
28
- # composes an unique vistor id for FlowcommerceSpree::Session model
45
+ # composes an unique visitor id for FlowcommerceSpree::Session model
29
46
  def visitor_id_for_flow_io
30
47
  guest_token = cookies.signed[:guest_token]
31
48
  uid = if guest_token
@@ -37,13 +54,4 @@ CurrentZoneLoader.module_eval do
37
54
 
38
55
  "session-#{uid}"
39
56
  end
40
-
41
- def fetch_product_for_zone(product)
42
- Rails.cache.fetch(
43
- "product_zone_#{current_zone.name}_#{product.sku}", expires_in: 1.day,
44
- race_condition_ttl: 10.seconds, compress: true
45
- ) do
46
- Spree::Zones::Product.find_product_for_zone(product, current_zone)
47
- end
48
- end
49
57
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ class InventoryController < ActionController::Base
5
+ def online_stock_availability
6
+ items = params['items'] || []
7
+ response = items.inject([]) { |result, item| result << check_stock(item[:id], item[:qty].to_i) }
8
+ render json: { items: response }, status: :ok
9
+ end
10
+
11
+ private
12
+
13
+ def check_stock(flow_number, quantity)
14
+ variant = Spree::Variant.find_by(sku: flow_number)
15
+ return { id: flow_number, has_inventory: false } unless variant
16
+
17
+ { id: flow_number, has_inventory: variant.available_online?(quantity) }
18
+ rescue StandardError
19
+ Rails.logger.error "[!] FlowcommerceSpree::InventoryController#stock unexpected Error: #{$ERROR_INFO}"
20
+ { id: flow_number, has_inventory: false }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlowcommerceSpree
4
+ class OrdersController < ApplicationController
5
+ wrap_parameters false
6
+
7
+ skip_before_action :setup_tracking, only: :order_completed
8
+
9
+ # proxy enpoint between flow and thankyou page.
10
+ # /flow/order_completed endpoint
11
+ def order_completed
12
+ order = Spree::Order.find_by number: params[:order], guest_token: params[:t]
13
+
14
+ flow_updater = FlowcommerceSpree::OrderUpdater.new(order: order)
15
+ flow_updater.complete_checkout
16
+
17
+ redirect_to "/thankyou?order=#{params[:order]}&t=#{params[:t]}"
18
+ end
19
+ end
20
+ end
@@ -2,24 +2,34 @@
2
2
 
3
3
  module FlowcommerceSpree
4
4
  class WebhooksController < ActionController::Base
5
+ wrap_parameters false
5
6
  respond_to :json
7
+ http_basic_authenticate_with name: FLOW_IO_WEBHOOK_USER, password: FLOW_IO_WEBHOOK_PASSWORD
6
8
 
7
- # forward all incoming requests to Flow WebhookService object
9
+ # forward incoming requests to respective Flow Webhooks Service objects
8
10
  # /flow/event-target endpoint
9
- def handle_flow_web_hook_event
10
- webhook_result = WebhookService.process(params[:webhook])
11
- result = {}
12
- result[:error] = webhook_result.full_messages.join("\n") if webhook_result.errors.any?
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?
13
18
  rescue StandardError => e
14
- 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 }
15
20
  ensure
16
- response_status = if result[:error]
17
- logger.info(result)
18
- :unprocessable_entity
19
- else
20
- :ok
21
- end
22
- 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
23
+ end
24
+
25
+ private
26
+
27
+ def organization_valid?
28
+ org = params[:organization]
29
+ return true if org == FlowcommerceSpree::ORGANIZATION
30
+
31
+ @result = { error: 'InvalidParam', message: "Organization '#{org}' is invalid!" }
32
+ false
23
33
  end
24
34
  end
25
35
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Users
4
+ SessionsController.class_eval do
5
+ # This endpoint is for returning to the FrontEnd the dynamic url to an external checkout, a flow.io url.
6
+ def checkout_url
7
+ flow_session_id = request.headers['flow-session-id']
8
+ return render json: { error: :session_id_missing }, status: 422 if flow_session_id.blank?
9
+
10
+ checkout_token =
11
+ FlowcommerceSpree::OrderSync.new(order: current_order, flow_session_id: flow_session_id).synchronize!
12
+ return render json: { error: :checkout_token_missing }, status: 422 if checkout_token.blank?
13
+
14
+ render json: { checkout_url: "https://checkout.flow.io/tokens/#{checkout_token}" }, status: 200
15
+ end
16
+
17
+ private
18
+
19
+ def add_optional_attrs(session_current)
20
+ session_current['user'] = current_user_attrs if current_user&.spree_api_key?
21
+ session_current['region'] = zone_attrs
22
+
23
+ external_checkout = current_zone.flow_io_active_experience?
24
+ session_current['external_checkout'] = external_checkout
25
+ session_current['flow_session_id'] = session['flow_session_id'] if external_checkout
26
+ end
27
+ end
28
+ end
@@ -12,16 +12,11 @@ module Spree
12
12
  update_meta = @current_order.zone_id ? nil : true
13
13
  @current_order.zone = current_zone
14
14
 
15
- if @current_order.zone&.flow_io_active_experience? && @current_order.flow_io_experience_key.nil?
16
- @current_order.flow_io_experience_from_zone
17
- order_flow_io_session_id = @current_order.flow_data['session_id']
18
- flow_io_session_id = session['_f60_session']
19
- if order_flow_io_session_id.present? && flow_io_session_id.blank?
20
- session['_f60_session'] = order_flow_io_session_id
21
- elsif flow_io_session_id.present?
22
- @current_order.flow_data['session_id'] = flow_io_session_id
15
+ if @current_order.zone&.flow_io_active_experience?
16
+ if @current_order.flow_io_experience_key.nil?
17
+ @current_order.flow_io_experience_from_zone
18
+ update_meta ||= true
23
19
  end
24
- update_meta = true
25
20
  end
26
21
 
27
22
  if @current_order.new_record?
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ Address.class_eval do
5
+ def prepare_from_flow_attributes(address_data)
6
+ self.attributes = {
7
+ first_name: address_data['first'],
8
+ last_name: address_data['last'],
9
+ phone: address_data['phone'],
10
+ address1: address_data['streets'][0],
11
+ address2: address_data['streets'][1],
12
+ zipcode: address_data['postal'],
13
+ city: address_data['city'],
14
+ state_name: address_data['province'],
15
+ country: Spree::Country.find_by(iso3: address_data['country'])
16
+ }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ class Calculator
5
+ class FlowIo < Calculator::DefaultTax
6
+ def self.description
7
+ 'FlowIO Calculator'
8
+ end
9
+
10
+ def compute_shipment_or_line_item(item)
11
+ order = item.order
12
+
13
+ if can_calculate_tax?(order)
14
+ flow_response = get_flow_tax_data(order)
15
+ tax_for_item(item, flow_response)
16
+ else
17
+ prev_tax_amount(item)
18
+ end
19
+ end
20
+ alias compute_shipment compute_shipment_or_line_item
21
+ alias compute_line_item compute_shipment_or_line_item
22
+
23
+ private
24
+
25
+ def prev_tax_amount(item)
26
+ if rate.included_in_price
27
+ item.included_tax_total
28
+ else
29
+ item.additional_tax_total
30
+ end
31
+ end
32
+
33
+ def can_calculate_tax?(order)
34
+ return false if order.flow_data.blank?
35
+ return false if %w[cart address].include?(order.state)
36
+
37
+ true
38
+ end
39
+
40
+ def get_flow_tax_data(order)
41
+ 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)
43
+ end
44
+ flow_io_tax_response
45
+ end
46
+
47
+ def tax_for_item(item, flow_response)
48
+ 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
55
+
56
+ amount = price_components&.find { |el| el.key.value == 'vat_item_price' }&.total&.amount
57
+ amount.present? && amount > 0 ? amount : prev_tax_amount
58
+ end
59
+ end
60
+ end
61
+ end