flowcommerce_spree 0.0.1
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 +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
|