solidus_braintree 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +47 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +1 -0
  5. data/.github_changelog_generator +2 -0
  6. data/.gitignore +20 -10
  7. data/.rspec +1 -1
  8. data/.rubocop.yml +79 -0
  9. data/CHANGELOG.md +178 -18
  10. data/Gemfile +34 -9
  11. data/LICENSE +26 -0
  12. data/README.md +389 -22
  13. data/Rakefile +4 -19
  14. data/app/assets/config/solidus_braintree_manifest.js +1 -0
  15. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_280x48.svg +19 -0
  16. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_320x48.svg +19 -0
  17. data/app/assets/images/solidus_braintree/venmo/venmo_active_blue_button_375x48.svg +19 -0
  18. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_280x48.svg +19 -0
  19. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_320x48.svg +19 -0
  20. data/app/assets/images/solidus_braintree/venmo/venmo_active_white_button_375x48.svg +19 -0
  21. data/app/assets/images/solidus_braintree/venmo/venmo_blue_acceptance_mark.svg +15 -0
  22. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_280x48.svg +19 -0
  23. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_320x48.svg +19 -0
  24. data/app/assets/images/solidus_braintree/venmo/venmo_blue_button_375x48.svg +19 -0
  25. data/app/assets/images/solidus_braintree/venmo/venmo_blue_logo.svg +18 -0
  26. data/app/assets/images/solidus_braintree/venmo/venmo_white_acceptance_mark.svg +20 -0
  27. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_280x48.svg +19 -0
  28. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_320x48.svg +19 -0
  29. data/app/assets/images/solidus_braintree/venmo/venmo_white_button_375x48.svg +19 -0
  30. data/app/assets/images/solidus_braintree/venmo/venmo_white_logo.svg +18 -0
  31. data/app/assets/javascripts/solidus_braintree/apple_pay_button.js +179 -0
  32. data/app/assets/javascripts/solidus_braintree/checkout.js +108 -0
  33. data/app/assets/javascripts/solidus_braintree/client.js +239 -0
  34. data/app/assets/javascripts/solidus_braintree/constants.js +89 -0
  35. data/app/assets/javascripts/solidus_braintree/frontend.js +14 -0
  36. data/app/assets/javascripts/solidus_braintree/hosted_form.js +46 -0
  37. data/app/assets/javascripts/solidus_braintree/paypal_button.js +178 -0
  38. data/app/assets/javascripts/solidus_braintree/paypal_messaging.js +22 -0
  39. data/app/assets/javascripts/solidus_braintree/promise.js +20 -0
  40. data/app/assets/javascripts/solidus_braintree/venmo_button.js +86 -0
  41. data/app/assets/javascripts/spree/backend/solidus_braintree.js +96 -0
  42. data/app/assets/javascripts/spree/frontend/paypal_button.js +34 -0
  43. data/app/assets/javascripts/spree/frontend/solidus_braintree.js +1 -0
  44. data/app/assets/stylesheets/spree/backend/solidus_braintree.scss +28 -0
  45. data/app/assets/stylesheets/spree/frontend/solidus_braintree.scss +51 -0
  46. data/app/decorators/controllers/solidus_braintree/admin_payments_controller_decorator.rb +11 -0
  47. data/app/decorators/controllers/solidus_braintree/checkout_controller_decorator.rb +11 -0
  48. data/app/decorators/controllers/solidus_braintree/client_tokens_controller.rb +41 -0
  49. data/app/decorators/controllers/solidus_braintree/orders_controller_decorator.rb +11 -0
  50. data/app/decorators/models/solidus_braintree/spree/store_decorator.rb +20 -0
  51. data/app/decorators/models/solidus_braintree/spree/user_decorator.rb +13 -0
  52. data/app/helpers/solidus_braintree/braintree_admin_helper.rb +23 -0
  53. data/app/helpers/solidus_braintree/braintree_checkout_helper.rb +60 -0
  54. data/app/models/application_record.rb +5 -0
  55. data/app/models/solidus_braintree/address.rb +64 -0
  56. data/app/models/solidus_braintree/avs_result.rb +69 -0
  57. data/app/models/solidus_braintree/configuration.rb +39 -0
  58. data/app/models/solidus_braintree/customer.rb +8 -0
  59. data/app/models/solidus_braintree/gateway.rb +433 -0
  60. data/app/models/solidus_braintree/response.rb +80 -0
  61. data/app/models/solidus_braintree/source.rb +135 -0
  62. data/app/models/solidus_braintree/transaction.rb +31 -0
  63. data/app/models/solidus_braintree/transaction_address.rb +88 -0
  64. data/app/models/solidus_braintree/transaction_import.rb +98 -0
  65. data/app/overrides/spree/payments/payment/add_paypal_funding_source_to_payment.rb +9 -0
  66. data/app/views/spree/api/payments/source_views/_braintree.json.jbuilder +3 -0
  67. data/app/views/spree/checkout/existing_payment/_braintree.html.erb +10 -0
  68. data/app/views/spree/shared/_apple_pay_button.html.erb +27 -0
  69. data/app/views/spree/shared/_braintree_errors.html.erb +16 -0
  70. data/app/views/spree/shared/_braintree_head_scripts.html.erb +26 -0
  71. data/app/views/spree/shared/_braintree_hosted_fields.html.erb +43 -0
  72. data/app/views/spree/shared/_paypal_cart_button.html.erb +38 -0
  73. data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
  74. data/app/views/spree/shared/_venmo_button.html.erb +33 -0
  75. data/bin/console +4 -1
  76. data/bin/rails +5 -5
  77. data/bin/rails-engine +13 -0
  78. data/bin/rails-sandbox +16 -0
  79. data/bin/rake +7 -0
  80. data/bin/sandbox +103 -0
  81. data/bin/setup +5 -4
  82. data/config/locales/en.yml +94 -2
  83. data/config/locales/it.yml +56 -0
  84. data/config/routes.rb +12 -3
  85. data/db/migrate/20160830061749_create_solidus_paypal_braintree_sources.rb +16 -0
  86. data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +13 -0
  87. data/db/migrate/20161114231422_create_solidus_paypal_braintree_configurations.rb +11 -0
  88. data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +7 -0
  89. data/db/migrate/20170203191030_add_credit_card_to_braintree_configuration.rb +6 -0
  90. data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +38 -0
  91. data/db/migrate/20170508085402_add_not_null_constraint_to_sources_payment_type.rb +14 -0
  92. data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
  93. data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
  94. data/db/migrate/20211222170950_add_paypal_funding_source_to_solidus_paypal_braintree_sources.rb +5 -0
  95. data/db/migrate/20220104150301_add_venmo_to_braintree_configuration.rb +5 -0
  96. data/db/migrate/20230109080950_rename_solidus_paypal_braintree_source_type.rb +31 -0
  97. data/lib/controllers/backend/solidus_braintree/configurations_controller.rb +48 -0
  98. data/lib/controllers/frontend/solidus_braintree/checkouts_controller.rb +31 -0
  99. data/lib/controllers/frontend/solidus_braintree/transactions_controller.rb +67 -0
  100. data/lib/generators/solidus_braintree/install/install_generator.rb +54 -18
  101. data/lib/generators/solidus_braintree/install/templates/initializer.rb +6 -0
  102. data/lib/solidus_braintree/country_mapper.rb +37 -0
  103. data/lib/solidus_braintree/engine.rb +55 -10
  104. data/lib/solidus_braintree/extension_configuration.rb +23 -0
  105. data/lib/solidus_braintree/request_protection.rb +21 -0
  106. data/lib/solidus_braintree/testing_support/factories.rb +53 -0
  107. data/lib/solidus_braintree/version.rb +3 -1
  108. data/lib/solidus_braintree.rb +15 -2
  109. data/lib/solidus_paypal_braintree.rb +6 -0
  110. data/lib/views/backend/solidus_braintree/configurations/list.html.erb +63 -0
  111. data/lib/views/backend/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
  112. data/lib/views/backend/spree/admin/payments/source_views/_braintree.html.erb +39 -0
  113. data/lib/views/backend/spree/admin/shared/preference_fields/_preference_select.html.erb +13 -0
  114. data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_braintree.html.erb +16 -0
  115. data/lib/views/backend_v2.4/spree/admin/shared/preference_fields/_hash.html.erb +12 -0
  116. data/lib/views/frontend/solidus_braintree/payments/_payment.html.erb +12 -0
  117. data/lib/views/frontend/spree/checkout/payment/_braintree.html.erb +23 -0
  118. data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +32 -0
  119. data/solidus_braintree.gemspec +39 -37
  120. data/spec/controllers/solidus_braintree/checkouts_controller_spec.rb +99 -0
  121. data/spec/controllers/solidus_braintree/client_tokens_controller_spec.rb +55 -0
  122. data/spec/controllers/solidus_braintree/configurations_controller_spec.rb +73 -0
  123. data/spec/controllers/solidus_braintree/transactions_controller_spec.rb +183 -0
  124. data/spec/features/backend/configuration_spec.rb +23 -0
  125. data/spec/features/backend/new_payment_spec.rb +137 -0
  126. data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +191 -0
  127. data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
  128. data/spec/features/frontend/venmo_checkout_spec.rb +194 -0
  129. data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
  130. data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
  131. data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
  132. data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
  133. data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
  134. data/spec/fixtures/cassettes/braintree/token.yml +63 -0
  135. data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
  136. data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
  137. data/spec/fixtures/cassettes/checkout/update.yml +71 -0
  138. data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +171 -0
  139. data/spec/fixtures/cassettes/checkout/valid_venmo_transaction.yml +599 -0
  140. data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
  141. data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
  142. data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
  143. data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
  144. data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
  145. data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
  146. data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
  147. data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
  148. data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
  149. data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
  150. data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
  151. data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
  152. data/spec/fixtures/cassettes/gateway/customer.yml +79 -0
  153. data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
  154. data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
  155. data/spec/fixtures/cassettes/gateway/void.yml +137 -0
  156. data/spec/fixtures/cassettes/source/bin.yml +295 -0
  157. data/spec/fixtures/cassettes/source/card_type.yml +267 -0
  158. data/spec/fixtures/cassettes/source/last4.yml +267 -0
  159. data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
  160. data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
  161. data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
  162. data/spec/helpers/solidus_braintree/braintree_admin_helper_spec.rb +17 -0
  163. data/spec/helpers/solidus_braintree/braintree_checkout_helper_spec.rb +70 -0
  164. data/spec/models/solidus_braintree/address_spec.rb +71 -0
  165. data/spec/models/solidus_braintree/avs_result_spec.rb +317 -0
  166. data/spec/models/solidus_braintree/gateway_spec.rb +742 -0
  167. data/spec/models/solidus_braintree/response_spec.rb +280 -0
  168. data/spec/models/solidus_braintree/source_spec.rb +539 -0
  169. data/spec/models/solidus_braintree/transaction_address_spec.rb +235 -0
  170. data/spec/models/solidus_braintree/transaction_import_spec.rb +302 -0
  171. data/spec/models/solidus_braintree/transaction_spec.rb +86 -0
  172. data/spec/models/spree/store_spec.rb +14 -0
  173. data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
  174. data/spec/spec_helper.rb +32 -0
  175. data/spec/support/capybara.rb +7 -0
  176. data/spec/support/gateway_helpers.rb +29 -0
  177. data/spec/support/order_ready_for_payment.rb +37 -0
  178. data/spec/support/vcr.rb +42 -0
  179. data/spec/support/views.rb +1 -0
  180. metadata +281 -214
  181. data/.travis.yml +0 -18
  182. data/LICENSE.txt +0 -21
  183. data/app/controllers/spree/api/braintree_client_token_controller.rb +0 -13
  184. data/app/helpers/braintree_view_helpers.rb +0 -20
  185. data/app/models/concerns/solidus_braintree/add_name_validation_concern.rb +0 -8
  186. data/app/models/concerns/solidus_braintree/inject_device_data_concern.rb +0 -18
  187. data/app/models/concerns/solidus_braintree/payment_braintree_nonce_concern.rb +0 -8
  188. data/app/models/concerns/solidus_braintree/permitted_attributes_concern.rb +0 -11
  189. data/app/models/concerns/solidus_braintree/skip_require_card_numbers_concern.rb +0 -14
  190. data/app/models/concerns/solidus_braintree/use_data_field_concern.rb +0 -23
  191. data/app/models/credit_card_decorator.rb +0 -3
  192. data/app/models/payment_decorator.rb +0 -2
  193. data/app/models/permitted_attributes_decorator.rb +0 -1
  194. data/app/models/solidus/gateway/braintree_gateway.rb +0 -293
  195. data/app/overrides/spree/checkout/_confirm/braintree_security.html.erb.deface +0 -9
  196. data/app/views/spree/admin/payments/source_forms/_braintree.html.erb +0 -38
  197. data/app/views/spree/admin/payments/source_views/_braintree.html.erb +0 -30
  198. data/app/views/spree/checkout/payment/_braintree.html.erb +0 -55
  199. data/app/views/spree/checkout/payment/_braintree_initialization.html.erb +0 -12
  200. data/config/initializers/braintree.rb +0 -1
  201. data/db/migrate/20150910170527_add_data_to_credit_card.rb +0 -5
  202. data/db/migrate/20160426221931_add_braintree_device_data_to_order.rb +0 -5
  203. data/lib/assets/javascripts/spree/backend/braintree/solidus_braintree.js +0 -59
  204. data/lib/assets/javascripts/spree/frontend/braintree/solidus_braintree.js +0 -144
  205. data/lib/assets/javascripts/vendor/braintree.js +0 -8
  206. data/lib/assets/stylesheets/spree/frontend/solidus_braintree.scss +0 -26
@@ -1,13 +0,0 @@
1
- class Spree::Api::BraintreeClientTokenController < Spree::Api::BaseController
2
- skip_before_action :authenticate_user
3
-
4
- def create
5
- if params[:payment_method_id]
6
- gateway = Solidus::Gateway::BraintreeGateway.find_by!(id: params[:payment_method_id])
7
- else
8
- gateway = Solidus::Gateway::BraintreeGateway.find_by!(active: true)
9
- end
10
-
11
- render json: { client_token: gateway.generate_client_token, payment_method_id: gateway.id }
12
- end
13
- 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,3 +0,0 @@
1
- Spree::CreditCard.include SolidusBraintree::SkipRequireCardNumbersConcern
2
- Spree::CreditCard.include SolidusBraintree::AddNameValidationConcern
3
- Spree::CreditCard.include SolidusBraintree::UseDataFieldConcern
@@ -1,2 +0,0 @@
1
- Spree::Payment.include SolidusBraintree::PaymentBraintreeNonceConcern
2
- Spree::Payment.include SolidusBraintree::InjectDeviceDataConcern
@@ -1 +0,0 @@
1
- Spree::PermittedAttributes.singleton_class.prepend SolidusBraintree::PermittedAttributesConcern
@@ -1,293 +0,0 @@
1
- require "braintree"
2
-
3
- module Solidus
4
- class Gateway::BraintreeGateway < ::Spree::Gateway
5
- preference :environment, :string
6
- preference :merchant_id, :string
7
- preference :public_key, :string
8
- preference :private_key, :string
9
- preference :always_send_bill_address, :boolean, default: false
10
- preference :transmit_shipping_address, :boolean, default: true
11
-
12
- CARD_TYPE_MAPPING = {
13
- 'American Express' => 'american_express',
14
- 'Diners Club' => 'diners_club',
15
- 'Discover' => 'discover',
16
- 'JCB' => 'jcb',
17
- 'Laser' => 'laser',
18
- 'Maestro' => 'maestro',
19
- 'MasterCard' => 'master',
20
- 'Solo' => 'solo',
21
- 'Switch' => 'switch',
22
- 'Visa' => 'visa',
23
- }
24
-
25
- def method_type
26
- 'braintree'
27
- end
28
-
29
- def gateway_options
30
- {
31
- environment: preferred_environment.to_sym,
32
- merchant_id: preferred_merchant_id,
33
- public_key: preferred_public_key,
34
- private_key: preferred_private_key,
35
- logger: ::Braintree::Configuration.logger.clone,
36
- }
37
- end
38
-
39
- def braintree_gateway
40
- @braintree_gateway ||= ::Braintree::Gateway.new(gateway_options)
41
- end
42
-
43
- def payment_profiles_supported?
44
- true
45
- end
46
-
47
- def generate_client_token(options = {})
48
- braintree_gateway.client_token.generate(options)
49
- end
50
-
51
- def create_profile(payment)
52
- source = payment.source
53
-
54
- return if source.gateway_customer_profile_id.present? || payment.payment_method_nonce.nil?
55
-
56
- user = payment.order.user
57
- email = user ? user.email : payment.order.email
58
- address = (payment.source.address || payment.order.bill_address).try(:active_merchant_hash)
59
-
60
- params = {
61
- first_name: source.first_name,
62
- last_name: source.last_name,
63
- email: email,
64
- credit_card: {
65
- cardholder_name: source.name,
66
- billing_address: map_address(address),
67
- payment_method_nonce: payment.payment_method_nonce,
68
- options: {
69
- verify_card: true,
70
- },
71
- },
72
- device_data: payment.order.braintree_device_data
73
- }
74
-
75
- result = braintree_gateway.customer.create(params)
76
-
77
- if result.success?
78
- card = result.customer.payment_methods.last
79
- source.tap do |solidus_cc|
80
- if card.is_a?(::Braintree::PayPalAccount)
81
- solidus_cc.cc_type = 'paypal'
82
- data = {
83
- email: card.email
84
- }
85
- solidus_cc.data = data.to_json
86
- else
87
- solidus_cc.name = card.cardholder_name
88
- solidus_cc.cc_type = CARD_TYPE_MAPPING[card.card_type]
89
- solidus_cc.month = card.expiration_month
90
- solidus_cc.year = card.expiration_year
91
- solidus_cc.last_digits = card.last_4
92
- end
93
- solidus_cc.payment_method = self
94
- solidus_cc.gateway_customer_profile_id = result.customer.id
95
- solidus_cc.gateway_payment_profile_id = card.token
96
- end
97
- source.save!
98
- else
99
- raise ::Spree::Core::GatewayError, result.message
100
- end
101
- end
102
-
103
- def supports?(payment)
104
- true
105
- end
106
-
107
- def provider_class
108
- self
109
- end
110
-
111
- def authorize(cents, creditcard, options = {})
112
- result = braintree_gateway.transaction.sale(transaction_authorize_or_purchase_params(cents, creditcard, options))
113
- handle_result(result)
114
- end
115
-
116
- def purchase(cents, creditcard, options = {})
117
- params = transaction_authorize_or_purchase_params(cents, creditcard, options)
118
- params[:options][:submit_for_settlement] = true
119
- result = braintree_gateway.transaction.sale(params)
120
- handle_result(result)
121
- end
122
-
123
- def capture(money, authorization_code, options = {})
124
- result = braintree_gateway.transaction.submit_for_settlement(authorization_code, amount(money))
125
- handle_result(result)
126
- end
127
-
128
- def void(authorization_code, source = {}, options = {})
129
- # Allows voiding payments that are in a checkout state
130
- if authorization_code.nil?
131
- # Fake response since we don't need to void anything with Braintree
132
- ActiveMerchant::Billing::Response.new(
133
- true,
134
- "OK",
135
- {},
136
- {}
137
- )
138
- else
139
- result = braintree_gateway.transaction.void(authorization_code)
140
- handle_result(result)
141
- end
142
- end
143
-
144
- def credit(cents, source, authorization_code, options = {})
145
- result = braintree_gateway.transaction.refund(authorization_code, amount(cents))
146
- handle_result(result)
147
- end
148
-
149
- def voidable?(response_code)
150
- transaction = braintree_gateway.transaction.find(response_code)
151
- [
152
- ::Braintree::Transaction::Status::SubmittedForSettlement,
153
- ::Braintree::Transaction::Status::Authorized,
154
- ].include?(transaction.status)
155
- end
156
-
157
- def card_number_placeholder
158
- '4141 4141 4141 4141'
159
- end
160
-
161
- def expiration_date_placeholder
162
- '01/2020'
163
- end
164
-
165
- def card_code_placeholder
166
- '123'
167
- end
168
-
169
- def cancel(response)
170
- if voidable?(response)
171
- void(response)
172
- else
173
- handle_result(
174
- braintree_gateway.transaction.refund(response)
175
- )
176
- end
177
- end
178
-
179
- private
180
- def message_from_result(result)
181
- if result.success?
182
- "OK"
183
- elsif result.errors.count == 0 && result.credit_card_verification
184
- "Processor declined: #{result.credit_card_verification.processor_response_text} (#{result.credit_card_verification.processor_response_code})"
185
- elsif result.errors.count == 0 && result.transaction
186
- result.transaction.status
187
- else
188
- result.errors.map { |e| "#{e.message} (#{e.code})" }.join(" ")
189
- end
190
- end
191
-
192
- def build_results_hash(result)
193
- if result.success?
194
- {
195
- authorization: result.transaction.id,
196
- avs_result: {
197
- code: result.transaction.avs_street_address_response_code
198
- }
199
- }
200
- else
201
- {}
202
- end
203
- end
204
-
205
- def handle_result(result)
206
- ActiveMerchant::Billing::Response.new(
207
- result.success?,
208
- message_from_result(result),
209
- {},
210
- build_results_hash(result)
211
- )
212
- end
213
-
214
- def map_address(addr)
215
- full_name = addr.fetch(:name, "")
216
- *first_name_parts, last_name = full_name.split(" ")
217
- first_name = first_name_parts.join(" ")
218
- last_name ||= ""
219
-
220
- {
221
- first_name: first_name,
222
- last_name: last_name,
223
- street_address: addr[:address1],
224
- extended_address: addr[:address2],
225
- locality: addr[:city],
226
- region: addr[:state],
227
- country_code_alpha2: addr[:country],
228
- postal_code: addr[:zip],
229
- }
230
- end
231
-
232
- def amount(cents)
233
- sprintf("%.2f", cents.to_f / 100)
234
- end
235
-
236
- def transaction_authorize_or_purchase_params(cents, creditcard, options = {})
237
- params = options.select {|k| %i[
238
- billing_address_id
239
- channel
240
- custom_fields
241
- descriptor
242
- device_data
243
- device_session_id
244
- merchant_account_id
245
- options
246
- order_id
247
- purchase_order_number
248
- recurring
249
- service_fee_amount
250
- shipping_address_id
251
- tax_amount
252
- tax_exempt
253
- ].include?(k)}
254
-
255
- params[:options] ||= {}
256
- params[:amount] = amount(cents)
257
- params[:channel] ||= "Solidus"
258
- if (options[:shipping_address] && preferred_transmit_shipping_address)
259
- params[:shipping] = map_address(options[:shipping_address])
260
- end
261
-
262
- if options[:payment_method_nonce]
263
- params[:payment_method_nonce] = options[:payment_method_nonce]
264
- else
265
- params[:payment_method_token] = creditcard.gateway_payment_profile_id
266
- end
267
-
268
- # Send the bill address if we're using a nonce (i.e. doing a one-time
269
- # payment) or if we're configured to always send the bill address
270
- if (
271
- options[:payment_method_nonce] || preferred_always_send_bill_address
272
- ) && options[:billing_address]
273
- params[:billing] = map_address(options[:billing_address])
274
- end
275
-
276
- # if has profile, set the customer_id to the profile_id and delete the customer key
277
- if creditcard.try(:gateway_customer_profile_id)
278
- params[:customer_id] = creditcard.gateway_customer_profile_id
279
- # if no profile, define the customer key, delete the customer_id because they are
280
- # mutually exclusive
281
- else
282
- params[:customer] = {
283
- id: options[:customer_id],
284
- email: options[:customer],
285
- first_name: creditcard.first_name,
286
- last_name: creditcard.last_name,
287
- }
288
- end
289
-
290
- params
291
- end
292
- end
293
- 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}" } %> <%= Spree.t(: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}", Spree.t(: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><%= Spree.t(:identifier) %>:</dt>
8
- <dd><%= payment.number %></dd>
9
-
10
- <dt><%= Spree.t(:response_code) %>:</dt>
11
- <dd><%= braintree_transaction_link(payment.response_code) %></dd>
12
-
13
- <dt><%= Spree.t(: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}", Spree.t(: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", Spree.t(: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" ><%= Spree.t(:card_type_is) %> <span id="type"></span></span>
29
- <span id="unrecognized"><%= Spree.t(:unrecognized_card_type) %></span>
30
- )
31
- </span>
32
- </p>
33
-
34
- <p class="field" data-hook="card_expiration">
35
- <%= label_tag "braintree_card_expiry", Spree.t(: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", Spree.t(: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 "(#{Spree.t(: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 +0,0 @@
1
- ActionView::Base.send :include, BraintreeViewHelpers
@@ -1,5 +0,0 @@
1
- class AddDataToCreditCard < ActiveRecord::Migration
2
- def change
3
- add_column :spree_credit_cards, :data, :text
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- class AddBraintreeDeviceDataToOrder < ActiveRecord::Migration
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.routes.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.routes.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
- });