spree_gateway 3.7.1 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +31 -38
  3. data/Appraisals +4 -10
  4. data/README.md +9 -20
  5. data/app/models/spree/check.rb +41 -0
  6. data/app/models/spree/gateway/stripe_ach_gateway.rb +60 -0
  7. data/app/models/spree/payment_decorator.rb +29 -0
  8. data/config/initializers/spree_permitted_attributes.rb +5 -0
  9. data/config/locales/en.yml +19 -0
  10. data/db/migrate/20200317135551_add_spree_check_payment_source.rb +22 -0
  11. data/gemfiles/{spree_3_2.gemfile → spree_4_1.gemfile} +1 -1
  12. data/gemfiles/{spree_3_5.gemfile → spree_4_2.gemfile} +1 -1
  13. data/lib/active_merchant/billing/stripe_gateway_decorator.rb +13 -0
  14. data/lib/controllers/spree/apple_pay_domain_verification_controller.rb +1 -1
  15. data/lib/spree_gateway/engine.rb +1 -0
  16. data/lib/spree_gateway/version.rb +1 -1
  17. data/lib/views/backend/spree/admin/payments/source_forms/_stripe_ach.html.erb +86 -0
  18. data/lib/views/backend/spree/admin/payments/source_forms/_stripe_apple_pay.html.erb +0 -0
  19. data/lib/views/backend/spree/admin/payments/source_forms/_stripe_elements.html.erb +79 -0
  20. data/lib/views/backend/spree/admin/payments/source_views/_stripe_ach.html.erb +21 -0
  21. data/lib/views/backend/spree/admin/payments/source_views/_stripe_apple_pay.html.erb +1 -0
  22. data/lib/views/backend/spree/admin/payments/source_views/_stripe_elements.html.erb +1 -0
  23. data/lib/views/frontend/spree/checkout/payment/_stripe_ach.html.erb +81 -0
  24. data/lib/views/frontend/spree/checkout/payment/_stripe_ach_verify.html.erb +16 -0
  25. data/lib/views/frontend/spree/checkout/payment/_stripe_apple_pay.html.erb +10 -1
  26. data/lib/views/frontend/spree/checkout/payment/_stripe_elements.html.erb +18 -23
  27. data/spec/factories/check_factory.rb +10 -0
  28. data/spec/features/admin/stripe_elements_payment_spec.rb +109 -0
  29. data/spec/features/stripe_checkout_spec.rb +3 -0
  30. data/spec/models/gateway/stripe_ach_gateway_spec.rb +185 -0
  31. data/spec/spec_helper.rb +7 -64
  32. data/spree_gateway.gemspec +1 -20
  33. metadata +25 -274
  34. data/gemfiles/spree_3_7.gemfile +0 -9
  35. data/gemfiles/spree_4_0.gemfile +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd1e911eb84eec86826be7b64e8d94b6105b1cee6eee6b6850d2629b0fba1eb9
4
- data.tar.gz: a36fcdaff09f3f3e15db2af4bbec15e1625b6bf36cd41c8a45d4b1c93b51e393
3
+ metadata.gz: '015491170e10b6b22d98da98f5b8e466ae2df12474e5029bff6bd8926d86732e'
4
+ data.tar.gz: 39713d557a03b1170dc36f4fcf4a6ec2e4fecb45b3a80376b00a23fd396c200b
5
5
  SHA512:
6
- metadata.gz: 7e92f44b23f2b004564ad303d0c5f67bd312e5d921c3e61235bd48748486624df87866f5bbba7b128fd626c301bb0778f25b22798d804d397f6f9351fd5af946
7
- data.tar.gz: 920f697c64fa5290ec1a6bb08a52295365665a86afaa93802a31b91061e8543fd7632c57afd059d0aefc1a8b453798e1e2e11f7c743e2ea81139458965c57eb4
6
+ metadata.gz: c9d5003e95dc31701dbea5239a10dc587300d27659f29ea6deba81a309df2d24729ec3259d253d99f4c327c7f8889bc52b28dc8015d785fbde376a128d05a6f1
7
+ data.tar.gz: 11a5083fba9163eabd567cef8173d949d6f6ac5b86a97f3c65281671d3fd82f6ed93d2f4626c2ac39e7ae71d16cc559735a9d5eb4024960041a1ba2128997ba8
@@ -1,51 +1,44 @@
1
- sudo: required
2
- dist: trusty
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
- addons:
7
- chrome: stable
8
- postgresql: 9.4
17
+ rvm:
18
+ - 2.6
9
19
 
10
20
  env:
11
- - DB=postgres
12
21
  - DB=mysql
22
+ - DB=postgres
13
23
 
14
24
  gemfile:
15
- - gemfiles/spree_3_5.gemfile
16
- - gemfiles/spree_3_7.gemfile
17
- - gemfiles/spree_4_0.gemfile
25
+ # - gemfiles/spree_4_1.gemfile
26
+ - gemfiles/spree_4_2.gemfile
18
27
  - gemfiles/spree_master.gemfile
19
28
 
20
- script:
21
- - bundle exec rake test_app
22
- - bundle exec rake spec
23
-
24
- rvm:
25
- - 2.5.1
26
- - 2.4.4
27
- - 2.3.8
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
29
+ jobs:
30
+ allow_failures:
31
+ - gemfile: gemfiles/spree_master.gemfile
43
32
 
44
33
  before_install:
45
34
  - mysql -u root -e "GRANT ALL ON *.* TO 'travis'@'%';"
46
- - wget -N https://chromedriver.storage.googleapis.com/2.35/chromedriver_linux64.zip -P ~/
47
- - unzip ~/chromedriver_linux64.zip -d ~/
48
- - rm ~/chromedriver_linux64.zip
49
- - sudo mv -f ~/chromedriver /usr/local/share/
50
- - sudo chmod +x /usr/local/share/chromedriver
51
- - sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
35
+
36
+ before_script:
37
+ - CHROME_MAIN_VERSION=`google-chrome-stable --version | sed -E 's/(^Google Chrome |\.[0-9]+ )//g'`
38
+ - CHROMEDRIVER_VERSION=`curl -s "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_$CHROME_MAIN_VERSION"`
39
+ - curl "https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip" -O
40
+ - unzip chromedriver_linux64.zip -d ~/bin
41
+
42
+ script:
43
+ - bundle exec rake test_app
44
+ - bundle exec rake spec
data/Appraisals CHANGED
@@ -1,16 +1,10 @@
1
- appraise 'spree-3-5' do
2
- gem 'spree', '~> 3.5.0'
1
+ appraise 'spree-4-1' do
2
+ gem 'spree', '~> 4.1.0'
3
3
  gem 'rails-controller-testing'
4
4
  end
5
5
 
6
- appraise 'spree-3-7' do
7
- gem 'spree', '~> 3.7.0'
8
- gem 'sass-rails'
9
- gem 'rails-controller-testing'
10
- end
11
-
12
- appraise 'spree-4-0' do
13
- gem 'spree', '~> 4.0.0.rc2'
6
+ appraise 'spree-4-2' do
7
+ gem 'spree', '~> 4.2.0.beta'
14
8
  gem 'rails-controller-testing'
15
9
  end
16
10
 
data/README.md CHANGED
@@ -36,30 +36,19 @@ For`PayPal` support head over to [braintree_vzero](https://github.com/spree-cont
36
36
 
37
37
  1. Add this extension to your Gemfile with this line:
38
38
 
39
- #### Spree >= 3.1
40
-
41
- ```ruby
42
- gem 'spree_gateway', '~> 3.3'
43
- ```
44
-
45
- #### Spree 3.0 and Spree 2.x
46
-
47
- ```ruby
48
- gem 'spree_gateway', github: 'spree/spree_gateway', branch: 'X-X-stable'
49
- ```
50
-
51
- The `branch` option is important: it must match the version of Spree you're using.
52
- For example, use `3-0-stable` if you're using Spree `3-0-stable` or any `3.0.x` version.
39
+ ```ruby
40
+ gem 'spree_gateway', '~> 3.7'
41
+ ```
53
42
 
54
43
  2. Install the gem using Bundler:
55
- ```ruby
56
- bundle install
57
- ```
44
+ ```ruby
45
+ bundle install
46
+ ```
58
47
 
59
48
  3. Copy & run migrations
60
- ```ruby
61
- bundle exec rails g spree_gateway:install
62
- ```
49
+ ```ruby
50
+ bundle exec rails g spree_gateway:install
51
+ ```
63
52
 
64
53
  Finally, make sure to **restart your app**. Navigate to *Configuration > Payment Methods > New Payment Method* in the admin panel and you should see that a bunch of additional gateways have been added to the list.
65
54
 
@@ -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
@@ -0,0 +1,29 @@
1
+ module Spree
2
+ module PaymentDecorator
3
+ def verify!(**options)
4
+ process_verification(options)
5
+ end
6
+
7
+ private
8
+
9
+ def process_verification(**options)
10
+ protect_from_connection_error do
11
+ response = payment_method.verify(source, options)
12
+
13
+ record_response(response)
14
+
15
+ if response.success?
16
+ unless response.authorization.nil?
17
+ self.response_code = response.authorization
18
+
19
+ source.update(status: response.params['status'])
20
+ end
21
+ else
22
+ gateway_error(response)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ Spree::Payment.prepend Spree::PaymentDecorator
@@ -0,0 +1,5 @@
1
+ module Spree
2
+ module PermittedAttributes
3
+ @@source_attributes += %i[account_number routing_number account_holder_type account_holder_name status]
4
+ end
5
+ end
@@ -1,6 +1,14 @@
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.
5
13
  log_entry:
6
14
  braintree:
@@ -21,3 +29,14 @@ en:
21
29
  cvv_result: CVV Result
22
30
  cvc_check: CVC Check
23
31
  address_zip_check: Address ZIP check
32
+ stripe:
33
+ ach:
34
+ account_holder_name: Account Holder Name
35
+ account_holder_type: Account Holder Type
36
+ routing_number: Routing Number
37
+ account_number: Account Number
38
+ verify_account_number: Verify Account Number
39
+ verify_bank_account: Verify Bank Account
40
+ first_deposit: First Deposit
41
+ second_deposit: Second Deposit
42
+ bank_transfer: bank_transfer
@@ -0,0 +1,22 @@
1
+ class AddSpreeCheckPaymentSource < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :spree_checks do |t|
4
+ t.references :payment_method
5
+ t.references :user
6
+ t.string "account_holder_name"
7
+ t.string "account_holder_type"
8
+ t.string "routing_number"
9
+ t.string "account_number"
10
+ t.string "account_type", default: 'checking'
11
+ t.string "status"
12
+ t.string "last_digits"
13
+ t.string "gateway_customer_profile_id"
14
+ t.string "gateway_payment_profile_id"
15
+
16
+ t.datetime "created_at", null: false
17
+ t.datetime "updated_at", null: false
18
+ t.datetime "deleted_at"
19
+ end
20
+ add_index :spree_payment_methods, :id
21
+ end
22
+ end
@@ -3,6 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "rails-controller-testing"
6
- gem "spree", "~> 3.2.0"
6
+ gem "spree", "~> 4.1.0"
7
7
 
8
8
  gemspec path: "../"
@@ -3,6 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "rails-controller-testing"
6
- gem "spree", "~> 3.5.0"
6
+ gem "spree", "~> 4.2.0.beta"
7
7
 
8
8
  gemspec path: "../"
@@ -1,6 +1,19 @@
1
1
  module ActiveMerchant
2
2
  module Billing
3
3
  module StripeGatewayDecorator
4
+ def verify(source, **options)
5
+ customer = source.gateway_customer_profile_id
6
+ bank_account_token = source.gateway_payment_profile_id
7
+
8
+ commit(:post, "customers/#{CGI.escape(customer)}/sources/#{bank_account_token}/verify", amounts: options[:amounts])
9
+ end
10
+
11
+ def retrieve(source, **options)
12
+ customer = source.gateway_customer_profile_id
13
+ bank_account_token = source.gateway_payment_profile_id
14
+ commit(:get, "customers/#{CGI.escape(customer)}/bank_accounts/#{bank_account_token}")
15
+ end
16
+
4
17
  private
5
18
 
6
19
  def headers(options = {})
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class ApplePayDomainVerificationController < Spree::BaseController
2
+ class ApplePayDomainVerificationController < ::ActionController::Base
3
3
  def show
4
4
  gateway = Spree::Gateway::StripeApplePayGateway.active.last
5
5
 
@@ -32,6 +32,7 @@ module SpreeGateway
32
32
  app.config.spree.payment_methods << Spree::Gateway::StripeGateway
33
33
  app.config.spree.payment_methods << Spree::Gateway::StripeElementsGateway
34
34
  app.config.spree.payment_methods << Spree::Gateway::StripeApplePayGateway
35
+ app.config.spree.payment_methods << Spree::Gateway::StripeAchGateway
35
36
  app.config.spree.payment_methods << Spree::Gateway::UsaEpayTransaction
36
37
  app.config.spree.payment_methods << Spree::Gateway::Worldpay
37
38
  end
@@ -1,5 +1,5 @@
1
1
  module SpreeGateway
2
2
  def self.version
3
- '3.7.1'
3
+ '3.8.0'
4
4
  end
5
5
  end
@@ -0,0 +1,86 @@
1
+ <fieldset data-id="bank_transfer">
2
+ <div id="bank_transfer_form<%= payment_method.id %>" class="margint" data-hook>
3
+ <% param_prefix = "payment_source[#{payment_method.id}]" %>
4
+
5
+ <div data-hook="account_holder_name" class="form-group">
6
+ <%= label_tag "account_holder_name#{payment_method.id}", raw(Spree.t('stripe.ach.account_holder_name') + required_span_tag) %>
7
+ <%= text_field_tag "#{param_prefix}[account_holder_name]", '', class: 'required form-control', id: "account_holder_name#{payment_method.id}" %>
8
+ </div>
9
+
10
+ <div data-hook="account_holder_type">
11
+ <%= label_tag "account_holder_type#{payment_method.id}", raw(Spree.t('stripe.ach.account_holder_type') + required_span_tag) %>
12
+ <%= select_tag "#{param_prefix}[account_holder_type]", options_for_select(%w(Individual Company)), {id: "account_holder_type#{payment_method.id}", class: 'required form-control'} %>
13
+ </div>
14
+
15
+ <div data-hook="routing_number">
16
+ <%= label_tag "routing_number#{payment_method.id}", raw(Spree.t('stripe.ach.routing_number') + required_span_tag)%>
17
+ <%= text_field_tag "#{param_prefix}[routing_number]", '', class: 'required form-control', id: "routing_number#{payment_method.id}", maxlength: 9 %>
18
+ </div>
19
+ <div data-hook="account_number">
20
+ <%= label_tag "account_number#{payment_method.id}", raw(Spree.t('stripe.ach.account_number') + required_span_tag) %>
21
+ <%= text_field_tag "#{param_prefix}[account_number]", '', class: 'required form-control', id: "account_number#{payment_method.id}" %>
22
+ </div>
23
+ <div data-hook="account_number">
24
+ <%= label_tag "verify_account_number#{payment_method.id}", raw(Spree.t('stripe.ach.verify_account_number') + required_span_tag) %>
25
+ <%= text_field_tag "#{param_prefix}[verify_account_number]", '', class: 'required form-control', id: "verify_account_number#{payment_method.id}" %>
26
+ </div>
27
+ </div>
28
+ </fieldset>
29
+
30
+ <script type="text/javascript" src="https://js.stripe.com/v3/"></script>
31
+ <script type="text/javascript">
32
+ var stripe = Stripe("<%= payment_method.preferred_publishable_key %>");
33
+ </script>
34
+
35
+ <script>
36
+ stripeResponseHandler = function(response) {
37
+ var token, paymentMethodId;
38
+ if (response.error) {
39
+ $('#stripeError').html(response.error.message);
40
+ const param_map = {
41
+ account_holder_name: '#account_holder_name',
42
+ account_holder_type: '#account_holder_type',
43
+ account_number: '#account_number',
44
+ routing_number: '#routing_number'
45
+ }
46
+ if (response.error.param){
47
+ errorField = Spree.stripePaymentMethod.find(param_map[response.error.param])
48
+ errorField.addClass('error');
49
+ errorField.parent().addClass('has-error');
50
+ }
51
+ return $('#stripeError').show();
52
+ } else {
53
+ Spree.stripePaymentMethod.find('#account_holder_name, #account_holder_type, #account_number, #routing_number').prop("disabled", true);
54
+ token = response.token['id'];
55
+ paymentMethodId = Spree.stripePaymentMethod.prop('id').split("_")[2];
56
+ Spree.stripePaymentMethod.append("<input type='hidden' class='stripeToken' name='payment_source[" + paymentMethodId + "][gateway_payment_profile_id]' value='" + token + "'/>");
57
+ return Spree.stripePaymentMethod.parents("form").trigger('submit');
58
+ }
59
+ };
60
+
61
+ window.addEventListener('DOMContentLoaded', function() {
62
+ Spree.stripePaymentMethod = $('#payment_method_' + <%= payment_method.id %>);
63
+
64
+ Spree.ready(function() {
65
+ Spree.stripePaymentMethod.prepend("<div id='stripeError' class='errorExplanation alert alert-danger' style='display:none'></div>");
66
+ return $('#new_payment [data-hook=buttons]').click(function() {
67
+ var params;
68
+ $('#stripeError').hide();
69
+ Spree.stripePaymentMethod.find('#account_holder_name, #account_holder_type, #account_number, #routing_number').removeClass('error');
70
+ if (Spree.stripePaymentMethod.is(':visible')) {
71
+ params = $.extend({
72
+ country: 'US',
73
+ currency: 'usd',
74
+ account_holder_name: $('.account_holder_name:visible').val(),
75
+ account_holder_type: $('.account_holder_type:visible').val(),
76
+ routing_number: $('.routing_number:visible').val(),
77
+ account_number: $('.account_number:visible').val()
78
+ }, Spree.stripeAdditionalInfo);
79
+ stripe.createToken('bank_account', params).then(stripeResponseHandler);
80
+ return false;
81
+ }
82
+ });
83
+ });
84
+ });
85
+ </script>
86
+