solidus_paypal_braintree 0.4.0 → 1.0.0

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +40 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +18 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +68 -0
  8. data/CHANGELOG.md +258 -0
  9. data/Gemfile +43 -0
  10. data/LICENSE +2 -2
  11. data/README.md +77 -23
  12. data/Rakefile +4 -25
  13. data/app/assets/javascripts/solidus_paypal_braintree/checkout.js +32 -3
  14. data/app/assets/javascripts/solidus_paypal_braintree/client.js +23 -4
  15. data/app/assets/javascripts/solidus_paypal_braintree/constants.js +19 -0
  16. data/app/assets/javascripts/solidus_paypal_braintree/frontend.js +1 -0
  17. data/app/assets/javascripts/solidus_paypal_braintree/hosted_form.js +15 -5
  18. data/app/assets/javascripts/solidus_paypal_braintree/paypal_button.js +47 -20
  19. data/app/assets/javascripts/solidus_paypal_braintree/paypal_messaging.js +22 -0
  20. data/app/decorators/controllers/solidus_paypal_braintree/admin_payments_controller_decorator.rb +11 -0
  21. data/app/decorators/controllers/solidus_paypal_braintree/checkout_controller_decorator.rb +11 -0
  22. data/app/decorators/controllers/solidus_paypal_braintree/client_tokens_controller.rb +41 -0
  23. data/app/decorators/controllers/solidus_paypal_braintree/orders_controller_decorator.rb +11 -0
  24. data/app/decorators/models/solidus_paypal_braintree/spree/store_decorator.rb +20 -0
  25. data/app/decorators/models/solidus_paypal_braintree/spree/user_decorator.rb +13 -0
  26. data/app/helpers/solidus_paypal_braintree/braintree_admin_helper.rb +23 -0
  27. data/app/helpers/solidus_paypal_braintree/braintree_checkout_helper.rb +46 -0
  28. data/app/models/application_record.rb +2 -0
  29. data/app/models/solidus_paypal_braintree/address.rb +30 -0
  30. data/app/models/solidus_paypal_braintree/configuration.rb +26 -3
  31. data/app/models/solidus_paypal_braintree/customer.rb +7 -3
  32. data/app/models/solidus_paypal_braintree/gateway.rb +52 -20
  33. data/app/models/solidus_paypal_braintree/response.rb +3 -2
  34. data/app/models/solidus_paypal_braintree/source.rb +21 -7
  35. data/app/models/solidus_paypal_braintree/transaction.rb +2 -0
  36. data/app/models/solidus_paypal_braintree/transaction_address.rb +30 -12
  37. data/app/models/solidus_paypal_braintree/transaction_import.rb +13 -9
  38. data/app/views/spree/api/payments/source_views/_paypal_braintree.json.jbuilder +3 -0
  39. data/app/views/spree/checkout/existing_payment/_paypal_braintree.html.erb +10 -0
  40. data/app/views/spree/shared/_apple_pay_button.html.erb +2 -2
  41. data/app/views/spree/shared/_braintree_errors.html.erb +11 -17
  42. data/app/views/spree/shared/_braintree_hosted_fields.html.erb +24 -9
  43. data/app/views/spree/shared/_paypal_braintree_head_scripts.html.erb +9 -6
  44. data/app/views/spree/shared/_paypal_cart_button.html.erb +16 -2
  45. data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
  46. data/bin/console +17 -0
  47. data/bin/rails +15 -0
  48. data/bin/setup +8 -0
  49. data/config/locales/en.yml +10 -0
  50. data/config/locales/it.yml +51 -8
  51. data/config/routes.rb +2 -0
  52. data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +3 -1
  53. data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +5 -7
  54. data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +3 -1
  55. data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
  56. data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
  57. data/lib/controllers/backend/solidus_paypal_braintree/configurations_controller.rb +20 -5
  58. data/lib/controllers/frontend/solidus_paypal_braintree/checkouts_controller.rb +25 -21
  59. data/lib/controllers/frontend/solidus_paypal_braintree/transactions_controller.rb +55 -51
  60. data/lib/generators/solidus_paypal_braintree/install/install_generator.rb +7 -5
  61. data/lib/solidus_paypal_braintree.rb +4 -0
  62. data/lib/solidus_paypal_braintree/country_mapper.rb +4 -2
  63. data/lib/solidus_paypal_braintree/engine.rb +11 -11
  64. data/lib/solidus_paypal_braintree/factories.rb +8 -4
  65. data/lib/solidus_paypal_braintree/request_protection.rb +3 -0
  66. data/lib/solidus_paypal_braintree/version.rb +3 -1
  67. data/lib/views/backend/solidus_paypal_braintree/configurations/list.html.erb +30 -5
  68. data/lib/views/backend/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
  69. data/lib/views/backend/spree/admin/payments/source_views/_paypal_braintree.html.erb +2 -2
  70. data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
  71. data/lib/views/frontend/spree/checkout/payment/_paypal_braintree.html.erb +4 -2
  72. data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +30 -0
  73. data/solidus_paypal_braintree.gemspec +42 -0
  74. data/spec/controllers/solidus_paypal_braintree/checkouts_controller_spec.rb +99 -0
  75. data/spec/controllers/solidus_paypal_braintree/client_tokens_controller_spec.rb +55 -0
  76. data/spec/controllers/solidus_paypal_braintree/configurations_controller_spec.rb +73 -0
  77. data/spec/controllers/solidus_paypal_braintree/transactions_controller_spec.rb +183 -0
  78. data/spec/features/backend/configuration_spec.rb +23 -0
  79. data/spec/features/backend/new_payment_spec.rb +137 -0
  80. data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +187 -0
  81. data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
  82. data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
  83. data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
  84. data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
  85. data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
  86. data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
  87. data/spec/fixtures/cassettes/braintree/token.yml +63 -0
  88. data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
  89. data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
  90. data/spec/fixtures/cassettes/checkout/update.yml +71 -0
  91. data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +156 -0
  92. data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
  93. data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
  94. data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
  95. data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
  96. data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
  97. data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
  98. data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
  99. data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
  100. data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
  101. data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
  102. data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
  103. data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
  104. data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
  105. data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
  106. data/spec/fixtures/cassettes/gateway/void.yml +137 -0
  107. data/spec/fixtures/cassettes/source/card_type.yml +267 -0
  108. data/spec/fixtures/cassettes/source/last4.yml +267 -0
  109. data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
  110. data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
  111. data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
  112. data/spec/helpers/solidus_paypal_braintree/braintree_admin_helper_spec.rb +17 -0
  113. data/spec/models/solidus_paypal_braintree/address_spec.rb +51 -0
  114. data/spec/models/solidus_paypal_braintree/avs_result_spec.rb +317 -0
  115. data/spec/models/solidus_paypal_braintree/gateway_spec.rb +692 -0
  116. data/spec/models/solidus_paypal_braintree/response_spec.rb +280 -0
  117. data/spec/models/solidus_paypal_braintree/source_spec.rb +360 -0
  118. data/spec/models/solidus_paypal_braintree/transaction_address_spec.rb +253 -0
  119. data/spec/models/solidus_paypal_braintree/transaction_import_spec.rb +283 -0
  120. data/spec/models/solidus_paypal_braintree/transaction_spec.rb +85 -0
  121. data/spec/models/spree/store_spec.rb +14 -0
  122. data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
  123. data/spec/spec_helper.rb +26 -0
  124. data/spec/support/capybara.rb +7 -0
  125. data/spec/support/factories.rb +2 -0
  126. data/spec/support/gateway_helpers.rb +29 -0
  127. data/spec/support/order_ready_for_payment.rb +37 -0
  128. data/spec/support/vcr.rb +42 -0
  129. data/spec/support/views.rb +1 -0
  130. metadata +182 -194
  131. data/app/controllers/solidus_paypal_braintree/client_tokens_controller.rb +0 -22
  132. data/app/helpers/braintree_admin_helper.rb +0 -18
  133. data/app/models/spree/store_decorator.rb +0 -11
  134. data/app/views/spree/shared/_paypal_checkout_button.html.erb +0 -27
  135. data/config/initializers/braintree.rb +0 -1
@@ -0,0 +1,22 @@
1
+ //= require solidus_paypal_braintree/constants
2
+
3
+ SolidusPaypalBraintree.PaypalMessaging = function(paypalOptions) {
4
+ this._paypalOptions = paypalOptions || {};
5
+
6
+ this._client = null;
7
+ };
8
+
9
+ SolidusPaypalBraintree.PaypalMessaging.prototype.initialize = function() {
10
+ this._client = new SolidusPaypalBraintree.createClient({usePaypal: true});
11
+
12
+ return this._client.initialize().then(this.initializeCallback.bind(this));
13
+ };
14
+
15
+ SolidusPaypalBraintree.PaypalMessaging.prototype.initializeCallback = function() {
16
+ this._paymentMethodId = this._client.paymentMethodId;
17
+
18
+ this._client.getPaypalInstance().loadPayPalSDK({
19
+ currency: this._paypalOptions.currency,
20
+ components: "messages"
21
+ })
22
+ };
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ module AdminPaymentsControllerDecorator
5
+ def self.prepended(base)
6
+ base.helper ::SolidusPaypalBraintree::BraintreeAdminHelper
7
+ end
8
+
9
+ ::Spree::Admin::PaymentsController.prepend(self)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ module CheckoutControllerDecorator
5
+ def self.prepended(base)
6
+ base.helper ::SolidusPaypalBraintree::BraintreeCheckoutHelper
7
+ end
8
+
9
+ ::Spree::CheckoutController.prepend(self)
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ class ClientTokensController < ::Spree::Api::BaseController
5
+ skip_before_action :authenticate_user
6
+
7
+ before_action :load_gateway
8
+
9
+ def create
10
+ token = @gateway.generate_token
11
+ if token
12
+ render json: { client_token: token, payment_method_id: @gateway.id }
13
+ else
14
+ render json: { error: Gateway::TOKEN_GENERATION_DISABLED_MESSAGE }, status: :unprocessable_entity
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def load_gateway
21
+ if params[:payment_method_id]
22
+ @gateway = ::SolidusPaypalBraintree::Gateway.find(params[:payment_method_id])
23
+ else
24
+ store_payment_methods_scope =
25
+ if current_store.payment_methods.empty?
26
+ ::SolidusPaypalBraintree::Gateway.all
27
+ else
28
+ ::SolidusPaypalBraintree::Gateway.where(id: current_store.payment_method_ids)
29
+ end
30
+ @gateway = ::SolidusPaypalBraintree::Gateway.where(active: true).merge(store_payment_methods_scope).first!
31
+ end
32
+ end
33
+
34
+ def generate_token
35
+ @gateway.generate_token
36
+ rescue ::SolidusPaypalBraintree::Gateway::TokenGenerationDisabledError => e
37
+ Rails.logger.error e
38
+ nil
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ module OrdersControllerDecorator
5
+ def self.prepended(base)
6
+ base.helper ::SolidusPaypalBraintree::BraintreeCheckoutHelper
7
+ end
8
+
9
+ ::Spree::OrdersController.prepend(self)
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ module Spree
5
+ module StoreDecorator
6
+ def self.prepended(base)
7
+ base.has_one :braintree_configuration, class_name: "SolidusPaypalBraintree::Configuration", dependent: :destroy
8
+ base.before_create :build_default_configuration
9
+ end
10
+
11
+ private
12
+
13
+ def build_default_configuration
14
+ build_braintree_configuration unless braintree_configuration
15
+ end
16
+
17
+ ::Spree::Store.prepend self
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ module Spree
5
+ module UserDecorator
6
+ def self.prepended(base)
7
+ base.has_one :braintree_customer, class_name: 'SolidusPaypalBraintree::Customer', inverse_of: :user
8
+ end
9
+
10
+ ::Spree.user_class.prepend self
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ module BraintreeAdminHelper
5
+ # Returns a link to the Braintree web UI for the given Braintree payment
6
+ def braintree_transaction_link(payment)
7
+ environment = payment.payment_method.preferred_environment == 'sandbox' ? 'sandbox' : 'www'
8
+ merchant_id = payment.payment_method.preferred_merchant_id
9
+ response_code = payment.response_code
10
+
11
+ return if response_code.blank?
12
+ return response_code if merchant_id.blank?
13
+
14
+ link_to(
15
+ response_code,
16
+ "https://#{environment}.braintreegateway.com/merchants/#{merchant_id}/transactions/#{response_code}",
17
+ title: 'Show payment on Braintree',
18
+ target: '_blank',
19
+ rel: 'noopener'
20
+ )
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ module BraintreeCheckoutHelper
5
+ def braintree_3ds_options_for(order)
6
+ ship_address = order.ship_address
7
+ bill_address = order.bill_address
8
+
9
+ {
10
+ nonce: nil, # populated after tokenization
11
+ bin: nil, # populated after tokenization
12
+ onLookupComplete: nil, # populated after tokenization
13
+ amount: order.total,
14
+ email: order.email,
15
+ billingAddress: {
16
+ givenName: bill_address.firstname,
17
+ surname: bill_address.lastname,
18
+ phoneNumber: bill_address.phone,
19
+ streetAddress: bill_address.address1,
20
+ extendedAddress: bill_address.address2,
21
+ locality: bill_address.city,
22
+ region: bill_address.state&.name,
23
+ postalCode: bill_address.zipcode,
24
+ countryCodeAlpha2: bill_address.country&.iso,
25
+ },
26
+ additionalInformation: {
27
+ shippingGivenName: ship_address.firstname,
28
+ shippingSurname: ship_address.lastname,
29
+ shippingPhone: ship_address.phone,
30
+ shippingAddress: {
31
+ streedAddress: ship_address.address1,
32
+ extendedAddress: ship_address.address2,
33
+ locality: ship_address.city,
34
+ region: ship_address.state&.name,
35
+ postalCode: ship_address.zipcode,
36
+ countryCodeAlpha2: ship_address.country&.iso,
37
+ }
38
+ }
39
+ }
40
+ end
41
+
42
+ def paypal_button_preference(key, store:)
43
+ store.braintree_configuration.preferences[key]
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ApplicationRecord < ActiveRecord::Base
2
4
  self.abstract_class = true
3
5
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ class Address
5
+ def initialize(spree_address)
6
+ @spree_address = spree_address
7
+ end
8
+
9
+ def to_json(*_args)
10
+ address_hash = {
11
+ line1: spree_address.address1,
12
+ line2: spree_address.address2,
13
+ city: spree_address.city,
14
+ postalCode: spree_address.zipcode,
15
+ countryCode: spree_address.country.iso,
16
+ phone: spree_address.phone,
17
+ recipientName: spree_address.full_name
18
+ }
19
+
20
+ if ::Spree::Config.address_requires_state && spree_address.country.states_required
21
+ address_hash[:state] = spree_address.state.name
22
+ end
23
+ address_hash.to_json
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :spree_address
29
+ end
30
+ end
@@ -1,5 +1,28 @@
1
- class SolidusPaypalBraintree::Configuration < ApplicationRecord
2
- belongs_to :store, class_name: 'Spree::Store'
1
+ # frozen_string_literal: true
3
2
 
4
- validates :store, presence: true
3
+ module SolidusPaypalBraintree
4
+ class Configuration < ::Spree::Base
5
+ PAYPAL_BUTTON_PREFERENCES = {
6
+ color: { availables: %w[gold blue silver white black], default: 'white' },
7
+ shape: { availables: %w[pill rect], default: 'rect' },
8
+ label: { availables: %w[checkout credit pay buynow paypal installment], default: 'checkout' },
9
+ tagline: { availables: %w[true false], default: 'false' },
10
+ layout: { availables: %w[horizontal vertical], default: 'horizontal' },
11
+ messaging: { availables: %w[true false], default: 'false' }
12
+ }.freeze
13
+
14
+ belongs_to :store, class_name: 'Spree::Store'
15
+
16
+ validates :store, presence: true
17
+
18
+ # Preferences for Paypal button
19
+ PAYPAL_BUTTON_PREFERENCES.each do |name, desc|
20
+ preference_name = "paypal_button_#{name}".to_sym
21
+ attribute_name = "preferred_#{preference_name}".to_sym
22
+
23
+ preference preference_name, :string, default: desc[:default]
24
+
25
+ validates attribute_name, inclusion: desc[:availables]
26
+ end
27
+ end
5
28
  end
@@ -1,4 +1,8 @@
1
- class SolidusPaypalBraintree::Customer < ApplicationRecord
2
- belongs_to :user, class_name: Spree::UserClassHandle.new
3
- has_many :sources, class_name: "SolidusPaypalBraintree::Source", inverse_of: :customer
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusPaypalBraintree
4
+ class Customer < ApplicationRecord
5
+ belongs_to :user, class_name: ::Spree::UserClassHandle.new, optional: true
6
+ has_many :sources, class_name: "SolidusPaypalBraintree::Source", inverse_of: :customer, dependent: :destroy
7
+ end
4
8
  end
@@ -1,22 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'braintree'
2
4
 
3
5
  module SolidusPaypalBraintree
4
6
  class Gateway < ::Spree::PaymentMethod
5
7
  include RequestProtection
6
8
 
9
+ class TokenGenerationDisabledError < StandardError; end
10
+
7
11
  # Error message from Braintree that gets returned by a non voidable transaction
8
- NON_VOIDABLE_STATUS_ERROR_REGEXP = /can only be voided if status is authorized/
12
+ NON_VOIDABLE_STATUS_ERROR_REGEXP = /can only be voided if status is authorized/.freeze
9
13
 
10
14
  TOKEN_GENERATION_DISABLED_MESSAGE = 'Token generation is disabled.' \
11
15
  ' To re-enable set the `token_generation_enabled` preference on the' \
12
- ' gateway to `true`.'.freeze
16
+ ' gateway to `true`.'
13
17
 
14
18
  ALLOWED_BRAINTREE_OPTIONS = [
15
19
  :device_data,
16
20
  :device_session_id,
17
21
  :merchant_account_id,
18
22
  :order_id
19
- ]
23
+ ].freeze
20
24
 
21
25
  VOIDABLE_STATUSES = [
22
26
  Braintree::Transaction::Status::SubmittedForSettlement,
@@ -35,9 +39,22 @@ module SolidusPaypalBraintree
35
39
  preference(:merchant_id, :string, default: nil)
36
40
  preference(:public_key, :string, default: nil)
37
41
  preference(:private_key, :string, default: nil)
42
+ preference(:http_open_timeout, :integer, default: 60)
43
+ preference(:http_read_timeout, :integer, default: 60)
38
44
  preference(:merchant_currency_map, :hash, default: {})
39
45
  preference(:paypal_payee_email_map, :hash, default: {})
40
46
 
47
+ # Which checkout flow to use (vault/checkout)
48
+ preference(:paypal_flow, :string, default: 'vault')
49
+
50
+ # A hash that gets passed to the `style` key when initializing the credit card fields.
51
+ # See https://developers.braintreepayments.com/guides/hosted-fields/styling/javascript/v3
52
+ preference(:credit_card_fields_style, :hash, default: {})
53
+
54
+ # A hash that gets its keys passed to the associated braintree field placeholder tag.
55
+ # Example: { number: "Enter card number", cvv: "Enter CVV", expirationDate: "mm/yy" }
56
+ preference(:placeholder_text, :hash, default: {})
57
+
41
58
  def partial_name
42
59
  "paypal_braintree"
43
60
  end
@@ -57,6 +74,8 @@ module SolidusPaypalBraintree
57
74
  merchant_id: preferred_merchant_id,
58
75
  public_key: preferred_public_key,
59
76
  private_key: preferred_private_key,
77
+ http_open_timeout: preferred_http_open_timeout,
78
+ http_read_timeout: preferred_http_read_timeout,
60
79
  logger: logger
61
80
  }
62
81
  end
@@ -73,7 +92,7 @@ module SolidusPaypalBraintree
73
92
  protected_request do
74
93
  result = braintree.transaction.sale(
75
94
  amount: dollars(money_cents),
76
- **transaction_options(source, gateway_options, true)
95
+ **transaction_options(source, gateway_options, submit_for_settlement: true)
77
96
  )
78
97
 
79
98
  Response.build(result)
@@ -200,7 +219,7 @@ module SolidusPaypalBraintree
200
219
  return if source.token.present? || source.customer.present? || source.nonce.nil?
201
220
 
202
221
  result = braintree.customer.create(customer_profile_params(payment))
203
- fail Spree::Core::GatewayError, result.message unless result.success?
222
+ fail ::Spree::Core::GatewayError, result.message unless result.success?
204
223
 
205
224
  customer = result.customer
206
225
 
@@ -213,12 +232,12 @@ module SolidusPaypalBraintree
213
232
  end
214
233
  end
215
234
 
235
+ # @raise [TokenGenerationDisabledError]
236
+ # If `preferred_token_generation_enabled` is false
237
+ #
216
238
  # @return [String]
217
239
  # The token that should be used along with the Braintree js-client sdk.
218
240
  #
219
- # returns an error message if `preferred_token_generation_enabled` is
220
- # set to false.
221
- #
222
241
  # @example
223
242
  # <script>
224
243
  # var token = #{Spree::Braintree::Gateway.first!.generate_token}
@@ -233,7 +252,10 @@ module SolidusPaypalBraintree
233
252
  # );
234
253
  # </script>
235
254
  def generate_token
236
- return TOKEN_GENERATION_DISABLED_MESSAGE unless preferred_token_generation_enabled
255
+ unless preferred_token_generation_enabled
256
+ raise TokenGenerationDisabledError, TOKEN_GENERATION_DISABLED_MESSAGE
257
+ end
258
+
237
259
  braintree.client_token.generate
238
260
  end
239
261
 
@@ -261,6 +283,12 @@ module SolidusPaypalBraintree
261
283
 
262
284
  private
263
285
 
286
+ # Whether to store this payment method in the PayPal Vault. This only works when the checkout
287
+ # flow is "vault", so make sure to call +super+ if you override it.
288
+ def store_in_vault
289
+ preferred_paypal_flow == 'vault'
290
+ end
291
+
264
292
  def logger
265
293
  Braintree::Configuration.logger.clone.tap do |logger|
266
294
  logger.level = Rails.logger.level
@@ -279,20 +307,24 @@ module SolidusPaypalBraintree
279
307
  JSON.parse(preference_string.gsub("=>", ":"))
280
308
  end
281
309
 
282
- def convert_preference_value(value, type)
310
+ def convert_preference_value(value, type, preference_encryptor = nil)
283
311
  if type == :hash && value.is_a?(String)
284
312
  value = to_hash(value)
285
313
  end
286
- super
314
+ if method(__method__).super_method.arity == 3
315
+ super
316
+ else
317
+ super(value, type)
318
+ end
287
319
  end
288
320
 
289
- def transaction_options(source, options, submit_for_settlement = false)
321
+ def transaction_options(source, options, submit_for_settlement: false)
290
322
  params = options.select do |key, _|
291
323
  ALLOWED_BRAINTREE_OPTIONS.include?(key)
292
324
  end
293
325
 
294
326
  params[:channel] = "Solidus"
295
- params[:options] = { store_in_vault_on_success: true }
327
+ params[:options] = { store_in_vault_on_success: store_in_vault }
296
328
 
297
329
  if submit_for_settlement
298
330
  params[:options][:submit_for_settlement] = true
@@ -349,21 +381,21 @@ module SolidusPaypalBraintree
349
381
  end
350
382
 
351
383
  def merchant_account_for(_source, options)
352
- if options[:currency]
353
- preferred_merchant_currency_map[options[:currency]]
354
- end
384
+ return unless options[:currency]
385
+
386
+ preferred_merchant_currency_map[options[:currency]]
355
387
  end
356
388
 
357
389
  def paypal_payee_email_for(source, options)
358
- if source.paypal?
359
- preferred_paypal_payee_email_map[options[:currency]]
360
- end
390
+ return unless source.paypal?
391
+
392
+ preferred_paypal_payee_email_map[options[:currency]]
361
393
  end
362
394
 
363
395
  def customer_profile_params(payment)
364
396
  params = {}
365
397
 
366
- if payment.source.try(:nonce)
398
+ if store_in_vault && payment.source.try(:nonce)
367
399
  params[:payment_method_nonce] = payment.source.nonce
368
400
  end
369
401