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.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +12 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github_changelog_generator +2 -0
  5. data/.gitignore +20 -11
  6. data/.rspec +1 -1
  7. data/.rubocop.yml +79 -0
  8. data/CHANGELOG.md +178 -18
  9. data/Gemfile +31 -23
  10. data/LICENSE +26 -0
  11. data/README.md +387 -26
  12. data/Rakefile +4 -19
  13. data/app/assets/config/solidus_braintree_manifest.js +1 -0
  14. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_280x48.svg +19 -0
  15. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_320x48.svg +19 -0
  16. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_375x48.svg +19 -0
  17. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_280x48.svg +19 -0
  18. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_320x48.svg +19 -0
  19. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_375x48.svg +19 -0
  20. data/app/assets/images/solidus_braintree/venmo/venmo_blue_acceptance_mark.svg +15 -0
  21. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_280x48.svg +19 -0
  22. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_320x48.svg +19 -0
  23. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_375x48.svg +19 -0
  24. data/app/assets/images/solidus_braintree/venmo/venmo_blue_logo.svg +18 -0
  25. data/app/assets/images/solidus_braintree/venmo/venmo_white_acceptance_mark.svg +20 -0
  26. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_280x48.svg +19 -0
  27. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_320x48.svg +19 -0
  28. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_375x48.svg +19 -0
  29. data/app/assets/images/solidus_braintree/venmo/venmo_white_logo.svg +18 -0
  30. data/app/assets/javascripts/solidus_braintree/apple_pay_button.js +179 -0
  31. data/app/assets/javascripts/solidus_braintree/checkout.js +108 -0
  32. data/app/assets/javascripts/solidus_braintree/client.js +239 -0
  33. data/app/assets/javascripts/solidus_braintree/constants.js +89 -0
  34. data/app/assets/javascripts/solidus_braintree/frontend.js +14 -0
  35. data/app/assets/javascripts/solidus_braintree/hosted_form.js +46 -0
  36. data/app/assets/javascripts/solidus_braintree/paypal_button.js +178 -0
  37. data/app/assets/javascripts/solidus_braintree/paypal_messaging.js +22 -0
  38. data/app/assets/javascripts/solidus_braintree/promise.js +20 -0
  39. data/app/assets/javascripts/solidus_braintree/venmo_button.js +86 -0
  40. data/app/assets/javascripts/spree/backend/solidus_braintree.js +96 -0
  41. data/app/assets/javascripts/spree/frontend/paypal_button.js +34 -0
  42. data/app/assets/javascripts/spree/frontend/solidus_braintree.js +1 -0
  43. data/app/assets/stylesheets/spree/backend/solidus_braintree.scss +28 -0
  44. data/app/assets/stylesheets/spree/frontend/solidus_braintree.scss +51 -0
  45. data/app/decorators/controllers/solidus_braintree/admin_payments_controller_decorator.rb +11 -0
  46. data/app/decorators/controllers/solidus_braintree/checkout_controller_decorator.rb +11 -0
  47. data/app/decorators/controllers/solidus_braintree/client_tokens_controller.rb +41 -0
  48. data/app/decorators/controllers/solidus_braintree/orders_controller_decorator.rb +11 -0
  49. data/app/decorators/models/solidus_braintree/spree/store_decorator.rb +20 -0
  50. data/app/decorators/models/solidus_braintree/spree/user_decorator.rb +13 -0
  51. data/app/helpers/solidus_braintree/braintree_admin_helper.rb +23 -0
  52. data/app/helpers/solidus_braintree/braintree_checkout_helper.rb +60 -0
  53. data/app/models/application_record.rb +5 -0
  54. data/app/models/solidus_braintree/address.rb +64 -0
  55. data/app/models/solidus_braintree/avs_result.rb +69 -0
  56. data/app/models/solidus_braintree/configuration.rb +39 -0
  57. data/app/models/solidus_braintree/customer.rb +8 -0
  58. data/app/models/solidus_braintree/gateway.rb +433 -0
  59. data/app/models/solidus_braintree/response.rb +80 -0
  60. data/app/models/solidus_braintree/source.rb +135 -0
  61. data/app/models/solidus_braintree/transaction.rb +31 -0
  62. data/app/models/solidus_braintree/transaction_address.rb +88 -0
  63. data/app/models/solidus_braintree/transaction_import.rb +98 -0
  64. data/app/overrides/spree/payments/payment/add_paypal_funding_source_to_payment.rb +9 -0
  65. data/app/views/spree/api/payments/source_views/_braintree.json.jbuilder +1 -1
  66. data/app/views/spree/checkout/existing_payment/_braintree.html.erb +10 -0
  67. data/app/views/spree/shared/_apple_pay_button.html.erb +27 -0
  68. data/app/views/spree/shared/_braintree_errors.html.erb +16 -0
  69. data/app/views/spree/shared/_braintree_head_scripts.html.erb +26 -0
  70. data/app/views/spree/shared/_braintree_hosted_fields.html.erb +43 -0
  71. data/app/views/spree/shared/_paypal_cart_button.html.erb +38 -0
  72. data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
  73. data/app/views/spree/shared/_venmo_button.html.erb +33 -0
  74. data/bin/console +4 -1
  75. data/bin/rails +5 -5
  76. data/bin/rails-engine +13 -0
  77. data/bin/rails-sandbox +16 -0
  78. data/bin/rake +7 -0
  79. data/bin/sandbox +103 -0
  80. data/bin/setup +5 -4
  81. data/config/locales/en.yml +94 -2
  82. data/config/locales/it.yml +56 -0
  83. data/config/routes.rb +12 -3
  84. data/db/migrate/20160830061749_create_solidus_paypal_braintree_sources.rb +16 -0
  85. data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +13 -0
  86. data/db/migrate/20161114231422_create_solidus_paypal_braintree_configurations.rb +11 -0
  87. data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +7 -0
  88. data/db/migrate/20170203191030_add_credit_card_to_braintree_configuration.rb +6 -0
  89. data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +38 -0
  90. data/db/migrate/20170508085402_add_not_null_constraint_to_sources_payment_type.rb +14 -0
  91. data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
  92. data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
  93. data/db/migrate/20211222170950_add_paypal_funding_source_to_solidus_paypal_braintree_sources.rb +5 -0
  94. data/db/migrate/20220104150301_add_venmo_to_braintree_configuration.rb +5 -0
  95. data/db/migrate/20230109080950_rename_solidus_paypal_braintree_source_type.rb +31 -0
  96. data/lib/controllers/backend/solidus_braintree/configurations_controller.rb +48 -0
  97. data/lib/controllers/frontend/solidus_braintree/checkouts_controller.rb +31 -0
  98. data/lib/controllers/frontend/solidus_braintree/transactions_controller.rb +67 -0
  99. data/lib/generators/solidus_braintree/install/install_generator.rb +54 -18
  100. data/lib/generators/solidus_braintree/install/templates/initializer.rb +6 -0
  101. data/lib/solidus_braintree/country_mapper.rb +37 -0
  102. data/lib/solidus_braintree/engine.rb +55 -10
  103. data/lib/solidus_braintree/extension_configuration.rb +23 -0
  104. data/lib/solidus_braintree/request_protection.rb +21 -0
  105. data/lib/solidus_braintree/testing_support/factories.rb +53 -0
  106. data/lib/solidus_braintree/version.rb +3 -1
  107. data/lib/solidus_braintree.rb +14 -2
  108. data/lib/solidus_paypal_braintree.rb +6 -0
  109. data/lib/views/backend/solidus_braintree/configurations/list.html.erb +63 -0
  110. data/lib/views/backend/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
  111. data/lib/views/backend/spree/admin/payments/source_views/_braintree.html.erb +39 -0
  112. data/lib/views/backend/spree/admin/shared/preference_fields/_preference_select.html.erb +13 -0
  113. data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
  114. data/lib/views/backend_v2.4/spree/admin/shared/preference_fields/_hash.html.erb +12 -0
  115. data/lib/views/frontend/solidus_braintree/payments/_payment.html.erb +12 -0
  116. data/lib/views/frontend/spree/checkout/payment/_braintree.html.erb +23 -0
  117. data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +32 -0
  118. data/solidus_braintree.gemspec +39 -38
  119. data/spec/controllers/solidus_braintree/checkouts_controller_spec.rb +99 -0
  120. data/spec/controllers/solidus_braintree/client_tokens_controller_spec.rb +55 -0
  121. data/spec/controllers/solidus_braintree/configurations_controller_spec.rb +73 -0
  122. data/spec/controllers/solidus_braintree/transactions_controller_spec.rb +183 -0
  123. data/spec/features/backend/configuration_spec.rb +23 -0
  124. data/spec/features/backend/new_payment_spec.rb +137 -0
  125. data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +191 -0
  126. data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
  127. data/spec/features/frontend/venmo_checkout_spec.rb +194 -0
  128. data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
  129. data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
  130. data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
  131. data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
  132. data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
  133. data/spec/fixtures/cassettes/braintree/token.yml +63 -0
  134. data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
  135. data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
  136. data/spec/fixtures/cassettes/checkout/update.yml +71 -0
  137. data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +171 -0
  138. data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -0
  139. data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
  140. data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
  141. data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
  142. data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
  143. data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
  144. data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
  145. data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
  146. data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
  147. data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
  148. data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
  149. data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
  150. data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
  151. data/spec/fixtures/cassettes/gateway/customer.yml +79 -0
  152. data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
  153. data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
  154. data/spec/fixtures/cassettes/gateway/void.yml +137 -0
  155. data/spec/fixtures/cassettes/source/bin.yml +295 -0
  156. data/spec/fixtures/cassettes/source/card_type.yml +267 -0
  157. data/spec/fixtures/cassettes/source/last4.yml +267 -0
  158. data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
  159. data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
  160. data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
  161. data/spec/helpers/solidus_braintree/braintree_admin_helper_spec.rb +17 -0
  162. data/spec/helpers/solidus_braintree/braintree_checkout_helper_spec.rb +70 -0
  163. data/spec/models/solidus_braintree/address_spec.rb +71 -0
  164. data/spec/models/solidus_braintree/avs_result_spec.rb +317 -0
  165. data/spec/models/solidus_braintree/gateway_spec.rb +742 -0
  166. data/spec/models/solidus_braintree/response_spec.rb +280 -0
  167. data/spec/models/solidus_braintree/source_spec.rb +539 -0
  168. data/spec/models/solidus_braintree/transaction_address_spec.rb +235 -0
  169. data/spec/models/solidus_braintree/transaction_import_spec.rb +302 -0
  170. data/spec/models/solidus_braintree/transaction_spec.rb +86 -0
  171. data/spec/models/spree/store_spec.rb +14 -0
  172. data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
  173. data/spec/spec_helper.rb +32 -0
  174. data/spec/support/capybara.rb +7 -0
  175. data/spec/support/gateway_helpers.rb +29 -0
  176. data/spec/support/order_ready_for_payment.rb +37 -0
  177. data/spec/support/vcr.rb +42 -0
  178. data/spec/support/views.rb +1 -0
  179. metadata +276 -224
  180. data/LICENSE.txt +0 -21
  181. data/app/controllers/spree/api/braintree_client_token_controller.rb +0 -13
  182. data/app/decorators/lib/solidus_braintree/spree/permitted_attributes_decorator.rb +0 -9
  183. data/app/decorators/models/solidus_braintree/spree/credit_card_decorator.rb +0 -11
  184. data/app/decorators/models/solidus_braintree/spree/payment_decorator.rb +0 -10
  185. data/app/helpers/braintree_view_helpers.rb +0 -20
  186. data/app/models/concerns/solidus_braintree/add_name_validation_concern.rb +0 -8
  187. data/app/models/concerns/solidus_braintree/inject_device_data_concern.rb +0 -18
  188. data/app/models/concerns/solidus_braintree/payment_braintree_nonce_concern.rb +0 -8
  189. data/app/models/concerns/solidus_braintree/permitted_attributes_concern.rb +0 -11
  190. data/app/models/concerns/solidus_braintree/skip_require_card_numbers_concern.rb +0 -14
  191. data/app/models/concerns/solidus_braintree/use_data_field_concern.rb +0 -23
  192. data/app/models/solidus/gateway/braintree_gateway.rb +0 -306
  193. data/app/overrides/spree/checkout/_confirm/braintree_security.html.erb.deface +0 -9
  194. data/app/views/spree/admin/payments/source_forms/_braintree.html.erb +0 -38
  195. data/app/views/spree/admin/payments/source_views/_braintree.html.erb +0 -30
  196. data/app/views/spree/checkout/payment/_braintree.html.erb +0 -55
  197. data/app/views/spree/checkout/payment/_braintree_initialization.html.erb +0 -12
  198. data/config/initializers/braintree.rb +0 -3
  199. data/db/migrate/20150910170527_add_data_to_credit_card.rb +0 -5
  200. data/db/migrate/20160426221931_add_braintree_device_data_to_order.rb +0 -5
  201. data/lib/assets/javascripts/spree/backend/braintree/solidus_braintree.js +0 -59
  202. data/lib/assets/javascripts/spree/frontend/braintree/solidus_braintree.js +0 -144
  203. data/lib/assets/javascripts/vendor/braintree.js +0 -8
  204. data/lib/assets/stylesheets/spree/frontend/solidus_braintree.scss +0 -26
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PermittedAttributesDecorator
4
- def self.prepended(base)
5
- base.singleton_class.prepend SolidusBraintree::PermittedAttributesConcern
6
- end
7
-
8
- Spree::PermittedAttributes.singleton_class.prepend(self)
9
- end
@@ -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,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PaymentDecorator
4
- def self.prepended(base)
5
- base.include SolidusBraintree::PaymentBraintreeNonceConcern
6
- base.include SolidusBraintree::InjectDeviceDataConcern
7
- end
8
-
9
- Spree::Payment.prepend(self)
10
- 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,8 +0,0 @@
1
- module SolidusBraintree
2
- module AddNameValidationConcern
3
- extend ActiveSupport::Concern
4
- included do
5
- validates :name, presence: true, on: :create
6
- end
7
- end
8
- 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,8 +0,0 @@
1
- module SolidusBraintree
2
- module PaymentBraintreeNonceConcern
3
- extend ActiveSupport::Concern
4
- included do
5
- attr_accessor :payment_method_nonce
6
- end
7
- end
8
- end
@@ -1,11 +0,0 @@
1
- module SolidusBraintree
2
- module PermittedAttributesConcern
3
- def payment_attributes
4
- super | [:payment_method_nonce]
5
- end
6
-
7
- def checkout_attributes
8
- super | [:braintree_device_data]
9
- end
10
- end
11
- 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
- &nbsp;
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,3 +0,0 @@
1
- Rails.application.config.to_prepare do
2
- ActionView::Base.include(BraintreeViewHelpers)
3
- end
@@ -1,5 +0,0 @@
1
- class AddDataToCreditCard < SolidusSupport::Migration[4.2]
2
- def change
3
- add_column :spree_credit_cards, :data, :text
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- class AddBraintreeDeviceDataToOrder < SolidusSupport::Migration[4.2]
2
- def change
3
- add_column :spree_orders, :braintree_device_data, :text
4
- end
5
- end
@@ -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
- });