solidus_braintree 1.4.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +12 -0
- data/.gem_release.yml +5 -0
- data/.github_changelog_generator +2 -0
- data/.gitignore +20 -11
- data/.rspec +1 -1
- data/.rubocop.yml +79 -0
- data/CHANGELOG.md +178 -18
- data/Gemfile +31 -23
- data/LICENSE +26 -0
- data/README.md +387 -26
- data/Rakefile +4 -19
- data/app/assets/config/solidus_braintree_manifest.js +1 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_280x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_320x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_375x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_280x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_320x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_375x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_blue_acceptance_mark.svg +15 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_280x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_320x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_375x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_blue_logo.svg +18 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_white_acceptance_mark.svg +20 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_white_button_280x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_white_button_320x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_white_button_375x48.svg +19 -0
- data/app/assets/images/solidus_braintree/venmo/venmo_white_logo.svg +18 -0
- data/app/assets/javascripts/solidus_braintree/apple_pay_button.js +179 -0
- data/app/assets/javascripts/solidus_braintree/checkout.js +108 -0
- data/app/assets/javascripts/solidus_braintree/client.js +239 -0
- data/app/assets/javascripts/solidus_braintree/constants.js +89 -0
- data/app/assets/javascripts/solidus_braintree/frontend.js +14 -0
- data/app/assets/javascripts/solidus_braintree/hosted_form.js +46 -0
- data/app/assets/javascripts/solidus_braintree/paypal_button.js +178 -0
- data/app/assets/javascripts/solidus_braintree/paypal_messaging.js +22 -0
- data/app/assets/javascripts/solidus_braintree/promise.js +20 -0
- data/app/assets/javascripts/solidus_braintree/venmo_button.js +86 -0
- data/app/assets/javascripts/spree/backend/solidus_braintree.js +96 -0
- data/app/assets/javascripts/spree/frontend/paypal_button.js +34 -0
- data/app/assets/javascripts/spree/frontend/solidus_braintree.js +1 -0
- data/app/assets/stylesheets/spree/backend/solidus_braintree.scss +28 -0
- data/app/assets/stylesheets/spree/frontend/solidus_braintree.scss +51 -0
- data/app/decorators/controllers/solidus_braintree/admin_payments_controller_decorator.rb +11 -0
- data/app/decorators/controllers/solidus_braintree/checkout_controller_decorator.rb +11 -0
- data/app/decorators/controllers/solidus_braintree/client_tokens_controller.rb +41 -0
- data/app/decorators/controllers/solidus_braintree/orders_controller_decorator.rb +11 -0
- data/app/decorators/models/solidus_braintree/spree/store_decorator.rb +20 -0
- data/app/decorators/models/solidus_braintree/spree/user_decorator.rb +13 -0
- data/app/helpers/solidus_braintree/braintree_admin_helper.rb +23 -0
- data/app/helpers/solidus_braintree/braintree_checkout_helper.rb +60 -0
- data/app/models/application_record.rb +5 -0
- data/app/models/solidus_braintree/address.rb +64 -0
- data/app/models/solidus_braintree/avs_result.rb +69 -0
- data/app/models/solidus_braintree/configuration.rb +39 -0
- data/app/models/solidus_braintree/customer.rb +8 -0
- data/app/models/solidus_braintree/gateway.rb +433 -0
- data/app/models/solidus_braintree/response.rb +80 -0
- data/app/models/solidus_braintree/source.rb +135 -0
- data/app/models/solidus_braintree/transaction.rb +31 -0
- data/app/models/solidus_braintree/transaction_address.rb +88 -0
- data/app/models/solidus_braintree/transaction_import.rb +98 -0
- data/app/overrides/spree/payments/payment/add_paypal_funding_source_to_payment.rb +9 -0
- data/app/views/spree/api/payments/source_views/_braintree.json.jbuilder +1 -1
- data/app/views/spree/checkout/existing_payment/_braintree.html.erb +10 -0
- data/app/views/spree/shared/_apple_pay_button.html.erb +27 -0
- data/app/views/spree/shared/_braintree_errors.html.erb +16 -0
- data/app/views/spree/shared/_braintree_head_scripts.html.erb +26 -0
- data/app/views/spree/shared/_braintree_hosted_fields.html.erb +43 -0
- data/app/views/spree/shared/_paypal_cart_button.html.erb +38 -0
- data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
- data/app/views/spree/shared/_venmo_button.html.erb +33 -0
- data/bin/console +4 -1
- data/bin/rails +5 -5
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +16 -0
- data/bin/rake +7 -0
- data/bin/sandbox +103 -0
- data/bin/setup +5 -4
- data/config/locales/en.yml +94 -2
- data/config/locales/it.yml +56 -0
- data/config/routes.rb +12 -3
- data/db/migrate/20160830061749_create_solidus_paypal_braintree_sources.rb +16 -0
- data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +13 -0
- data/db/migrate/20161114231422_create_solidus_paypal_braintree_configurations.rb +11 -0
- data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +7 -0
- data/db/migrate/20170203191030_add_credit_card_to_braintree_configuration.rb +6 -0
- data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +38 -0
- data/db/migrate/20170508085402_add_not_null_constraint_to_sources_payment_type.rb +14 -0
- data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
- data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
- data/db/migrate/20211222170950_add_paypal_funding_source_to_solidus_paypal_braintree_sources.rb +5 -0
- data/db/migrate/20220104150301_add_venmo_to_braintree_configuration.rb +5 -0
- data/db/migrate/20230109080950_rename_solidus_paypal_braintree_source_type.rb +31 -0
- data/lib/controllers/backend/solidus_braintree/configurations_controller.rb +48 -0
- data/lib/controllers/frontend/solidus_braintree/checkouts_controller.rb +31 -0
- data/lib/controllers/frontend/solidus_braintree/transactions_controller.rb +67 -0
- data/lib/generators/solidus_braintree/install/install_generator.rb +54 -18
- data/lib/generators/solidus_braintree/install/templates/initializer.rb +6 -0
- data/lib/solidus_braintree/country_mapper.rb +37 -0
- data/lib/solidus_braintree/engine.rb +55 -10
- data/lib/solidus_braintree/extension_configuration.rb +23 -0
- data/lib/solidus_braintree/request_protection.rb +21 -0
- data/lib/solidus_braintree/testing_support/factories.rb +53 -0
- data/lib/solidus_braintree/version.rb +3 -1
- data/lib/solidus_braintree.rb +14 -2
- data/lib/solidus_paypal_braintree.rb +6 -0
- data/lib/views/backend/solidus_braintree/configurations/list.html.erb +63 -0
- data/lib/views/backend/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
- data/lib/views/backend/spree/admin/payments/source_views/_braintree.html.erb +39 -0
- data/lib/views/backend/spree/admin/shared/preference_fields/_preference_select.html.erb +13 -0
- data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
- data/lib/views/backend_v2.4/spree/admin/shared/preference_fields/_hash.html.erb +12 -0
- data/lib/views/frontend/solidus_braintree/payments/_payment.html.erb +12 -0
- data/lib/views/frontend/spree/checkout/payment/_braintree.html.erb +23 -0
- data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +32 -0
- data/solidus_braintree.gemspec +39 -38
- data/spec/controllers/solidus_braintree/checkouts_controller_spec.rb +99 -0
- data/spec/controllers/solidus_braintree/client_tokens_controller_spec.rb +55 -0
- data/spec/controllers/solidus_braintree/configurations_controller_spec.rb +73 -0
- data/spec/controllers/solidus_braintree/transactions_controller_spec.rb +183 -0
- data/spec/features/backend/configuration_spec.rb +23 -0
- data/spec/features/backend/new_payment_spec.rb +137 -0
- data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +191 -0
- data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
- data/spec/features/frontend/venmo_checkout_spec.rb +194 -0
- data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
- data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
- data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
- data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
- data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
- data/spec/fixtures/cassettes/braintree/token.yml +63 -0
- data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
- data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
- data/spec/fixtures/cassettes/checkout/update.yml +71 -0
- data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +171 -0
- data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -0
- data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
- data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
- data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
- data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
- data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
- data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
- data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
- data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
- data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
- data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
- data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
- data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
- data/spec/fixtures/cassettes/gateway/customer.yml +79 -0
- data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
- data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
- data/spec/fixtures/cassettes/gateway/void.yml +137 -0
- data/spec/fixtures/cassettes/source/bin.yml +295 -0
- data/spec/fixtures/cassettes/source/card_type.yml +267 -0
- data/spec/fixtures/cassettes/source/last4.yml +267 -0
- data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
- data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
- data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
- data/spec/helpers/solidus_braintree/braintree_admin_helper_spec.rb +17 -0
- data/spec/helpers/solidus_braintree/braintree_checkout_helper_spec.rb +70 -0
- data/spec/models/solidus_braintree/address_spec.rb +71 -0
- data/spec/models/solidus_braintree/avs_result_spec.rb +317 -0
- data/spec/models/solidus_braintree/gateway_spec.rb +742 -0
- data/spec/models/solidus_braintree/response_spec.rb +280 -0
- data/spec/models/solidus_braintree/source_spec.rb +539 -0
- data/spec/models/solidus_braintree/transaction_address_spec.rb +235 -0
- data/spec/models/solidus_braintree/transaction_import_spec.rb +302 -0
- data/spec/models/solidus_braintree/transaction_spec.rb +86 -0
- data/spec/models/spree/store_spec.rb +14 -0
- data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/capybara.rb +7 -0
- data/spec/support/gateway_helpers.rb +29 -0
- data/spec/support/order_ready_for_payment.rb +37 -0
- data/spec/support/vcr.rb +42 -0
- data/spec/support/views.rb +1 -0
- metadata +276 -224
- data/LICENSE.txt +0 -21
- data/app/controllers/spree/api/braintree_client_token_controller.rb +0 -13
- data/app/decorators/lib/solidus_braintree/spree/permitted_attributes_decorator.rb +0 -9
- data/app/decorators/models/solidus_braintree/spree/credit_card_decorator.rb +0 -11
- data/app/decorators/models/solidus_braintree/spree/payment_decorator.rb +0 -10
- data/app/helpers/braintree_view_helpers.rb +0 -20
- data/app/models/concerns/solidus_braintree/add_name_validation_concern.rb +0 -8
- data/app/models/concerns/solidus_braintree/inject_device_data_concern.rb +0 -18
- data/app/models/concerns/solidus_braintree/payment_braintree_nonce_concern.rb +0 -8
- data/app/models/concerns/solidus_braintree/permitted_attributes_concern.rb +0 -11
- data/app/models/concerns/solidus_braintree/skip_require_card_numbers_concern.rb +0 -14
- data/app/models/concerns/solidus_braintree/use_data_field_concern.rb +0 -23
- data/app/models/solidus/gateway/braintree_gateway.rb +0 -306
- data/app/overrides/spree/checkout/_confirm/braintree_security.html.erb.deface +0 -9
- data/app/views/spree/admin/payments/source_forms/_braintree.html.erb +0 -38
- data/app/views/spree/admin/payments/source_views/_braintree.html.erb +0 -30
- data/app/views/spree/checkout/payment/_braintree.html.erb +0 -55
- data/app/views/spree/checkout/payment/_braintree_initialization.html.erb +0 -12
- data/config/initializers/braintree.rb +0 -3
- data/db/migrate/20150910170527_add_data_to_credit_card.rb +0 -5
- data/db/migrate/20160426221931_add_braintree_device_data_to_order.rb +0 -5
- data/lib/assets/javascripts/spree/backend/braintree/solidus_braintree.js +0 -59
- data/lib/assets/javascripts/spree/frontend/braintree/solidus_braintree.js +0 -144
- data/lib/assets/javascripts/vendor/braintree.js +0 -8
- data/lib/assets/stylesheets/spree/frontend/solidus_braintree.scss +0 -26
@@ -1,11 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CreditCardDecorator
|
4
|
-
def self.prepended(base)
|
5
|
-
base.include SolidusBraintree::SkipRequireCardNumbersConcern
|
6
|
-
base.include SolidusBraintree::AddNameValidationConcern
|
7
|
-
base.include SolidusBraintree::UseDataFieldConcern
|
8
|
-
end
|
9
|
-
|
10
|
-
Spree::CreditCard.prepend(self)
|
11
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module BraintreeViewHelpers
|
2
|
-
# Returns a link to the Braintree web UI for the given Braintree +payment_id+
|
3
|
-
# (e.g. from Spree::Payment#response_code), or just the +payment_id+ if
|
4
|
-
# Braintree's merchant ID is not configured or +payment_id+ is blank
|
5
|
-
def braintree_transaction_link(payment_id)
|
6
|
-
env = ENV['BRAINTREE_ENV'] == 'production' ? 'www' : 'sandbox'
|
7
|
-
merchant = ENV['BRAINTREE_MERCHANT_ID']
|
8
|
-
|
9
|
-
if payment_id.present? && merchant.present?
|
10
|
-
link_to(
|
11
|
-
payment_id,
|
12
|
-
"https://#{env}.braintreegateway.com/merchants/#{merchant}/transactions/#{payment_id}",
|
13
|
-
title: 'Show payment on Braintree',
|
14
|
-
target: '_blank'
|
15
|
-
)
|
16
|
-
else
|
17
|
-
payment_id
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module SolidusBraintree
|
2
|
-
module InjectDeviceDataConcern
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
included do
|
5
|
-
prepend(InstanceMethods)
|
6
|
-
end
|
7
|
-
|
8
|
-
module InstanceMethods
|
9
|
-
def gateway_options
|
10
|
-
options = super
|
11
|
-
|
12
|
-
options[:device_data] = order.braintree_device_data if order.braintree_device_data
|
13
|
-
|
14
|
-
options
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module SolidusBraintree
|
2
|
-
module SkipRequireCardNumbersConcern
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
included do
|
5
|
-
prepend(InstanceMethods)
|
6
|
-
end
|
7
|
-
|
8
|
-
module InstanceMethods
|
9
|
-
def require_card_numbers?
|
10
|
-
super && !self.payment_method.kind_of?(Solidus::Gateway::BraintreeGateway)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module SolidusBraintree
|
2
|
-
module UseDataFieldConcern
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
included do
|
5
|
-
prepend(InstanceMethods)
|
6
|
-
end
|
7
|
-
|
8
|
-
module InstanceMethods
|
9
|
-
|
10
|
-
def email
|
11
|
-
data["email"]
|
12
|
-
end
|
13
|
-
|
14
|
-
def display_number
|
15
|
-
cc_type == 'paypal' ? email : super
|
16
|
-
end
|
17
|
-
|
18
|
-
def data
|
19
|
-
super.is_a?(String) ? JSON.parse(super) : super
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,306 +0,0 @@
|
|
1
|
-
require "braintree"
|
2
|
-
|
3
|
-
module Solidus
|
4
|
-
gateway_superclass =
|
5
|
-
if SolidusSupport.solidus_gem_version < Gem::Version.new('2.3.x')
|
6
|
-
::Spree::Gateway
|
7
|
-
else
|
8
|
-
::Spree::PaymentMethod::CreditCard
|
9
|
-
end
|
10
|
-
|
11
|
-
class Gateway::BraintreeGateway < gateway_superclass
|
12
|
-
preference :environment, :string
|
13
|
-
preference :merchant_id, :string
|
14
|
-
preference :public_key, :string
|
15
|
-
preference :private_key, :string
|
16
|
-
preference :always_send_bill_address, :boolean, default: false
|
17
|
-
preference :transmit_shipping_address, :boolean, default: true
|
18
|
-
|
19
|
-
CARD_TYPE_MAPPING = {
|
20
|
-
'American Express' => 'american_express',
|
21
|
-
'Diners Club' => 'diners_club',
|
22
|
-
'Discover' => 'discover',
|
23
|
-
'JCB' => 'jcb',
|
24
|
-
'Laser' => 'laser',
|
25
|
-
'Maestro' => 'maestro',
|
26
|
-
'MasterCard' => 'master',
|
27
|
-
'Solo' => 'solo',
|
28
|
-
'Switch' => 'switch',
|
29
|
-
'Visa' => 'visa',
|
30
|
-
}
|
31
|
-
|
32
|
-
if SolidusSupport.solidus_gem_version < Gem::Version.new('2.3.x')
|
33
|
-
def method_type
|
34
|
-
'braintree'
|
35
|
-
end
|
36
|
-
else
|
37
|
-
def partial_name
|
38
|
-
'braintree'
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def gateway_options
|
43
|
-
{
|
44
|
-
environment: preferred_environment.to_sym,
|
45
|
-
merchant_id: preferred_merchant_id,
|
46
|
-
public_key: preferred_public_key,
|
47
|
-
private_key: preferred_private_key,
|
48
|
-
logger: ::Braintree::Configuration.logger.clone,
|
49
|
-
}
|
50
|
-
end
|
51
|
-
|
52
|
-
def braintree_gateway
|
53
|
-
@braintree_gateway ||= ::Braintree::Gateway.new(gateway_options)
|
54
|
-
end
|
55
|
-
|
56
|
-
def payment_profiles_supported?
|
57
|
-
true
|
58
|
-
end
|
59
|
-
|
60
|
-
def generate_client_token(options = {})
|
61
|
-
braintree_gateway.client_token.generate(options)
|
62
|
-
end
|
63
|
-
|
64
|
-
def create_profile(payment)
|
65
|
-
source = payment.source
|
66
|
-
|
67
|
-
return if source.gateway_customer_profile_id.present? || payment.payment_method_nonce.nil?
|
68
|
-
|
69
|
-
user = payment.order.user
|
70
|
-
email = user ? user.email : payment.order.email
|
71
|
-
address = (payment.source.address || payment.order.bill_address).try(:active_merchant_hash)
|
72
|
-
|
73
|
-
params = {
|
74
|
-
first_name: source.first_name,
|
75
|
-
last_name: source.last_name,
|
76
|
-
email: email,
|
77
|
-
credit_card: {
|
78
|
-
cardholder_name: source.name,
|
79
|
-
billing_address: map_address(address),
|
80
|
-
payment_method_nonce: payment.payment_method_nonce,
|
81
|
-
options: {
|
82
|
-
verify_card: true,
|
83
|
-
},
|
84
|
-
},
|
85
|
-
device_data: payment.order.braintree_device_data
|
86
|
-
}
|
87
|
-
|
88
|
-
result = braintree_gateway.customer.create(params)
|
89
|
-
|
90
|
-
if result.success?
|
91
|
-
card = result.customer.payment_methods.last
|
92
|
-
source.tap do |solidus_cc|
|
93
|
-
if card.is_a?(::Braintree::PayPalAccount)
|
94
|
-
solidus_cc.cc_type = 'paypal'
|
95
|
-
data = {
|
96
|
-
email: card.email
|
97
|
-
}
|
98
|
-
solidus_cc.data = data.to_json
|
99
|
-
else
|
100
|
-
solidus_cc.name = card.cardholder_name
|
101
|
-
solidus_cc.cc_type = CARD_TYPE_MAPPING[card.card_type]
|
102
|
-
solidus_cc.month = card.expiration_month
|
103
|
-
solidus_cc.year = card.expiration_year
|
104
|
-
solidus_cc.last_digits = card.last_4
|
105
|
-
end
|
106
|
-
solidus_cc.payment_method = self
|
107
|
-
solidus_cc.gateway_customer_profile_id = result.customer.id
|
108
|
-
solidus_cc.gateway_payment_profile_id = card.token
|
109
|
-
end
|
110
|
-
source.save!
|
111
|
-
else
|
112
|
-
raise ::Spree::Core::GatewayError, result.message
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def supports?(payment)
|
117
|
-
true
|
118
|
-
end
|
119
|
-
|
120
|
-
def provider_class
|
121
|
-
self
|
122
|
-
end
|
123
|
-
|
124
|
-
def authorize(cents, creditcard, options = {})
|
125
|
-
result = braintree_gateway.transaction.sale(transaction_authorize_or_purchase_params(cents, creditcard, options))
|
126
|
-
handle_result(result)
|
127
|
-
end
|
128
|
-
|
129
|
-
def purchase(cents, creditcard, options = {})
|
130
|
-
params = transaction_authorize_or_purchase_params(cents, creditcard, options)
|
131
|
-
params[:options][:submit_for_settlement] = true
|
132
|
-
result = braintree_gateway.transaction.sale(params)
|
133
|
-
handle_result(result)
|
134
|
-
end
|
135
|
-
|
136
|
-
def capture(money, authorization_code, options = {})
|
137
|
-
result = braintree_gateway.transaction.submit_for_settlement(authorization_code, amount(money))
|
138
|
-
handle_result(result)
|
139
|
-
end
|
140
|
-
|
141
|
-
def void(authorization_code, source = {}, options = {})
|
142
|
-
# Allows voiding payments that are in a checkout state
|
143
|
-
if authorization_code.nil?
|
144
|
-
# Fake response since we don't need to void anything with Braintree
|
145
|
-
ActiveMerchant::Billing::Response.new(
|
146
|
-
true,
|
147
|
-
"OK",
|
148
|
-
{},
|
149
|
-
{}
|
150
|
-
)
|
151
|
-
else
|
152
|
-
result = braintree_gateway.transaction.void(authorization_code)
|
153
|
-
handle_result(result)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def credit(cents, source, authorization_code, options = {})
|
158
|
-
result = braintree_gateway.transaction.refund(authorization_code, amount(cents))
|
159
|
-
handle_result(result)
|
160
|
-
end
|
161
|
-
|
162
|
-
def voidable?(response_code)
|
163
|
-
transaction = braintree_gateway.transaction.find(response_code)
|
164
|
-
[
|
165
|
-
::Braintree::Transaction::Status::SubmittedForSettlement,
|
166
|
-
::Braintree::Transaction::Status::Authorized,
|
167
|
-
].include?(transaction.status)
|
168
|
-
end
|
169
|
-
|
170
|
-
def card_number_placeholder
|
171
|
-
'4141 4141 4141 4141'
|
172
|
-
end
|
173
|
-
|
174
|
-
def expiration_date_placeholder
|
175
|
-
'01/2020'
|
176
|
-
end
|
177
|
-
|
178
|
-
def card_code_placeholder
|
179
|
-
'123'
|
180
|
-
end
|
181
|
-
|
182
|
-
def cancel(response)
|
183
|
-
if voidable?(response)
|
184
|
-
void(response)
|
185
|
-
else
|
186
|
-
handle_result(
|
187
|
-
braintree_gateway.transaction.refund(response)
|
188
|
-
)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
private
|
193
|
-
def message_from_result(result)
|
194
|
-
if result.success?
|
195
|
-
"OK"
|
196
|
-
elsif result.errors.count == 0 && result.credit_card_verification
|
197
|
-
"Processor declined: #{result.credit_card_verification.processor_response_text} (#{result.credit_card_verification.processor_response_code})"
|
198
|
-
elsif result.errors.count == 0 && result.transaction
|
199
|
-
result.transaction.status
|
200
|
-
else
|
201
|
-
result.errors.map { |e| "#{e.message} (#{e.code})" }.join(" ")
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def build_results_hash(result)
|
206
|
-
if result.success?
|
207
|
-
{
|
208
|
-
authorization: result.transaction.id,
|
209
|
-
avs_result: {
|
210
|
-
code: result.transaction.avs_street_address_response_code
|
211
|
-
}
|
212
|
-
}
|
213
|
-
else
|
214
|
-
{}
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
def handle_result(result)
|
219
|
-
ActiveMerchant::Billing::Response.new(
|
220
|
-
result.success?,
|
221
|
-
message_from_result(result),
|
222
|
-
{},
|
223
|
-
build_results_hash(result)
|
224
|
-
)
|
225
|
-
end
|
226
|
-
|
227
|
-
def map_address(addr)
|
228
|
-
full_name = addr.fetch(:name, "")
|
229
|
-
*first_name_parts, last_name = full_name.split(" ")
|
230
|
-
first_name = first_name_parts.join(" ")
|
231
|
-
last_name ||= ""
|
232
|
-
|
233
|
-
{
|
234
|
-
first_name: first_name,
|
235
|
-
last_name: last_name,
|
236
|
-
street_address: addr[:address1],
|
237
|
-
extended_address: addr[:address2],
|
238
|
-
locality: addr[:city],
|
239
|
-
region: addr[:state],
|
240
|
-
country_code_alpha2: addr[:country],
|
241
|
-
postal_code: addr[:zip],
|
242
|
-
}
|
243
|
-
end
|
244
|
-
|
245
|
-
def amount(cents)
|
246
|
-
sprintf("%.2f", cents.to_f / 100)
|
247
|
-
end
|
248
|
-
|
249
|
-
def transaction_authorize_or_purchase_params(cents, creditcard, options = {})
|
250
|
-
params = options.select {|k| %i[
|
251
|
-
billing_address_id
|
252
|
-
channel
|
253
|
-
custom_fields
|
254
|
-
descriptor
|
255
|
-
device_data
|
256
|
-
device_session_id
|
257
|
-
merchant_account_id
|
258
|
-
options
|
259
|
-
order_id
|
260
|
-
purchase_order_number
|
261
|
-
recurring
|
262
|
-
service_fee_amount
|
263
|
-
shipping_address_id
|
264
|
-
tax_amount
|
265
|
-
tax_exempt
|
266
|
-
].include?(k)}
|
267
|
-
|
268
|
-
params[:options] ||= {}
|
269
|
-
params[:amount] = amount(cents)
|
270
|
-
params[:channel] ||= "Solidus"
|
271
|
-
if (options[:shipping_address] && preferred_transmit_shipping_address)
|
272
|
-
params[:shipping] = map_address(options[:shipping_address])
|
273
|
-
end
|
274
|
-
|
275
|
-
if options[:payment_method_nonce]
|
276
|
-
params[:payment_method_nonce] = options[:payment_method_nonce]
|
277
|
-
else
|
278
|
-
params[:payment_method_token] = creditcard.gateway_payment_profile_id
|
279
|
-
end
|
280
|
-
|
281
|
-
# Send the bill address if we're using a nonce (i.e. doing a one-time
|
282
|
-
# payment) or if we're configured to always send the bill address
|
283
|
-
if (
|
284
|
-
options[:payment_method_nonce] || preferred_always_send_bill_address
|
285
|
-
) && options[:billing_address]
|
286
|
-
params[:billing] = map_address(options[:billing_address])
|
287
|
-
end
|
288
|
-
|
289
|
-
# if has profile, set the customer_id to the profile_id and delete the customer key
|
290
|
-
if creditcard.try(:gateway_customer_profile_id)
|
291
|
-
params[:customer_id] = creditcard.gateway_customer_profile_id
|
292
|
-
# if no profile, define the customer key, delete the customer_id because they are
|
293
|
-
# mutually exclusive
|
294
|
-
else
|
295
|
-
params[:customer] = {
|
296
|
-
id: options[:customer_id],
|
297
|
-
email: options[:customer],
|
298
|
-
first_name: creditcard.first_name,
|
299
|
-
last_name: creditcard.last_name,
|
300
|
-
}
|
301
|
-
end
|
302
|
-
|
303
|
-
params
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
@@ -1,9 +0,0 @@
|
|
1
|
-
<!-- insert_before "erb[loud]:contains('place_order')" -->
|
2
|
-
|
3
|
-
<%
|
4
|
-
# Currently we assume we only have one braintree
|
5
|
-
# payment method. In practice this should be true and it simplifies the code.
|
6
|
-
braintree_payment = @order.unprocessed_payments.find {|p| p.payment_method.class == Solidus::Gateway::BraintreeGateway }
|
7
|
-
if braintree_payment %>
|
8
|
-
<%= render 'spree/checkout/payment/braintree_initialization', payment_method: braintree_payment.payment_method %>
|
9
|
-
<% end %>
|
@@ -1,38 +0,0 @@
|
|
1
|
-
<fieldset data-id='credit-card' class="no-border-bottom">
|
2
|
-
<div class="field" data-hook="previous_cards">
|
3
|
-
<% if previous_cards.any? %>
|
4
|
-
<% previous_cards.each do |card| %>
|
5
|
-
<label><%= radio_button_tag :card, card.id, card == previous_cards.first %> <%= card.display_number %><br /></label>
|
6
|
-
<% end %>
|
7
|
-
<% end %>
|
8
|
-
<label><%= radio_button_tag :card, 'new', false, { id: "card_new#{payment_method.id}" } %> <%= t('spree.use_new_cc') %></label>
|
9
|
-
</div>
|
10
|
-
|
11
|
-
<div id="card_form<%= payment_method.id %>" data-hook>
|
12
|
-
<% param_prefix = "payment_source[#{payment_method.id}]" %>
|
13
|
-
|
14
|
-
<div class="clear"></div>
|
15
|
-
|
16
|
-
<div class="alpha four columns">
|
17
|
-
<div data-hook="card_name">
|
18
|
-
<div class="field">
|
19
|
-
<%= label_tag "card_name#{payment_method.id}", Spree::CreditCard.human_attribute_name(:name), class: 'required' %>
|
20
|
-
<%= text_field_tag "#{param_prefix}[name]", '', id: "card_name#{payment_method.id}", class: 'required fullwidth', maxlength: 19 %>
|
21
|
-
</div>
|
22
|
-
</div>
|
23
|
-
</div>
|
24
|
-
|
25
|
-
<div id="braintree-dropin"></div>
|
26
|
-
<input type="hidden" id="payment_method_nonce" name="payment[payment_method_nonce]">
|
27
|
-
|
28
|
-
<div class="clear"></div>
|
29
|
-
|
30
|
-
<%= label_tag "card_address#{payment_method.id}", t('spree.billing_address') %>
|
31
|
-
<% address = @order.bill_address || @order.ship_address || Spree::Address.build_default %>
|
32
|
-
<%= fields_for "#{param_prefix}[address_attributes]", address do |f| %>
|
33
|
-
<%= render :partial => 'spree/admin/shared/address_form', :locals => { :f => f, :type => "billing" } %>
|
34
|
-
<% end %>
|
35
|
-
|
36
|
-
<div class="clear"></div>
|
37
|
-
</div>
|
38
|
-
</fieldset>
|
@@ -1,30 +0,0 @@
|
|
1
|
-
<fieldset data-hook="credit_card">
|
2
|
-
<legend align="center"><%= Spree::CreditCard.model_name.human %></legend>
|
3
|
-
|
4
|
-
<div class="row">
|
5
|
-
<div class="alpha six columns">
|
6
|
-
<dl>
|
7
|
-
<dt><%= t('spree.identifier') %>:</dt>
|
8
|
-
<dd><%= payment.number %></dd>
|
9
|
-
|
10
|
-
<dt><%= t('spree.response_code') %>:</dt>
|
11
|
-
<dd><%= braintree_transaction_link(payment.response_code) %></dd>
|
12
|
-
|
13
|
-
<dt><%= t('spree.name_on_card') %>:</dt>
|
14
|
-
<dd><%= payment.source.name %></dd>
|
15
|
-
|
16
|
-
<dt><%= Spree::CreditCard.human_attribute_name(:cc_type) %>:</dt>
|
17
|
-
<dd><%= payment.source.cc_type %></dd>
|
18
|
-
|
19
|
-
<dt><%= Spree::CreditCard.human_attribute_name(:number) %>:</dt>
|
20
|
-
<dd><%= payment.source.display_number %></dd>
|
21
|
-
|
22
|
-
<dt><%= Spree::CreditCard.human_attribute_name(:expiration) %>:</dt>
|
23
|
-
<dd><%= payment.source.month %>/<%= payment.source.year %></dd>
|
24
|
-
</dl>
|
25
|
-
<% if payment.source.address %>
|
26
|
-
<%= render partial: 'spree/admin/shared/address', locals: {address: payment.source.address} %>
|
27
|
-
<% end %>
|
28
|
-
</div>
|
29
|
-
</div>
|
30
|
-
</fieldset>
|
@@ -1,55 +0,0 @@
|
|
1
|
-
<div class="braintree-payment">
|
2
|
-
<%= render 'spree/checkout/payment/braintree_initialization', payment_method: payment_method %>
|
3
|
-
|
4
|
-
<div class="braintree-paypal-input">
|
5
|
-
<div class="braintree-paypal-header">
|
6
|
-
<%= t('solidus_braintree.paypal_header_html') %>
|
7
|
-
</div>
|
8
|
-
<div id="#braintree_paypal_container"></div>
|
9
|
-
</div>
|
10
|
-
|
11
|
-
<div class="braintree-cc-input">
|
12
|
-
<div class="braintree-cc-header">
|
13
|
-
<%= t('solidus_braintree.creditcard_header_html') %>
|
14
|
-
<%= image_tag 'credit_cards/credit_card.gif', :id => 'credit-card-image' %>
|
15
|
-
</div>
|
16
|
-
<% param_prefix = "payment_source[#{payment_method.id}]" %>
|
17
|
-
|
18
|
-
<p class="field">
|
19
|
-
<%= label_tag "name_on_card_#{payment_method.id}", t('spree.name_on_card') %><span class="required">*</span><br />
|
20
|
-
<%= text_field_tag "#{param_prefix}[name]", "#{@order.billing_firstname} #{@order.billing_lastname}", { id: "name_on_card_#{payment_method.id}", :autocomplete => "cc-name" } %>
|
21
|
-
</p>
|
22
|
-
|
23
|
-
<p class="field" data-hook="card_number">
|
24
|
-
<%= label_tag "braintree_card_number", t('spree.card_number') %><span class="required">*</span><br />
|
25
|
-
<label for="braintree_card_number" id="braintree_card_number" class="braintree-hosted-field"></label>
|
26
|
-
|
27
|
-
<span id="card_type" style="display:none;">
|
28
|
-
( <span id="looks_like" ><%= t('spree.card_type_is') %> <span id="type"></span></span>
|
29
|
-
<span id="unrecognized"><%= t('spree.unrecognized_card_type') %></span>
|
30
|
-
)
|
31
|
-
</span>
|
32
|
-
</p>
|
33
|
-
|
34
|
-
<p class="field" data-hook="card_expiration">
|
35
|
-
<%= label_tag "braintree_card_expiry", t('spree.expiration') %><span class="required">*</span><br />
|
36
|
-
<label for="braintree_card_expiry" id="braintree_card_expiry" class="braintree-hosted-field"></label>
|
37
|
-
</p>
|
38
|
-
|
39
|
-
<p class="field" data-hook="card_code">
|
40
|
-
<%= label_tag "braintree_card_code", t('spree.card_code') %><span class="required">*</span><br />
|
41
|
-
|
42
|
-
<label for="braintree_card_code" id="braintree_card_code" class="braintree-hosted-field card-code"></label>
|
43
|
-
<%= link_to "(#{t('spree.what_is_this')})", spree.cvv_path, :target => '_blank', "data-hook" => "cvv_link", :id => "cvv_link" %>
|
44
|
-
</p>
|
45
|
-
</div>
|
46
|
-
|
47
|
-
<% if @order.bill_address %>
|
48
|
-
<%= fields_for "#{param_prefix}[address_attributes]", @order.bill_address do |f| %>
|
49
|
-
<%= render :partial => 'spree/address/form_hidden', :locals => { :form => f } %>
|
50
|
-
<% end %>
|
51
|
-
<% end %>
|
52
|
-
|
53
|
-
<%= hidden_field_tag "#{param_prefix}[cc_type]", '', :id => "cc_type", :class => 'ccType' %>
|
54
|
-
<%= hidden_field_tag "order[payments_attributes][][payment_method_nonce]", '', :id => "payment_method_nonce" %>
|
55
|
-
</div>
|
@@ -1,12 +0,0 @@
|
|
1
|
-
<% content_for :head do %>
|
2
|
-
<%= javascript_tag do %>
|
3
|
-
braintree.environment = "<%= payment_method.preferred_environment %>"
|
4
|
-
braintree.placeholders = {
|
5
|
-
"number": "<%= payment_method.card_number_placeholder %>",
|
6
|
-
"expirationDate": "<%= payment_method.expiration_date_placeholder %>",
|
7
|
-
"cvv": "<%= payment_method.card_code_placeholder %>"
|
8
|
-
}
|
9
|
-
<% end %>
|
10
|
-
<% end %>
|
11
|
-
|
12
|
-
<%= hidden_field_tag "order[braintree_device_data]", '', :id => "device_data" %>
|
@@ -1,59 +0,0 @@
|
|
1
|
-
//= require "vendor/braintree"
|
2
|
-
|
3
|
-
Spree.pathFor.payment_client_token_api = Spree.pathFor("api/payment_client_token")
|
4
|
-
|
5
|
-
var braintreeDropinIntegration;
|
6
|
-
var paymentForm = "#new_payment";
|
7
|
-
var cardSelector = "#new_payment [name=card]";
|
8
|
-
|
9
|
-
var getClientToken = function(onSuccess) {
|
10
|
-
return Spree.ajax({
|
11
|
-
url: Spree.pathFor.payment_client_token_api,
|
12
|
-
type: "POST",
|
13
|
-
data: {
|
14
|
-
payment_method_id: $('form input[type=radio]:checked').val()
|
15
|
-
},
|
16
|
-
error: function(xhr, status) {
|
17
|
-
show_flash("error", xhr.responseJSON.message);
|
18
|
-
},
|
19
|
-
success: function(data) {
|
20
|
-
onSuccess(data);
|
21
|
-
}
|
22
|
-
});
|
23
|
-
};
|
24
|
-
|
25
|
-
var attachDropIn = function(data) {
|
26
|
-
braintree.setup(data.client_token, "dropin", {
|
27
|
-
container: "braintree-dropin",
|
28
|
-
form: "new_payment",
|
29
|
-
onReady: function (integration) {
|
30
|
-
braintreeDropinIntegration = integration;
|
31
|
-
},
|
32
|
-
onError: function(type, message) {
|
33
|
-
show_flash("error", message);
|
34
|
-
},
|
35
|
-
onPaymentMethodReceived: function(obj) {
|
36
|
-
$("#payment_method_nonce").val(obj.nonce);
|
37
|
-
$("#new_payment").submit();
|
38
|
-
return;
|
39
|
-
}
|
40
|
-
});
|
41
|
-
};
|
42
|
-
|
43
|
-
$(document).ready(function() {
|
44
|
-
if ($(paymentForm).length) {
|
45
|
-
if ($(cardSelector).length) {
|
46
|
-
$(cardSelector).on("change", function() {
|
47
|
-
if ($(cardSelector + ":checked").val() === "new") {
|
48
|
-
getClientToken(attachDropIn);
|
49
|
-
} else {
|
50
|
-
if (braintreeDropinIntegration) {
|
51
|
-
braintreeDropinIntegration.teardown();
|
52
|
-
}
|
53
|
-
}
|
54
|
-
});
|
55
|
-
} else {
|
56
|
-
getClientToken(attachDropIn);
|
57
|
-
}
|
58
|
-
}
|
59
|
-
});
|