flowcommerce_spree 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +91 -0
- data/Rakefile +33 -0
- data/SPREE_FLOW.md +134 -0
- data/app/assets/javascripts/flowcommerce_spree/application.js +13 -0
- data/app/assets/stylesheets/flowcommerce_spree/application.css +15 -0
- data/app/controllers/concerns/current_zone_loader_decorator.rb +49 -0
- data/app/controllers/flowcommerce_spree/webhooks_controller.rb +25 -0
- data/app/helpers/flowcommerce_spree/application_helper.rb +6 -0
- data/app/helpers/spree/admin/orders_helper_decorator.rb +17 -0
- data/app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb +53 -0
- data/app/mailers/spree/spree_order_mailer_decorator.rb +24 -0
- data/app/models/flowcommerce_spree/settings.rb +8 -0
- data/app/models/spree/credit_card_decorator.rb +9 -0
- data/app/models/spree/flow_io_product_decorator.rb +91 -0
- data/app/models/spree/flow_io_variant_decorator.rb +205 -0
- data/app/models/spree/gateway/spree_flow_gateway.rb +116 -0
- data/app/models/spree/line_item_decorator.rb +15 -0
- data/app/models/spree/order_decorator.rb +179 -0
- data/app/models/spree/promotion_decorator.rb +10 -0
- data/app/models/spree/promotion_handler/coupon_decorator.rb +30 -0
- data/app/models/spree/spree_user_decorator.rb +15 -0
- data/app/models/spree/taxon_decorator.rb +37 -0
- data/app/models/spree/zone_decorator.rb +7 -0
- data/app/models/spree/zones/flow_io_product_zone_decorator.rb +55 -0
- data/app/services/flowcommerce_spree/import_experience_items.rb +76 -0
- data/app/services/flowcommerce_spree/import_experiences.rb +37 -0
- data/app/services/flowcommerce_spree/order_sync.rb +231 -0
- data/app/views/layouts/flowcommerce_spree/application.html.erb +14 -0
- data/app/views/spree/admin/payments/index.html.erb +28 -0
- data/app/views/spree/admin/promotions/edit.html.erb +57 -0
- data/app/views/spree/admin/shared/_order_summary.html.erb +44 -0
- data/app/views/spree/admin/shared/_order_summary_flow.html.erb +13 -0
- data/app/views/spree/order_mailer/confirm_email.html.erb +86 -0
- data/app/views/spree/order_mailer/confirm_email.text.erb +38 -0
- data/config/initializers/flowcommerce_spree.rb +7 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20201021160159_add_type_and_meta_to_spree_zone.rb +23 -0
- data/db/migrate/20201021755957_add_meta_to_spree_tables.rb +17 -0
- data/db/migrate/20201022173210_add_zone_type_to_spree_zone_members.rb +24 -0
- data/db/migrate/20201022174252_add_kind_to_zone.rb +22 -0
- data/lib/flow/error.rb +73 -0
- data/lib/flow/pay_pal.rb +25 -0
- data/lib/flow/simple_gateway.rb +115 -0
- data/lib/flowcommerce_spree.rb +31 -0
- data/lib/flowcommerce_spree/api.rb +48 -0
- data/lib/flowcommerce_spree/engine.rb +27 -0
- data/lib/flowcommerce_spree/experience_service.rb +65 -0
- data/lib/flowcommerce_spree/logging_http_client.rb +43 -0
- data/lib/flowcommerce_spree/logging_http_handler.rb +15 -0
- data/lib/flowcommerce_spree/refresher.rb +81 -0
- data/lib/flowcommerce_spree/session.rb +71 -0
- data/lib/flowcommerce_spree/version.rb +5 -0
- data/lib/flowcommerce_spree/webhook_service.rb +98 -0
- data/lib/simple_csv_writer.rb +44 -0
- data/lib/tasks/flowcommerce_spree.rake +289 -0
- metadata +220 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6893ddfb8f021ff6400c0bbe31fc6b2c532886892730a1c9097d172944a8eca8
|
4
|
+
data.tar.gz: 9d3a1b190708053a5ad664588abe553617cf07a02ce6fb8f8b2b9d8d17b393a7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 531a87c9a666b3057d16983c3e6168492ac124112a881821891e3bb2174f7e5589785301e023348f3bb06ef2ea105961f20a6a2aaa884e9845e92896973586d7
|
7
|
+
data.tar.gz: c84a3cb370744c3313b04cdc513d38d70ea0aaa01e7e09470bdf768f77d41fdb0c4bb9df240bbe4fec58adc4068b96d64fa538a315d73e8a361a1f718ecc6b46
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2020 Aurel Branzeanu
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
<img src="https://i.imgur.com/tov8bTw.png" alt="flowcommerce_spree" style="float:right">
|
2
|
+
|
3
|
+
# Flow.io < - > Spree adapter
|
4
|
+
|
5
|
+
All flowcommerce_spree code is located in the ./app and ./lib folders.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
- Add the gem to main application's Gemfile:
|
9
|
+
|
10
|
+
```
|
11
|
+
gem 'flowcommerce_spree', git: 'https://github.com/mejuri-inc/flowcommerce_spree'
|
12
|
+
```
|
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:
|
16
|
+
|
17
|
+
```
|
18
|
+
gem 'activerecord-postgres-json', git: 'https://github.com/mejuri-inc/activerecord-postgres-json'
|
19
|
+
```
|
20
|
+
|
21
|
+
|
22
|
+
- Run `bundle install`.
|
23
|
+
|
24
|
+
- Define this additional ENV variables. You will find them in
|
25
|
+
[Flow console](https://console.flow.io/org_account_name/organization/integrations):
|
26
|
+
|
27
|
+
```
|
28
|
+
FLOW_TOKEN='SUPERsecretTOKEN' # API_KEY
|
29
|
+
FLOW_ORGANIZATION='spree-app-sandbox'
|
30
|
+
FLOW_BASE_COUNTRY='usa'
|
31
|
+
```
|
32
|
+
|
33
|
+
- The only piece of code that is needed to enable payments with the FlowCommerce engine
|
34
|
+
|
35
|
+
```
|
36
|
+
# config/application.rb
|
37
|
+
config.after_initialize do |app|
|
38
|
+
# init Flow payments as an option
|
39
|
+
app.config.spree.payment_methods << Spree::Gateway::Flow
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
- To see and optionally invoke the list of FlowCommerce tasks, run `bundle exec rake flowcommerce_spree:list_tasks
|
44
|
+
`. Any task from the list could be invoked, typing at the `Type the task number to be invoked:` prompt the task
|
45
|
+
number, or from a terminal prompt, in the main application's root folder, running `bundle exec rake {task_name}`
|
46
|
+
|
47
|
+
- Run the `flowcommerce_spree:install:migrations` task to copy the DB migrations' file into the main application's
|
48
|
+
`db/migrate` folder.
|
49
|
+
|
50
|
+
- Run `bundle exec rake db:migrate SCOPE=flowcommerce_spree
|
51
|
+
` from a terminal prompt. This will add an `meta` jsonb column to the Spree::CreditCard, Spree::Product,
|
52
|
+
Spree::Variant, Spree::Order, Spree::Promotion models' DB tables, if there is not yet such a column defined.
|
53
|
+
|
54
|
+
- If the main application's Rails version is less than 4.2, add the JSON serializer for the `meta` column to the
|
55
|
+
affected models' decorators (Spree::CreditCard, Spree::Product, Spree::Variant, Spree::Order, Spree::Promotion models):
|
56
|
+
|
57
|
+
`serialize :flow_data, ActiveRecord::Coders::JSON.new(symbolize_keys: true)`
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
## Flow API specific
|
62
|
+
|
63
|
+
Classes that begin with Flow are responsible for communicating with flow API.
|
64
|
+
|
65
|
+
### Flow
|
66
|
+
|
67
|
+
Helper class that offers low level flow api access and few helper methods.
|
68
|
+
|
69
|
+
### FlowcommerceSpree::ExperienceService
|
70
|
+
|
71
|
+
Responsible for selecting current experience. You have to define available experiences in flow console.
|
72
|
+
|
73
|
+
### Flow::Order
|
74
|
+
|
75
|
+
Maintain and synchronizes Spree::Order with Flow API.
|
76
|
+
|
77
|
+
### Flow::Session
|
78
|
+
|
79
|
+
Every shop user has a session. This class helps in creating and maintaining session with Flow.
|
80
|
+
|
81
|
+
## Decorators
|
82
|
+
|
83
|
+
Decorators are found in ./app/flow/decorators folders and they decorate Spree models with Flow specific methods.
|
84
|
+
|
85
|
+
All methods are prefixed with ```flow_```.
|
86
|
+
|
87
|
+
## Helper lib
|
88
|
+
|
89
|
+
### Spree::Flow::Gateway
|
90
|
+
|
91
|
+
Adapter for Spree, that allows using [Flow.io](https://www.flow.io) as payment gateway. Flow is PCI compliant payment processor.
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rdoc/task'
|
10
|
+
|
11
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
12
|
+
rdoc.rdoc_dir = 'rdoc'
|
13
|
+
rdoc.title = 'FlowcommerceSpree'
|
14
|
+
rdoc.options << '--line-numbers'
|
15
|
+
rdoc.rdoc_files.include('README.rdoc')
|
16
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
|
+
end
|
18
|
+
|
19
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
20
|
+
load 'rails/tasks/engine.rake'
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
task default: :test
|
data/SPREE_FLOW.md
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
# Flow, ActiveMerchant and Spree integration
|
2
|
+
|
3
|
+
Integration of Spree with Flow, how it is done.
|
4
|
+
|
5
|
+
I plan to be concise as possible, but cover all important topics.
|
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:
|
25
|
+
|
26
|
+
```
|
27
|
+
# ./config/initializers/flowcommerce_spree.rb
|
28
|
+
|
29
|
+
FlowcommerceSpree.configure do |c|
|
30
|
+
c.experience_associator = FlowcommerceSpree::ExperienceAssociator
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
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
|
+
## Things to take into account
|
40
|
+
|
41
|
+
ActiveMerchant is not supporting sessions and orders, natively. If one wants
|
42
|
+
to maintain sessions and orders in Flow, you have to do it outside the ActiveMerchant
|
43
|
+
terminology which focuses around purchases, voids and refunds.
|
44
|
+
|
45
|
+
Another thing to have in mind is that Spree can't work with ActiveMerchant directly, it has to have
|
46
|
+
an adapter. Adapter can be "stupid" and light, and can forward all the "heavy lifting" to ActiveMerchant gem
|
47
|
+
but it can also have all the logic localy.
|
48
|
+
|
49
|
+
In http://guides.spreecommerce.org/developer/payments.html at the bottom of the page Spree authors say
|
50
|
+
|
51
|
+
"better_spree_paypal_express and spree-adyen are good examples of standalone
|
52
|
+
custom gateways. No dependency on spree_gateway or activemerchant required."
|
53
|
+
|
54
|
+
Reading that we can see this is even considered good approach. For us, this is a possibility
|
55
|
+
but we consume ActiveMerchatFlow gem.
|
56
|
+
|
57
|
+
## ActiveMerchant gem into more detail
|
58
|
+
|
59
|
+
https://github.com/flowcommerce/active_merchant
|
60
|
+
|
61
|
+
Sopporst stanard public ActiveMerchant actions which are
|
62
|
+
purchase, authorize, capture, void, store and refund.
|
63
|
+
|
64
|
+
It depends on following gems
|
65
|
+
|
66
|
+
* flowcommerce - api calls
|
67
|
+
* flow-reference - we use currency validations
|
68
|
+
|
69
|
+
It is not aware of Spree or any other shopping lib or framework.
|
70
|
+
|
71
|
+
### ActiveMerchant::Flow supported actions in detail
|
72
|
+
|
73
|
+
* purchase - shortcut for authorize and then capture
|
74
|
+
* authorize - authorize the cc and funds.
|
75
|
+
* capture - capture the funds
|
76
|
+
* void - cancel the transaction
|
77
|
+
* store - store credit card (gets credit card flow token)
|
78
|
+
* refund - refund the funds
|
79
|
+
|
80
|
+
## Spree Implementation in more detail
|
81
|
+
|
82
|
+
Not present as standalone gem, yet. I will do that once we agree on implementation details.
|
83
|
+
|
84
|
+
From product list to purchase, complete chain v1
|
85
|
+
|
86
|
+
1. customer has to prepare data, migrate db and connect to Flow. In general
|
87
|
+
* create experiences in Flow console, add tiers, shipping methods, etc.
|
88
|
+
* add flow_data (jsonb) fields to this models
|
89
|
+
* Spree::Variant - we cache localized product prices
|
90
|
+
* Spree::Order - we cache flow order state details, shipping method
|
91
|
+
* create and sync product catalog via rake tasks
|
92
|
+
1. now site users can browse prooducts and add them to cart.
|
93
|
+
1. when user comes to shop, FlowSession is created
|
94
|
+
1. once product is in cart
|
95
|
+
* spree order is created and linked to Experience that we get from FlowSession
|
96
|
+
* it is captured and synced with flow, realtime
|
97
|
+
* we do this all the time because we want to have 100% accurate prices.
|
98
|
+
Product prices that are shown in cart come directly from Flow API.
|
99
|
+
* in checkout, when customer address is added or shipping method defined,
|
100
|
+
all is synced with flow order.
|
101
|
+
* when order is complete, we trigger flow-cc-authorize or flow-cc-capture directly
|
102
|
+
on Spree::Order object instance. This is good because all gateway actions
|
103
|
+
are functions of the order object anyway.
|
104
|
+
* flow-cc-authorize or flow-cc-capture use ActiveMerchantFlow to execute this actions
|
105
|
+
* ActiveMerchantFlow included flow-reference gem
|
106
|
+
|
107
|
+
## What can be better
|
108
|
+
|
109
|
+
We need a way to access the order in Rails. Access it after it is created in
|
110
|
+
controller but before it hits the render.
|
111
|
+
Current implementation is -> "overload" ApplicationController render
|
112
|
+
If we detect @spree_order object or debug flags, we react.
|
113
|
+
|
114
|
+
* good - elegant solution, all need code is in one file in few lines of code
|
115
|
+
* bad - somehow intrusive, we overload render, somw people will not like that.
|
116
|
+
* alternatives: gem that allows before_render bethod, call explicitly when needed
|
117
|
+
|
118
|
+
## Aditional notes - view and frontend
|
119
|
+
|
120
|
+
I see many Spree merchant gems carry frontend code, js, coffe, views etc.
|
121
|
+
I thing that this is bad practise and that shop frontend has to be 100% customer code.
|
122
|
+
|
123
|
+
What I did not see but thing is great idea is to have custom light Flow admin present at
|
124
|
+
|
125
|
+
/admin/flow
|
126
|
+
|
127
|
+
that will ease the way of working with Flow. Code can be made to be Rails 4 and Rails 5 compatibile.
|
128
|
+
Part of that is allready done as can be seen here [Flow admin screenshot](https://i.imgur.com/FXbPrwK.png)
|
129
|
+
|
130
|
+
By default Flow Admin (on /admin/flow) is anybody that is Spree admin.
|
131
|
+
|
132
|
+
This way we provide good frontend info, some integration notes in realtime as opposed to running
|
133
|
+
rake tests to check for integrity of Flow integration.
|
134
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any styles
|
10
|
+
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
|
11
|
+
* file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
CurrentZoneLoader.module_eval do
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def flow_zone # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
7
|
+
return unless Spree::Zones::Product.active
|
8
|
+
.where("meta -> 'flow_data' ->> 'country' = ?",
|
9
|
+
ISO3166::Country[request_iso_code]&.alpha3).exists?
|
10
|
+
|
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
|
25
|
+
zone
|
26
|
+
end
|
27
|
+
|
28
|
+
# composes an unique vistor id for FlowcommerceSpree::Session model
|
29
|
+
def visitor_id_for_flow_io
|
30
|
+
guest_token = cookies.signed[:guest_token]
|
31
|
+
uid = if guest_token
|
32
|
+
Digest::SHA1.hexdigest(guest_token)
|
33
|
+
else
|
34
|
+
session_id = session[:session_id]
|
35
|
+
session_id ? Digest::SHA1.hexdigest(session_id) : Digest::SHA1.hexdigest(request.ip + request.user_agent)
|
36
|
+
end
|
37
|
+
|
38
|
+
"session-#{uid}"
|
39
|
+
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
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlowcommerceSpree
|
4
|
+
class WebhooksController < ActionController::Base
|
5
|
+
respond_to :json
|
6
|
+
|
7
|
+
# forward all incoming requests to Flow WebhookService object
|
8
|
+
# /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?
|
13
|
+
rescue StandardError => e
|
14
|
+
result = { error: e.class.to_s, message: e.message, backtrace: e.backtrace }
|
15
|
+
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
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Flow (2017)
|
4
|
+
# Enable this modifications if you want to display flow localized line item shipment price beside Spree default
|
5
|
+
# Example: https://i.imgur.com/7v2ix2G.png
|
6
|
+
module Spree
|
7
|
+
module Admin
|
8
|
+
OrdersHelper.module_eval do
|
9
|
+
# admin show line item total price
|
10
|
+
def line_item_shipment_price(line_item, quantity)
|
11
|
+
price = Spree::Money.new(line_item.price * quantity, currency: line_item.currency).to_s
|
12
|
+
price += " (#{@order.flow_line_item_price(line_item, quantity)})" if @order.flow_order
|
13
|
+
price.html_safe
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Core
|
5
|
+
module ControllerHelpers
|
6
|
+
# Spree::Core::ControllerHelpers::Order decorator to inject Flow.io Experience into the order, if such an
|
7
|
+
# Experience is present in the Order's zone
|
8
|
+
module FlowIoOrderHelperDecorator
|
9
|
+
private
|
10
|
+
|
11
|
+
def adjust_zone_and_ip
|
12
|
+
update_meta = @current_order.zone_id ? nil : true
|
13
|
+
@current_order.zone = current_zone
|
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
|
23
|
+
end
|
24
|
+
update_meta = true
|
25
|
+
end
|
26
|
+
|
27
|
+
if @current_order.new_record?
|
28
|
+
@current_order.last_ip_address = ip_address
|
29
|
+
return @current_order.save
|
30
|
+
end
|
31
|
+
|
32
|
+
attrs_to_update = {}
|
33
|
+
|
34
|
+
# Update last_ip_address only for a new request_id
|
35
|
+
attrs_to_update = { last_ip_address: ip_address } if @request_id != request_id
|
36
|
+
|
37
|
+
# :meta is a jsonb column costly to update every time, especially with all the flow.io data, that's why
|
38
|
+
# here it is updated only if no zone_id there was inside :meta
|
39
|
+
attrs_to_update[:meta] = @current_order.meta.to_json if update_meta
|
40
|
+
|
41
|
+
@current_order.update_columns(attrs_to_update) if attrs_to_update.present?
|
42
|
+
attrs_to_update
|
43
|
+
end
|
44
|
+
|
45
|
+
def request_id
|
46
|
+
@request_id ||= env['action_dispatch.request_id']
|
47
|
+
end
|
48
|
+
|
49
|
+
ApplicationController.prepend(self) if ApplicationController.included_modules.exclude?(self)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|