spree_gateway 3.7.4 → 3.9.3
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/.travis.yml +36 -37
- data/Appraisals +3 -8
- data/app/models/spree/check.rb +41 -0
- data/app/models/spree/credit_card_decorator.rb +10 -0
- data/app/models/spree/gateway/stripe_ach_gateway.rb +60 -0
- data/app/models/spree/gateway/stripe_elements_gateway.rb +50 -0
- data/app/models/spree/gateway/stripe_gateway.rb +1 -0
- data/app/models/spree/order_decorator.rb +28 -0
- data/app/models/spree/payment_decorator.rb +36 -0
- data/app/views/spree/checkout/_payment_confirm.html.erb +39 -0
- data/config/initializers/spree_permitted_attributes.rb +5 -0
- data/config/locales/en.yml +23 -0
- data/config/routes.rb +12 -0
- data/db/migrate/20200317135551_add_spree_check_payment_source.rb +22 -0
- data/db/migrate/20200422114908_add_intent_key_to_payment.rb +5 -0
- data/gemfiles/{spree_3_5.gemfile → spree_4_1.gemfile} +1 -1
- data/lib/active_merchant/billing/stripe_gateway_decorator.rb +13 -0
- data/lib/controllers/spree/api/v2/storefront/intents_controller.rb +27 -0
- data/lib/spree_frontend/controllers/spree/checkout_controller_decorator.rb +19 -0
- data/lib/spree_gateway/engine.rb +8 -0
- data/lib/spree_gateway/version.rb +1 -1
- data/lib/views/backend/spree/admin/payments/source_forms/_stripe_ach.html.erb +86 -0
- data/lib/views/backend/spree/admin/payments/source_forms/_stripe_apple_pay.html.erb +0 -0
- data/lib/views/backend/spree/admin/payments/source_views/_stripe_ach.html.erb +21 -0
- data/lib/views/backend/spree/admin/payments/source_views/_stripe_apple_pay.html.erb +1 -0
- data/lib/views/frontend/spree/checkout/payment/_stripe_ach.html.erb +81 -0
- data/lib/views/frontend/spree/checkout/payment/_stripe_ach_verify.html.erb +16 -0
- data/lib/views/frontend/spree/checkout/payment/_stripe_apple_pay.html.erb +10 -1
- data/lib/views/frontend/spree/checkout/payment/_stripe_elements.html.erb +2 -1
- data/spec/factories/check_factory.rb +10 -0
- data/spec/features/admin/stripe_elements_payment_spec.rb +32 -32
- data/spec/features/stripe_checkout_spec.rb +30 -19
- data/spec/features/stripe_elements_3ds_checkout_spec.rb +224 -0
- data/spec/models/gateway/stripe_ach_gateway_spec.rb +186 -0
- data/spec/models/gateway/stripe_gateway_spec.rb +1 -0
- data/spec/spec_helper.rb +7 -65
- data/spec/support/order_walktrough.rb +73 -0
- data/spec/support/within_stripe_3ds_popup.rb +10 -0
- data/spree_gateway.gemspec +10 -22
- metadata +44 -282
- data/gemfiles/spree_4_0.gemfile +0 -8
- data/spec/support/capybara_helper.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82e672befb08ae277659eec1f7686002af0b6f66b1f8ecb467649ab29667aee2
|
4
|
+
data.tar.gz: 47d5a54c20d7987569af842d50f471e6f3eea69647f6807865191c55e97f61cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5efb8b8ce887c92a222bf0b4c4b53b0ea16ee45f6efff3ad2908acdc5e3383139b778362be57ed858d15a0497df4d6aa37fa2c8f56ddee81f334945bcb67fe9f
|
7
|
+
data.tar.gz: fb61b3afbfc998e819bd11cf5d1f53c782e0e486c5b0fea6c43710fba74664398384badff68298a593b715185da3eaa68727e18b3d575dc5f14511d232d7f437
|
data/.travis.yml
CHANGED
@@ -1,51 +1,50 @@
|
|
1
|
-
|
2
|
-
dist:
|
1
|
+
os: linux
|
2
|
+
dist: bionic
|
3
|
+
|
4
|
+
addons:
|
5
|
+
apt:
|
6
|
+
sources:
|
7
|
+
- google-chrome
|
8
|
+
packages:
|
9
|
+
- google-chrome-stable
|
10
|
+
|
11
|
+
services:
|
12
|
+
- mysql
|
13
|
+
- postgresql
|
3
14
|
|
4
15
|
language: ruby
|
5
16
|
|
6
|
-
|
7
|
-
|
8
|
-
|
17
|
+
rvm:
|
18
|
+
- 2.7
|
19
|
+
- 3.0
|
9
20
|
|
10
21
|
env:
|
11
|
-
- DB=postgres
|
12
22
|
- DB=mysql
|
23
|
+
- DB=postgres
|
13
24
|
|
14
25
|
gemfile:
|
15
|
-
- gemfiles/spree_3_5.gemfile
|
16
26
|
- gemfiles/spree_3_7.gemfile
|
17
|
-
- gemfiles/
|
27
|
+
- gemfiles/spree_4_1.gemfile
|
18
28
|
- gemfiles/spree_master.gemfile
|
19
29
|
|
20
|
-
|
21
|
-
|
22
|
-
-
|
23
|
-
|
24
|
-
rvm:
|
25
|
-
|
26
|
-
-
|
27
|
-
|
28
|
-
|
29
|
-
matrix:
|
30
|
-
allow_failures:
|
31
|
-
- gemfile: gemfiles/spree_master.gemfile
|
32
|
-
exclude:
|
33
|
-
- rvm: 2.3.8
|
34
|
-
gemfile: gemfiles/spree_master.gemfile
|
35
|
-
- rvm: 2.4.4
|
36
|
-
gemfile: gemfiles/spree_master.gemfile
|
37
|
-
- rvm: 2.3.8
|
38
|
-
gemfile: gemfiles/spree_4_0.gemfile
|
39
|
-
- rvm: 2.4.4
|
40
|
-
gemfile: gemfiles/spree_4_0.gemfile
|
41
|
-
- rvm: 2.5.1
|
42
|
-
gemfile: gemfiles/spree_3_5.gemfile
|
30
|
+
jobs:
|
31
|
+
allow_failures:
|
32
|
+
- gemfile: gemfiles/spree_master.gemfile
|
33
|
+
exclude:
|
34
|
+
- rvm: 3.0
|
35
|
+
gemfile: gemfiles/spree_4_1.gemfile
|
36
|
+
- rvm: 3.0
|
37
|
+
gemfile: gemfiles/spree_3_7.gemfile
|
43
38
|
|
44
39
|
before_install:
|
45
40
|
- mysql -u root -e "GRANT ALL ON *.* TO 'travis'@'%';"
|
46
|
-
|
47
|
-
|
48
|
-
-
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
41
|
+
|
42
|
+
before_script:
|
43
|
+
- CHROME_MAIN_VERSION=`google-chrome-stable --version | sed -E 's/(^Google Chrome |\.[0-9]+ )//g'`
|
44
|
+
- CHROMEDRIVER_VERSION=`curl -s "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_$CHROME_MAIN_VERSION"`
|
45
|
+
- curl "https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip" -O
|
46
|
+
- unzip chromedriver_linux64.zip -d ~/bin
|
47
|
+
|
48
|
+
script:
|
49
|
+
- bundle exec rake test_app
|
50
|
+
- bundle exec rake spec
|
data/Appraisals
CHANGED
@@ -1,16 +1,11 @@
|
|
1
|
-
appraise 'spree-3-5' do
|
2
|
-
gem 'spree', '~> 3.5.0'
|
3
|
-
gem 'rails-controller-testing'
|
4
|
-
end
|
5
|
-
|
6
1
|
appraise 'spree-3-7' do
|
7
2
|
gem 'spree', '~> 3.7.0'
|
8
|
-
gem 'sass-rails'
|
9
3
|
gem 'rails-controller-testing'
|
4
|
+
gem 'sass-rails'
|
10
5
|
end
|
11
6
|
|
12
|
-
appraise 'spree-4-
|
13
|
-
gem 'spree', '~> 4.
|
7
|
+
appraise 'spree-4-1' do
|
8
|
+
gem 'spree', '~> 4.1.0'
|
14
9
|
gem 'rails-controller-testing'
|
15
10
|
end
|
16
11
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Spree
|
2
|
+
class Check < Spree::Base
|
3
|
+
|
4
|
+
attr_accessor :imported
|
5
|
+
|
6
|
+
belongs_to :payment_method
|
7
|
+
belongs_to :user, class_name: Spree.user_class.to_s, foreign_key: 'user_id',
|
8
|
+
optional: true
|
9
|
+
has_many :payments, as: :source
|
10
|
+
|
11
|
+
scope :with_payment_profile, -> { where.not(gateway_customer_profile_id: nil) }
|
12
|
+
|
13
|
+
validates :account_holder_name, presence: true
|
14
|
+
validates :account_holder_type, presence: true, inclusion: { in: %w[Individual Company] }
|
15
|
+
validates :account_number, presence: true, numericality: { only_integer: true }
|
16
|
+
validates :routing_number, presence: true, numericality: { only_integer: true }
|
17
|
+
|
18
|
+
def has_payment_profile?
|
19
|
+
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?
|
20
|
+
end
|
21
|
+
|
22
|
+
def actions
|
23
|
+
%w[capture void credit]
|
24
|
+
end
|
25
|
+
|
26
|
+
def can_capture?(payment)
|
27
|
+
payment.pending? || payment.checkout?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Indicates whether its possible to void the payment.
|
31
|
+
def can_void?(payment)
|
32
|
+
!payment.failed? && !payment.void?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Indicates whether its possible to credit the payment. Note that most gateways require that the
|
36
|
+
# payment be settled first which generally happens within 12-24 hours of the transaction.
|
37
|
+
def can_credit?(payment)
|
38
|
+
payment.completed? && payment.credit_allowed > 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Spree
|
2
|
+
class Gateway::StripeAchGateway < Gateway::StripeGateway
|
3
|
+
|
4
|
+
def method_type
|
5
|
+
'stripe_ach'
|
6
|
+
end
|
7
|
+
|
8
|
+
def payment_source_class
|
9
|
+
Check
|
10
|
+
end
|
11
|
+
|
12
|
+
def verify(source, gateway_options)
|
13
|
+
provider.verify(source, gateway_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_profile(payment)
|
17
|
+
return unless payment.source&.gateway_customer_profile_id.nil?
|
18
|
+
|
19
|
+
options = {
|
20
|
+
email: payment.order.user&.email || payment.order.email,
|
21
|
+
login: preferred_secret_key,
|
22
|
+
}.merge! address_for(payment)
|
23
|
+
|
24
|
+
source = payment.source
|
25
|
+
bank_account = if source.gateway_payment_profile_id.present?
|
26
|
+
source.gateway_payment_profile_id
|
27
|
+
else
|
28
|
+
source
|
29
|
+
end
|
30
|
+
|
31
|
+
response = provider.store(bank_account, options)
|
32
|
+
|
33
|
+
if response.success?
|
34
|
+
payment.source.update!({
|
35
|
+
gateway_customer_profile_id: response.params['id'],
|
36
|
+
gateway_payment_profile_id: response.params['default_source'] || response.params['default_card']
|
37
|
+
})
|
38
|
+
|
39
|
+
else
|
40
|
+
payment.send(:gateway_error, response.message)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def supports?(_source)
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def available_for_order?(order)
|
49
|
+
# Stripe ACH payments are supported only for US customers
|
50
|
+
# Therefore we need to check order's addresses
|
51
|
+
return unless order.ship_address_id && order.bill_address_id
|
52
|
+
return unless order.ship_address && order.bill_address_id
|
53
|
+
|
54
|
+
usa_id = ::Spree::Country.find_by(iso: 'US')&.id
|
55
|
+
return false unless usa_id
|
56
|
+
|
57
|
+
order.ship_address.country_id == usa_id && order.bill_address.country_id == usa_id
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,7 +1,57 @@
|
|
1
1
|
module Spree
|
2
2
|
class Gateway::StripeElementsGateway < Gateway::StripeGateway
|
3
|
+
preference :intents, :boolean, default: true
|
4
|
+
|
3
5
|
def method_type
|
4
6
|
'stripe_elements'
|
5
7
|
end
|
8
|
+
|
9
|
+
def provider_class
|
10
|
+
if get_preference(:intents)
|
11
|
+
ActiveMerchant::Billing::StripePaymentIntentsGateway
|
12
|
+
else
|
13
|
+
ActiveMerchant::Billing::StripeGateway
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_profile(payment)
|
18
|
+
return unless payment.source.gateway_customer_profile_id.nil?
|
19
|
+
|
20
|
+
options = {
|
21
|
+
email: payment.order.email,
|
22
|
+
login: preferred_secret_key
|
23
|
+
}.merge! address_for(payment)
|
24
|
+
|
25
|
+
source = update_source!(payment.source)
|
26
|
+
creditcard = source.gateway_payment_profile_id.present? ? source.gateway_payment_profile_id : source
|
27
|
+
response = provider.store(creditcard, options)
|
28
|
+
if response.success?
|
29
|
+
if get_preference(:intents)
|
30
|
+
payment.source.update!(
|
31
|
+
cc_type: payment.source.cc_type,
|
32
|
+
gateway_customer_profile_id: response.params['id'],
|
33
|
+
gateway_payment_profile_id: response.params['sources']['data'].first['id']
|
34
|
+
)
|
35
|
+
else
|
36
|
+
response_cc_type = response.params['sources']['data'].first['brand']
|
37
|
+
cc_type = CARD_TYPE_MAPPING.include?(response_cc_type) ? CARD_TYPE_MAPPING[response_cc_type] : payment.source.cc_type
|
38
|
+
payment.source.update!({
|
39
|
+
cc_type: cc_type, # side-effect of update_source!
|
40
|
+
gateway_customer_profile_id: response.params['id'],
|
41
|
+
gateway_payment_profile_id: response.params['default_source'] || response.params['default_card']
|
42
|
+
})
|
43
|
+
end
|
44
|
+
else
|
45
|
+
payment.send(:gateway_error, response.message)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def options_for_purchase_or_auth(money, creditcard, gateway_options)
|
52
|
+
money, creditcard, options = super
|
53
|
+
options[:execute_threed] = get_preference(:intents)
|
54
|
+
return money, creditcard, options
|
55
|
+
end
|
6
56
|
end
|
7
57
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Spree
|
2
|
+
module OrderDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
return if base.checkout_steps.key?(:payment_confirm)
|
5
|
+
|
6
|
+
base.insert_checkout_step(
|
7
|
+
:payment_confirm,
|
8
|
+
before: :complete,
|
9
|
+
if: ->(order) { order.intents? }
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_payments!
|
14
|
+
# Payments are processed in confirm_payment step where after successful
|
15
|
+
# 3D Secure authentication `intent_client_key` is saved for payment.
|
16
|
+
# In case authentication is unsuccessful, `intent_client_key` is removed.
|
17
|
+
return if intents? && payments.valid.last.intent_client_key.present?
|
18
|
+
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def intents?
|
23
|
+
payments.valid.map { |p| p.payment_method&.has_preference?(:intents) && p.payment_method&.get_preference(:intents) }.any?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Spree::Order.prepend(Spree::OrderDecorator)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Spree
|
2
|
+
module PaymentDecorator
|
3
|
+
def handle_response(response, success_state, failure_state)
|
4
|
+
if response.success? && response.respond_to?(:params)
|
5
|
+
self.intent_client_key = response.params['client_secret'] if response.params['client_secret']
|
6
|
+
end
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def verify!(**options)
|
11
|
+
process_verification(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def process_verification(**options)
|
17
|
+
protect_from_connection_error do
|
18
|
+
response = payment_method.verify(source, options)
|
19
|
+
|
20
|
+
record_response(response)
|
21
|
+
|
22
|
+
if response.success?
|
23
|
+
unless response.authorization.nil?
|
24
|
+
self.response_code = response.authorization
|
25
|
+
|
26
|
+
source.update(status: response.params['status'])
|
27
|
+
end
|
28
|
+
else
|
29
|
+
gateway_error(response)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Spree::Payment.prepend(Spree::PaymentDecorator)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<div id='errorBox' class='errorExplanation alert alert-danger' style='display:none'></div>
|
2
|
+
<div id='successBox' class='alert alert-success' style='display:none'></div>
|
3
|
+
<div id='infoBox' class='alert alert-info'><%= t('spree.please_wait_for_confirmation_popup') %></div>
|
4
|
+
|
5
|
+
<% if @client_secret.present? && @pk_key.present? %>
|
6
|
+
<script type="text/javascript" src="https://js.stripe.com/v3/"></script>
|
7
|
+
<script>
|
8
|
+
var form = document.getElementById('checkout_form_payment_confirm');
|
9
|
+
|
10
|
+
function confirmCardPaymentResponseHandler(response) {
|
11
|
+
$.post("/api/v2/storefront/intents/handle_response", { response: response, order_token: "<%= @order.token %>" }).done(function (result) {
|
12
|
+
// conditional needs for spree 3.7
|
13
|
+
if(form.elements["commit"]) {
|
14
|
+
form.elements["commit"].disabled = false;
|
15
|
+
}
|
16
|
+
$('#successBox').html(result.message);
|
17
|
+
$('#successBox').show();
|
18
|
+
form.submit();
|
19
|
+
}).fail(function(result) {
|
20
|
+
if(form.elements["commit"]) {
|
21
|
+
form.elements["commit"].disabled = false;
|
22
|
+
}
|
23
|
+
$('#errorBox').html(result.responseJSON.error);
|
24
|
+
$('#errorBox').show();
|
25
|
+
});
|
26
|
+
}
|
27
|
+
|
28
|
+
var stripeElements = Stripe("<%= @pk_key %>");
|
29
|
+
stripeElements.confirmCardPayment("<%= @client_secret %>").then(function(result) {
|
30
|
+
$('#infoBox').hide();
|
31
|
+
confirmCardPaymentResponseHandler(result);
|
32
|
+
});
|
33
|
+
|
34
|
+
document.addEventListener('DOMContentLoaded', function(){
|
35
|
+
form.elements["commit"].value = "continue"
|
36
|
+
form.elements["commit"].disabled = true
|
37
|
+
});
|
38
|
+
</script>
|
39
|
+
<% end %>
|
data/config/locales/en.yml
CHANGED
@@ -1,7 +1,19 @@
|
|
1
1
|
---
|
2
2
|
en:
|
3
|
+
activerecord:
|
4
|
+
attributes:
|
5
|
+
spree/check:
|
6
|
+
account_holder_name: Account Holder Name
|
7
|
+
account_holder_type: Account Holder Type
|
8
|
+
account_number: Account Number
|
9
|
+
routing_number: Routing Number
|
3
10
|
spree:
|
11
|
+
check: Check
|
4
12
|
payment_has_been_cancelled: The payment has been cancelled.
|
13
|
+
please_wait_for_confirmation_popup: Please wait for payment confirmation popup to appear.
|
14
|
+
payment_successfully_authorized: The payment was successfully authorized.
|
15
|
+
order_state:
|
16
|
+
payment_confirm: Verify payment
|
5
17
|
log_entry:
|
6
18
|
braintree:
|
7
19
|
message: Message
|
@@ -21,3 +33,14 @@ en:
|
|
21
33
|
cvv_result: CVV Result
|
22
34
|
cvc_check: CVC Check
|
23
35
|
address_zip_check: Address ZIP check
|
36
|
+
stripe:
|
37
|
+
ach:
|
38
|
+
account_holder_name: Account Holder Name
|
39
|
+
account_holder_type: Account Holder Type
|
40
|
+
routing_number: Routing Number
|
41
|
+
account_number: Account Number
|
42
|
+
verify_account_number: Verify Account Number
|
43
|
+
verify_bank_account: Verify Bank Account
|
44
|
+
first_deposit: First Deposit
|
45
|
+
second_deposit: Second Deposit
|
46
|
+
bank_transfer: bank_transfer
|