spree_gateway 3.8.0 → 3.9.4

Sign up to get free protection for your applications and to get access to all the features.
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
+