flowcommerce_spree 0.0.2 → 0.0.7
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.
- checksums.yaml +4 -4
- data/README.md +46 -13
- data/SPREE_FLOW.md +6 -28
- data/app/controllers/concerns/current_zone_loader_decorator.rb +33 -25
- data/app/controllers/flowcommerce_spree/inventory_controller.rb +23 -0
- data/app/controllers/flowcommerce_spree/orders_controller.rb +20 -0
- data/app/controllers/flowcommerce_spree/webhooks_controller.rb +23 -13
- data/app/controllers/users/sessions_controller_decorator.rb +28 -0
- data/app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb +4 -9
- data/app/models/spree/address_decorator.rb +19 -0
- data/app/models/spree/calculator/flow_io.rb +61 -0
- data/app/models/spree/calculator/shipping/flow_io.rb +40 -0
- data/app/models/spree/flow_io_credit_card_decorator.rb +21 -0
- data/app/models/spree/flow_io_order_decorator.rb +163 -0
- data/app/models/spree/flow_io_variant_decorator.rb +4 -2
- data/app/models/spree/gateway/flow_io.rb +153 -0
- data/app/models/spree/{credit_card_decorator.rb → payment_capture_event_decorator.rb} +1 -1
- data/app/models/spree/promotion_handler/coupon_decorator.rb +1 -1
- data/app/models/spree/zones/flow_io_product_zone_decorator.rb +8 -0
- data/app/models/tracking/setup_decorator.rb +40 -0
- data/app/overrides/spree/admin/order_sidebar_summary_flow_link.rb +13 -0
- data/app/overrides/spree/admin/products/order_price_flow_message.rb +9 -0
- data/app/serializers/api/v2/order_serializer_decorator.rb +20 -0
- data/app/services/flowcommerce_spree/import_experience_items.rb +1 -1
- data/app/services/flowcommerce_spree/order_sync.rb +81 -173
- data/app/services/flowcommerce_spree/order_updater.rb +78 -0
- data/app/services/flowcommerce_spree/webhooks/capture_upserted_v2.rb +76 -0
- data/app/services/flowcommerce_spree/webhooks/card_authorization_upserted_v2.rb +66 -0
- data/app/services/flowcommerce_spree/webhooks/experience_upserted_v2.rb +25 -0
- data/app/services/flowcommerce_spree/webhooks/fraud_status_changed.rb +35 -0
- data/app/services/flowcommerce_spree/webhooks/local_item_upserted.rb +40 -0
- data/app/views/spree/admin/payments/source_views/_flow_io_gateway.html.erb +21 -0
- data/config/rails_best_practices.yml +51 -0
- data/config/routes.rb +3 -1
- data/db/migrate/20201021755957_add_meta_to_spree_tables.rb +6 -4
- data/lib/flow/simple_gateway.rb +0 -36
- data/lib/flowcommerce_spree.rb +17 -3
- data/lib/flowcommerce_spree/engine.rb +33 -3
- data/lib/flowcommerce_spree/experience_service.rb +1 -27
- data/lib/flowcommerce_spree/logging_http_client.rb +33 -15
- data/lib/flowcommerce_spree/session.rb +17 -32
- data/lib/flowcommerce_spree/test_support.rb +7 -0
- data/lib/flowcommerce_spree/version.rb +1 -1
- data/lib/tasks/flowcommerce_spree.rake +4 -1
- metadata +88 -21
- data/app/mailers/spree/spree_order_mailer_decorator.rb +0 -24
- data/app/models/spree/gateway/spree_flow_gateway.rb +0 -116
- data/app/models/spree/line_item_decorator.rb +0 -15
- data/app/models/spree/order_decorator.rb +0 -179
- data/app/views/spree/order_mailer/confirm_email.html.erb +0 -86
- data/app/views/spree/order_mailer/confirm_email.text.erb +0 -38
- data/config/initializers/flowcommerce_spree.rb +0 -7
- data/lib/flow/error.rb +0 -73
- data/lib/flow/pay_pal.rb +0 -25
- data/lib/flowcommerce_spree/webhook_service.rb +0 -98
- data/lib/simple_csv_writer.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6aa92dd937ce7ff2ac430c684e76eaf18f80dc165191b5452407b73a51f6cc59
|
4
|
+
data.tar.gz: 83270c61b581abf426a1e19d65c63d6c43ea4c766ba3bf67c3fc334cb234e6f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
15
|
-
-postgres-json` gem (
|
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',
|
18
|
+
gem 'activerecord-postgres-json', '>= 0.2.3'
|
19
19
|
```
|
20
|
-
|
21
20
|
|
22
21
|
- Run `bundle install`.
|
23
22
|
|
24
|
-
- Define
|
25
|
-
[Flow
|
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
|
-
-
|
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
|
-
#
|
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::
|
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::
|
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
|
-
|
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
|
-
|
5
|
+
## Installation
|
6
6
|
|
7
|
-
|
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.
|
30
|
-
|
31
|
-
|
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
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
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
|
9
|
+
# forward incoming requests to respective Flow Webhooks Service objects
|
8
10
|
# /flow/event-target endpoint
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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?
|
16
|
-
@current_order.
|
17
|
-
|
18
|
-
|
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
|