spree_gateway 3.8.0 → 3.9.4

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -11
  3. data/Gemfile +3 -1
  4. data/README.md +2 -2
  5. data/Rakefile +2 -2
  6. data/app/models/spree/gateway/stripe_ach_gateway.rb +1 -1
  7. data/app/models/spree/gateway/stripe_elements_gateway.rb +54 -0
  8. data/app/models/spree/gateway/stripe_gateway.rb +5 -0
  9. data/app/models/{spree → spree_gateway}/apple_pay_order_decorator.rb +2 -2
  10. data/app/models/{spree → spree_gateway}/apple_pay_payment_decorator.rb +2 -2
  11. data/app/models/spree_gateway/credit_card_decorator.rb +10 -0
  12. data/app/models/spree_gateway/order_decorator.rb +28 -0
  13. data/app/models/{spree → spree_gateway}/payment_decorator.rb +9 -2
  14. data/app/views/spree/checkout/_payment_confirm.html.erb +39 -0
  15. data/config/locales/en.yml +4 -0
  16. data/config/routes.rb +12 -0
  17. data/db/migrate/20200422114908_add_intent_key_to_payment.rb +5 -0
  18. data/lib/controllers/spree/api/v2/storefront/intents_controller.rb +27 -0
  19. data/lib/spree_frontend/controllers/spree/checkout_controller_decorator.rb +19 -0
  20. data/lib/spree_gateway/engine.rb +10 -0
  21. data/lib/spree_gateway/version.rb +1 -1
  22. data/lib/views/frontend/spree/checkout/payment/_stripe_elements.html.erb +2 -1
  23. data/spec/features/admin/stripe_elements_payment_spec.rb +20 -29
  24. data/spec/features/stripe_checkout_spec.rb +37 -23
  25. data/spec/features/stripe_elements_3ds_checkout_spec.rb +225 -0
  26. data/spec/models/gateway/authorize_net_spec.rb +1 -1
  27. data/spec/models/gateway/balanced_gateway_spec.rb +1 -1
  28. data/spec/models/gateway/banwire_spec.rb +1 -1
  29. data/spec/models/gateway/beanstream_spec.rb +1 -1
  30. data/spec/models/gateway/braintree_gateway_spec.rb +24 -13
  31. data/spec/models/gateway/card_save_spec.rb +1 -1
  32. data/spec/models/gateway/{data_cache_spec.rb → data_cash_spec.rb} +1 -1
  33. data/spec/models/gateway/epay_spec.rb +1 -1
  34. data/spec/models/gateway/eway_rapid_spec.rb +1 -1
  35. data/spec/models/gateway/eway_spec.rb +1 -1
  36. data/spec/models/gateway/moneris_spec.rb +1 -1
  37. data/spec/models/gateway/pay_junction_spec.rb +1 -1
  38. data/spec/models/gateway/pay_pal_spec.rb +1 -1
  39. data/spec/models/gateway/payflow_pro_spec.rb +1 -1
  40. data/spec/models/gateway/paymill_spec.rb +1 -1
  41. data/spec/models/gateway/pin_gateway_spec.rb +1 -1
  42. data/spec/models/gateway/quickpay_spec.rb +1 -1
  43. data/spec/models/gateway/sage_pay_spec.rb +1 -1
  44. data/spec/models/gateway/secure_pay_au_spec.rb +1 -1
  45. data/spec/models/gateway/stripe_ach_gateway_spec.rb +2 -1
  46. data/spec/models/gateway/stripe_gateway_spec.rb +1 -0
  47. data/spec/models/gateway/usa_epay_transaction_spec.rb +2 -2
  48. data/spec/models/gateway/worldpay_spec.rb +1 -1
  49. data/spec/models/spree/order_spec.rb +4 -2
  50. data/spec/support/order_walktrough.rb +73 -0
  51. data/spec/support/within_stripe_3ds_popup.rb +10 -0
  52. data/spree_gateway.gemspec +9 -3
  53. metadata +34 -28
  54. data/Appraisals +0 -14
  55. data/gemfiles/spree_4_1.gemfile +0 -8
  56. data/gemfiles/spree_4_2.gemfile +0 -8
  57. data/gemfiles/spree_master.gemfile +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '015491170e10b6b22d98da98f5b8e466ae2df12474e5029bff6bd8926d86732e'
4
- data.tar.gz: 39713d557a03b1170dc36f4fcf4a6ec2e4fecb45b3a80376b00a23fd396c200b
3
+ metadata.gz: a29093f977d40e708b032c608a9e25f1949352bee57b9321fa36488000d7711f
4
+ data.tar.gz: 5f5d7ff9014be360d444df942dc24d1313ef0881e786ac37a49f4fe884b5d0fe
5
5
  SHA512:
6
- metadata.gz: c9d5003e95dc31701dbea5239a10dc587300d27659f29ea6deba81a309df2d24729ec3259d253d99f4c327c7f8889bc52b28dc8015d785fbde376a128d05a6f1
7
- data.tar.gz: 11a5083fba9163eabd567cef8173d949d6f6ac5b86a97f3c65281671d3fd82f6ed93d2f4626c2ac39e7ae71d16cc559735a9d5eb4024960041a1ba2128997ba8
6
+ metadata.gz: 807b40308555c5149f146fa3fc38c52f10c47ec765a1988f0562adcc296115d43670f09052a80a2493edd166d6d195092e7861ae07457c8c47eedb0cca90559b
7
+ data.tar.gz: 0ce03934963ea212e16aed6148eff226362d90544789ec1fa283c69dbff81c1d2834c91bce4aab81794935c5d3e825ffb89f07b95d66d1d9994128b11f8e31de
data/.travis.yml CHANGED
@@ -1,6 +1,8 @@
1
1
  os: linux
2
2
  dist: bionic
3
3
 
4
+ cache: bundler
5
+
4
6
  addons:
5
7
  apt:
6
8
  sources:
@@ -11,25 +13,18 @@ addons:
11
13
  services:
12
14
  - mysql
13
15
  - postgresql
16
+ - redis-server
14
17
 
15
18
  language: ruby
16
19
 
17
20
  rvm:
18
- - 2.6
21
+ - 2.7
22
+ - 3.0
19
23
 
20
24
  env:
21
25
  - DB=mysql
22
26
  - DB=postgres
23
27
 
24
- gemfile:
25
- # - gemfiles/spree_4_1.gemfile
26
- - gemfiles/spree_4_2.gemfile
27
- - gemfiles/spree_master.gemfile
28
-
29
- jobs:
30
- allow_failures:
31
- - gemfile: gemfiles/spree_master.gemfile
32
-
33
28
  before_install:
34
29
  - mysql -u root -e "GRANT ALL ON *.* TO 'travis'@'%';"
35
30
 
@@ -41,4 +36,4 @@ before_script:
41
36
 
42
37
  script:
43
38
  - bundle exec rake test_app
44
- - bundle exec rake spec
39
+ - bundle exec rake spec
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rails-controller-testing'
4
- gem 'spree', github: 'spree/spree', branch: 'master'
4
+ gem 'spree', github: 'spree/spree', branch: 'main'
5
+ gem 'spree_backend', github: 'spree/spree', branch: 'main'
6
+ gem 'spree_frontend', github: 'spree/spree', branch: 'main'
5
7
 
6
8
  gemspec
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Spree Gateway
2
2
 
3
- [![Build Status](https://api.travis-ci.org/spree/spree_gateway.svg?branch=master)](https://travis-ci.org/spree/spree_gateway)
3
+ [![Build Status](https://api.travis-ci.org/spree/spree_gateway.svg?branch=main)](https://travis-ci.org/spree/spree_gateway)
4
4
  [![Code Climate](https://codeclimate.com/github/spree/spree_gateway.svg)](https://codeclimate.com/github/spree/spree_gateway)
5
5
 
6
6
  Community supported Spree Payment Method Gateways. It works as a wrapper for
@@ -100,6 +100,6 @@ We are [available for hire][spark].
100
100
 
101
101
  [1]: http://www.fsf.org/licensing/essays/free-sw.html
102
102
  [2]: https://github.com/spree/spree_gateway/issues
103
- [3]: https://github.com/spree/spree_gateway/blob/master/LICENSE.md
103
+ [3]: https://github.com/spree/spree_gateway/blob/main/LICENSE.md
104
104
  [4]: https://github.com/spree
105
105
  [5]: https://github.com/spree/spree_gateway/graphs/contributors
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
4
  require 'rspec/core/rake_task'
5
- require 'spree/testing_support/common_rake'
5
+ require 'spree/testing_support/extension_rake'
6
6
 
7
7
  RSpec::Core::RakeTask.new
8
8
 
@@ -11,5 +11,5 @@ task :default => [:spec]
11
11
  desc "Generates a dummy app for testing"
12
12
  task :test_app do
13
13
  ENV['LIB_NAME'] = 'spree_gateway'
14
- Rake::Task['common:test_app'].invoke
14
+ Rake::Task['extension:test_app'].invoke
15
15
  end
@@ -9,7 +9,7 @@ module Spree
9
9
  Check
10
10
  end
11
11
 
12
- def verify(source, **gateway_options)
12
+ def verify(source, gateway_options)
13
13
  provider.verify(source, gateway_options)
14
14
  end
15
15
 
@@ -1,7 +1,61 @@
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
56
+
57
+ def public_preference_keys
58
+ %i[publishable_key test_mode intents]
59
+ end
6
60
  end
7
61
  end
@@ -54,6 +54,7 @@ module Spree
54
54
 
55
55
  def create_profile(payment)
56
56
  return unless payment.source.gateway_customer_profile_id.nil?
57
+
57
58
  options = {
58
59
  email: payment.order.email,
59
60
  login: preferred_secret_key,
@@ -142,5 +143,9 @@ module Spree
142
143
  url = 'https://spreecommerce.org'
143
144
  "#{name_with_version} #{url}"
144
145
  end
146
+
147
+ def public_preference_keys
148
+ %i[publishable_key test_mode]
149
+ end
145
150
  end
146
151
  end
@@ -1,4 +1,4 @@
1
- module Spree
1
+ module SpreeGateway
2
2
  module ApplePayOrderDecorator
3
3
  def confirmation_required?
4
4
  return false if paid_with_apple_pay?
@@ -17,4 +17,4 @@ module Spree
17
17
  end
18
18
  end
19
19
 
20
- Spree::Order.prepend Spree::ApplePayOrderDecorator
20
+ ::Spree::Order.prepend(::SpreeGateway::ApplePayOrderDecorator)
@@ -1,4 +1,4 @@
1
- module Spree
1
+ module SpreeGateway
2
2
  module ApplePayPaymentDecorator
3
3
  def apple_pay?
4
4
  payment_method.is_a? Spree::Gateway::StripeApplePayGateway
@@ -6,4 +6,4 @@ module Spree
6
6
  end
7
7
  end
8
8
 
9
- Spree::Payment.prepend Spree::ApplePayPaymentDecorator
9
+ ::Spree::Payment.prepend(::SpreeGateway::ApplePayPaymentDecorator)
@@ -0,0 +1,10 @@
1
+ module SpreeGateway
2
+ module CreditCardDecorator
3
+ def set_last_digits
4
+ self.last_digits ||= number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
5
+ end
6
+
7
+ end
8
+ end
9
+
10
+ ::Spree::CreditCard.prepend(::SpreeGateway::CreditCardDecorator)
@@ -0,0 +1,28 @@
1
+ module SpreeGateway
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(::SpreeGateway::OrderDecorator)
@@ -1,5 +1,12 @@
1
- module Spree
1
+ module SpreeGateway
2
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
+
3
10
  def verify!(**options)
4
11
  process_verification(options)
5
12
  end
@@ -26,4 +33,4 @@ module Spree
26
33
  end
27
34
  end
28
35
 
29
- Spree::Payment.prepend Spree::PaymentDecorator
36
+ ::Spree::Payment.prepend(::SpreeGateway::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 %>
@@ -10,6 +10,10 @@ en:
10
10
  spree:
11
11
  check: Check
12
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
13
17
  log_entry:
14
18
  braintree:
15
19
  message: Message
data/config/routes.rb CHANGED
@@ -4,3 +4,15 @@
4
4
  Rails.application.routes.draw do
5
5
  get '/.well-known/apple-developer-merchantid-domain-association' => 'spree/apple_pay_domain_verification#show'
6
6
  end
7
+
8
+ Spree::Core::Engine.add_routes do
9
+ namespace :api, defaults: { format: 'json' } do
10
+ namespace :v2 do
11
+ namespace :storefront do
12
+ namespace :intents do
13
+ post :handle_response
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ class AddIntentKeyToPayment < ActiveRecord::Migration[4.2]
2
+ def change
3
+ add_column :spree_payments, :intent_client_key, :string
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ module Spree
2
+ module Api
3
+ module V2
4
+ module Storefront
5
+ class IntentsController < ::Spree::Api::V2::BaseController
6
+ include Spree::Api::V2::Storefront::OrderConcern
7
+
8
+ def handle_response
9
+ if params['response']['error']
10
+ invalidate_payment
11
+ render_error_payload(params['response']['error']['message'])
12
+ else
13
+ render_serialized_payload { { message: I18n.t('spree.payment_successfully_authorized') } }
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def invalidate_payment
20
+ payment = spree_current_order.payments.find_by!(response_code: params['response']['error']['payment_intent']['id'])
21
+ payment.update(state: 'failed', intent_client_key: nil)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ module Spree
2
+ module CheckoutControllerDecorator
3
+ def self.prepended(base)
4
+ base.before_action :process_payments_and_set_keys, only: :edit, if: proc { params[:state] == 'payment_confirm' }
5
+ end
6
+
7
+ def process_payments_and_set_keys
8
+ @order.tap do |order|
9
+ order.process_payments!
10
+ order.reload.payments.valid.where.not(intent_client_key: nil).last.tap do |payment|
11
+ @client_secret = payment.intent_client_key
12
+ @pk_key = payment.payment_method.preferred_publishable_key
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ ::Spree::CheckoutController.prepend Spree::CheckoutControllerDecorator
@@ -41,9 +41,18 @@ module SpreeGateway
41
41
  Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/spree/*_decorator*.rb')) do |c|
42
42
  Rails.application.config.cache_classes ? require(c) : load(c)
43
43
  end
44
+ Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/spree_gateway/*_decorator*.rb')) do |c|
45
+ Rails.application.config.cache_classes ? require(c) : load(c)
46
+ end
44
47
  Dir.glob(File.join(File.dirname(__FILE__), '../../lib/active_merchant/**/*_decorator*.rb')) do |c|
45
48
  Rails.application.config.cache_classes ? require(c) : load(c)
46
49
  end
50
+
51
+ if self.frontend_available?
52
+ Dir.glob(File.join(File.dirname(__FILE__), '../../lib/spree_frontend/controllers/spree/*_decorator*.rb')) do |c|
53
+ Rails.application.config.cache_classes ? require(c) : load(c)
54
+ end
55
+ end
47
56
  end
48
57
 
49
58
  def self.backend_available?
@@ -61,6 +70,7 @@ module SpreeGateway
61
70
  paths['app/controllers'] << 'lib/controllers'
62
71
 
63
72
  if self.frontend_available?
73
+ paths["app/controllers"] << "lib/spree_frontend/controllers"
64
74
  paths["app/views"] << "lib/views/frontend"
65
75
  end
66
76
 
@@ -1,5 +1,5 @@
1
1
  module SpreeGateway
2
2
  def self.version
3
- '3.8.0'
3
+ '3.9.4'
4
4
  end
5
5
  end
@@ -103,7 +103,8 @@
103
103
  }
104
104
  });
105
105
  };
106
-
106
+
107
107
  </script>
108
108
 
109
109
  <%= render 'spree/checkout/payment/stripe_additional_info' %>
110
+