spree_braintree_vzero 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +15 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +63 -0
  6. data/Appraisals +45 -0
  7. data/CONTRIBUTING.md +28 -0
  8. data/Gemfile +14 -0
  9. data/LICENSE +26 -0
  10. data/README.md +83 -0
  11. data/Rakefile +21 -0
  12. data/app/assets/images/credit_cards/icons/jcb.png +0 -0
  13. data/app/assets/javascripts/spree/backend/payments.js +19 -0
  14. data/app/assets/javascripts/spree/backend/spree_braintree_vzero.js +81 -0
  15. data/app/assets/javascripts/spree/frontend/spree_braintree_vzero.js +68 -0
  16. data/app/assets/stylesheets/spree/backend/spree_braintree_vzero.css +5 -0
  17. data/app/controllers/spree/admin/payments_controller_decorator.rb +43 -0
  18. data/app/controllers/spree/api/v1/braintree_client_token_controller.rb +31 -0
  19. data/app/controllers/spree/checkout_controller_decorator.rb +38 -0
  20. data/app/controllers/spree/orders_controller_decorator.rb +62 -0
  21. data/app/controllers/spree/user_sessions_controller_decorator.rb +15 -0
  22. data/app/helpers/spree/admin/decorated_navigation_helper.rb +10 -0
  23. data/app/helpers/spree/admin/payment_methods_helper.rb +101 -0
  24. data/app/helpers/spree/braintree_helper.rb +27 -0
  25. data/app/models/braintree/successful_result_decorator.rb +21 -0
  26. data/app/models/spree/address_decorator.rb +18 -0
  27. data/app/models/spree/braintree_checkout.rb +105 -0
  28. data/app/models/spree/gateway/braintree_vzero_base.rb +168 -0
  29. data/app/models/spree/gateway/braintree_vzero_base/address.rb +33 -0
  30. data/app/models/spree/gateway/braintree_vzero_base/braintree_user.rb +25 -0
  31. data/app/models/spree/gateway/braintree_vzero_base/purchase_data.rb +48 -0
  32. data/app/models/spree/gateway/braintree_vzero_base/transaction.rb +39 -0
  33. data/app/models/spree/gateway/braintree_vzero_base/utils.rb +108 -0
  34. data/app/models/spree/gateway/braintree_vzero_drop_in_ui.rb +24 -0
  35. data/app/models/spree/gateway/braintree_vzero_hosted_fields.rb +28 -0
  36. data/app/models/spree/gateway/braintree_vzero_paypal_express.rb +36 -0
  37. data/app/models/spree/order_decorator.rb +153 -0
  38. data/app/models/spree/payment_decorator.rb +10 -0
  39. data/app/models/spree/payment_processing_decorator.rb +61 -0
  40. data/app/models/spree/preferences/preferable_decorator.rb +54 -0
  41. data/app/overrides/spree/admin/orders/customer_details/_form.rb +8 -0
  42. data/app/overrides/spree/admin/payment_methods/_form.rb +10 -0
  43. data/app/overrides/spree/admin/shared/_order_summary.rb +23 -0
  44. data/app/overrides/spree/admin/shared/_refunds.rb +13 -0
  45. data/app/overrides/spree/checkout/_new_user.rb +6 -0
  46. data/app/overrides/spree/checkout/_payment.rb +20 -0
  47. data/app/overrides/spree/checkout/registration.rb +6 -0
  48. data/app/overrides/spree/orders/edit.rb +6 -0
  49. data/app/overrides/spree/shared/_order_details.rb +13 -0
  50. data/app/overrides/spree/shared/_payment.rb +28 -0
  51. data/app/views/spree/admin/payment_methods/_braintree_vzero_form.html.erb +83 -0
  52. data/app/views/spree/admin/payments/source_forms/_braintree_vzero_dropin_ui.html.erb +1 -0
  53. data/app/views/spree/admin/payments/source_forms/_braintree_vzero_hosted_fields.html.erb +1 -0
  54. data/app/views/spree/admin/payments/source_forms/_braintree_vzero_paypal_express.html.erb +1 -0
  55. data/app/views/spree/admin/payments/source_forms/braintree_vzero/_payments.html.erb +87 -0
  56. data/app/views/spree/admin/payments/source_views/_braintree_vzero_dropin_ui.html.erb +1 -0
  57. data/app/views/spree/admin/payments/source_views/_braintree_vzero_hosted_fields.html.erb +1 -0
  58. data/app/views/spree/admin/payments/source_views/_braintree_vzero_paypal_express.html.erb +1 -0
  59. data/app/views/spree/admin/payments/source_views/braintree_vzero/_payment.html.erb +17 -0
  60. data/app/views/spree/braintree_vzero/_paypal_checkout.html.erb +87 -0
  61. data/app/views/spree/checkout/payment/_braintree_vzero_dropin_ui.html.erb +4 -0
  62. data/app/views/spree/checkout/payment/_braintree_vzero_hosted_fields.html.erb +4 -0
  63. data/app/views/spree/checkout/payment/_braintree_vzero_paypal_express.html.erb +4 -0
  64. data/app/views/spree/checkout/payment/braintree_vzero/_buttons.html.erb +11 -0
  65. data/app/views/spree/checkout/payment/braintree_vzero/_dropin_on_error_callback.js.erb +3 -0
  66. data/app/views/spree/checkout/payment/braintree_vzero/_dropin_on_ready_callback.js.erb +1 -0
  67. data/app/views/spree/checkout/payment/braintree_vzero/_hosted_fields_on_field_event_callback.js.erb +12 -0
  68. data/app/views/spree/checkout/payment/braintree_vzero/_hosted_fields_styles.js.erb +29 -0
  69. data/app/views/spree/checkout/payment/braintree_vzero/_payment.html.erb +84 -0
  70. data/app/views/spree/checkout/payment/braintree_vzero/_three_d_secure.html.erb +218 -0
  71. data/app/views/spree/shared/braintree_vzero/_dropin.js.erb +70 -0
  72. data/app/views/spree/shared/braintree_vzero/_hosted.js.erb +66 -0
  73. data/app/views/spree/shared/braintree_vzero/_paypal.js.erb +39 -0
  74. data/bin/rails +7 -0
  75. data/config/initializers/extend_spree_permitted_checkout_attributes.rb +5 -0
  76. data/config/initializers/prepend_helpers.rb +1 -0
  77. data/config/locales/en.yml +79 -0
  78. data/config/routes.rb +7 -0
  79. data/db/migrate/20150904143013_create_spree_braintree_checkouts.rb +9 -0
  80. data/db/migrate/20151002094655_add_braintree_id_to_spree_addresses.rb +5 -0
  81. data/db/migrate/20151018123907_add_braintree_token_and_nonce_to_spree_payments.rb +6 -0
  82. data/db/migrate/20151027135109_add_paypal_email_to_spree_braintree_checkout.rb +5 -0
  83. data/db/migrate/20151028095515_add_advanced_fraud_data_to_spree_braintree_checkout.rb +5 -0
  84. data/db/migrate/20151202095956_add_risk_id_and_risk_decision_to_spree_braintree_checkouts.rb +6 -0
  85. data/db/migrate/20151211100203_add_braintree_last_digits_and_braintree_card_type_to_spree_braintree_checkouts.rb +6 -0
  86. data/db/migrate/20160112153422_add_admin_payment_to_spree_braintree_checkout.rb +5 -0
  87. data/gemfiles/spree_3_5.gemfile +12 -0
  88. data/gemfiles/spree_3_5_spree_auth_devise.gemfile +13 -0
  89. data/gemfiles/spree_3_7.gemfile +12 -0
  90. data/gemfiles/spree_3_7_spree_auth_devise.gemfile +13 -0
  91. data/gemfiles/spree_4_0.gemfile +11 -0
  92. data/gemfiles/spree_4_0_spree_auth_devise.gemfile +12 -0
  93. data/gemfiles/spree_master.gemfile +11 -0
  94. data/gemfiles/spree_master_spree_auth_devise.gemfile +12 -0
  95. data/lib/generators/spree_braintree_vzero/install/install_generator.rb +34 -0
  96. data/lib/spree_braintree_vzero.rb +6 -0
  97. data/lib/spree_braintree_vzero/engine.rb +28 -0
  98. data/lib/spree_braintree_vzero/factories.rb +10 -0
  99. data/lib/spree_braintree_vzero/railtie.rb +8 -0
  100. data/lib/spree_braintree_vzero/version.rb +17 -0
  101. data/lib/tasks/spree_braintree_vzero.rake +6 -0
  102. data/spec/controllers/spree/api/v1/braintree_client_token_controller_spec.rb +49 -0
  103. data/spec/controllers/spree/checkout_controller_spec.rb +85 -0
  104. data/spec/controllers/spree/orders_controller_spec.rb +97 -0
  105. data/spec/factories/braintree_checkout_factory.rb +7 -0
  106. data/spec/factories/braintree_gateway_factory.rb +35 -0
  107. data/spec/factories/payment_factory_decorator.rb +28 -0
  108. data/spec/features/spree/admin/log_entries_spec.rb +63 -0
  109. data/spec/models/gateway/braintree_vzero_base/address_spec.rb +28 -0
  110. data/spec/models/gateway/braintree_vzero_base/purchase_data_spec.rb +57 -0
  111. data/spec/models/gateway/braintree_vzero_base_spec.rb +346 -0
  112. data/spec/models/gateway/braintree_vzero_dropin_ui_spec.rb +35 -0
  113. data/spec/models/gateway/braintree_vzero_hosted_fields_spec.rb +35 -0
  114. data/spec/models/spree/order_spec.rb +186 -0
  115. data/spec/spec_helper.rb +100 -0
  116. data/spec/support/vcr.rb +10 -0
  117. data/spec/vcr/Log_entries/with_a_failed_log_entry/shows_a_failed_attempt.yml +91 -0
  118. data/spec/vcr/Log_entries/with_a_successful_log_entry/shows_a_successful_attempt.yml +113 -0
  119. data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/guest_checkout/returns_proper_json_data_when_gateway_not_specified.yml +90 -0
  120. data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/guest_checkout/returns_proper_json_data_when_gateway_specified.yml +90 -0
  121. data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/user_checkout/returns_proper_json_data_when_gateway_not_specified.yml +191 -0
  122. data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/user_checkout/returns_proper_json_data_when_gateway_specified.yml +191 -0
  123. data/spec/vcr/Spree_CheckoutController/_update/braintree_payment/advanced_fraud_data_in_source_should_be_updated.yml +71 -0
  124. data/spec/vcr/Spree_CheckoutController/_update/braintree_payment/when_token_credit_card_data_in_source_should_be_updated_from_Braintree_Vault.yml +139 -0
  125. data/spec/vcr/Spree_CheckoutController/_update/braintree_paypal_express_payment/amount_in_payment_should_be_updated.yml +280 -0
  126. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_capture/captures_authorized_amount/updates_Payment_state.yml +206 -0
  127. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_credit/with_refundable_state/should_be_a_success.yml +211 -0
  128. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_credit/with_unrefundable_state/should_not_be_a_success.yml +177 -0
  129. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/data_from_admin_panel/should_include_only_essential_data.yml +78 -0
  130. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/does_not_store_Transaction_in_Vault_by_default.yml +111 -0
  131. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_false_with_invalid_nonce.yml +88 -0
  132. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_false_with_invalid_token.yml +88 -0
  133. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_success_with_valid_token.yml +113 -0
  134. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_suceess_with_valid_nonce.yml +111 -0
  135. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/using_Vault/saves_Braintree_Address_id_to_Spree_Address_when_address_is_being_saved.yml +130 -0
  136. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/using_Vault/saves_unique_Braintree_Addresses_ids.yml +143 -0
  137. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/using_Vault/sends_empty_address_id_when_address_is_already_in_vault.yml +553 -0
  138. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/using_Vault/stores_Transaction.yml +181 -0
  139. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_3DSecure_option_turned_on/performs_3DSecure_check.yml +112 -0
  140. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_3DSecure_option_turned_on/returns_error.yml +112 -0
  141. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_advanced_fraud_tool_enabled/returns_fraud_data.yml +111 -0
  142. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_advanced_fraud_tool_enabled/returns_success.yml +111 -0
  143. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/does_not_update_Order_payment_state.yml +204 -0
  144. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/prepares_Checkout_for_status_updating.yml +204 -0
  145. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/submits_Transaction_for_settlement.yml +377 -0
  146. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/updates_Payment_state.yml +203 -0
  147. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/does_not_update_completed_Checkout_on_subsequent_runs.yml +202 -0
  148. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/updates_Order_payment_state_when_Checkout_is_updated.yml +202 -0
  149. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/updates_Payment_state_when_Checkout_is_updated.yml +202 -0
  150. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/updates_payment_State.yml +202 -0
  151. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_void/with_unvoidable_state/should_not_change_payment_source_state.yml +178 -0
  152. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_void/with_voidable_state/should_change_payment_source_state_to_voided.yml +199 -0
  153. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/generates_token_for_User_registered_in_Braintree.yml +356 -0
  154. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/generates_token_for_new_User.yml +189 -0
  155. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/generates_token_without_User.yml +89 -0
  156. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/with_invalid_credentials/raises_Braintree_error.yml +62 -0
  157. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/creates_Braintree_Address.yml +84 -0
  158. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/deletes_Braintree_Address.yml +141 -0
  159. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/finds_Braintree_Address.yml +148 -0
  160. data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/updates_Braintree_Address.yml +154 -0
  161. data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/with_auto_capture/should_complete_payment.yml +116 -0
  162. data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/with_auto_capture/should_update_payment_s_response_code.yml +111 -0
  163. data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/with_auto_capture/should_update_payment_s_source_state_and_transaction_id.yml +111 -0
  164. data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/without_auto_capture/should_pend_payment.yml +111 -0
  165. data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/without_auto_capture/should_update_payment_s_response_code.yml +111 -0
  166. data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/without_auto_capture/should_update_payment_s_source_state_and_transaction_id.yml +110 -0
  167. data/spree_braintree_vzero.gemspec +52 -0
  168. data/vendor/assets/javascripts/maskedinput/jquery.maskedinput.min.js +7 -0
  169. metadata +643 -0
@@ -0,0 +1,168 @@
1
+ require 'braintree'
2
+
3
+ module Spree
4
+ class Gateway::BraintreeVzeroBase < Gateway
5
+ include BraintreeVzeroBase::PurchaseData
6
+
7
+ preference :merchant_id, :string
8
+ preference :public_key, :string
9
+ preference :private_key, :string
10
+ preference :server, :select, default: -> { { values: [:sandbox, :production] } }
11
+ preference :pass_billing_and_shipping_address, :boolean_select, default: false
12
+ preference :kount_merchant_id, :string
13
+ preference :advanced_fraud_tools, :boolean_select, default: false
14
+ preference :descriptor_name, :string
15
+ preference :currency_merchant_accounts, :hash, default: {}
16
+
17
+ attr_reader :utils
18
+
19
+ def self.current
20
+ super
21
+ end
22
+
23
+ def provider_class
24
+ Braintree
25
+ end
26
+
27
+ def provider
28
+ Braintree::Configuration.environment = preferred_server.to_sym
29
+ Braintree::Configuration.merchant_id = preferred_merchant_id
30
+ Braintree::Configuration.public_key = preferred_public_key
31
+ Braintree::Configuration.private_key = preferred_private_key
32
+ Braintree
33
+ end
34
+
35
+ def client_token(order = nil, user = nil)
36
+ braintree_provider = provider
37
+ braintree_provider::ClientToken.generate token_params(braintree_provider, user, order)
38
+ end
39
+
40
+ def purchase(money_in_cents, source, gateway_options)
41
+ order, payment = order_data_from_options(gateway_options)
42
+
43
+ @utils = Utils.new(self, order)
44
+ identifier_hash = find_identifier_hash(payment, @utils)
45
+
46
+ data = set_purchase_data(identifier_hash, order, money_in_cents, source)
47
+
48
+ return invalid_payment_error(data) if identifier_hash.values.all?(&:blank?)
49
+ sale(data, order, payment.source)
50
+ end
51
+
52
+ def authorize(money_in_cents, source, gateway_options)
53
+ purchase money_in_cents, source, gateway_options
54
+ end
55
+
56
+ def settle(amount, checkout, _gateway_options)
57
+ result = Transaction.new(provider, checkout.transaction_id).submit_for_settlement(amount / 100.0)
58
+ checkout.update(state: result.transaction.status)
59
+ result
60
+ end
61
+
62
+ def capture(amount, transaction_id, _gateway_options)
63
+ checkout = Spree::BraintreeCheckout.find_by(transaction_id: transaction_id)
64
+ settle(amount, checkout, _gateway_options)
65
+ end
66
+
67
+ def void(transaction_id, _data)
68
+ result = Transaction.new(provider, transaction_id).void
69
+
70
+ if result.success?
71
+ Spree::BraintreeCheckout.find_by(transaction_id: transaction_id).update(state: 'voided')
72
+ end
73
+
74
+ result
75
+ end
76
+
77
+ def credit(credit_cents, transaction_id, _options)
78
+ Transaction.new(provider, transaction_id).refund(credit_cents.to_f / 100)
79
+ end
80
+
81
+ def customer_payment_methods(order, payment_method_type)
82
+ @utils = Utils.new(self, order)
83
+ @utils.customer_payment_methods(payment_method_type)
84
+ end
85
+
86
+ def vaulted_payment_method(token)
87
+ provider::PaymentMethod.find(token)
88
+ end
89
+
90
+ private
91
+
92
+ def sale(data, order, source = nil)
93
+ Rails.logger.info "Sale data: #{data.inspect}"
94
+ result = Transaction.new(provider).sale(data)
95
+ Rails.logger.info "Risk Data: #{result.transaction.risk_data.inspect}" if result.success?
96
+
97
+ if result.success?
98
+ update_addresses(result, order)
99
+ update_source(result, source)
100
+ else
101
+ add_order_errors(result, order)
102
+ end
103
+
104
+ result
105
+ end
106
+
107
+ def update_addresses(response, order)
108
+ shipping_address = order.shipping_address
109
+ billing_address = order.billing_address
110
+ transaction = response.transaction
111
+
112
+ shipping_details_id = transaction.shipping_details.id
113
+ details_id = if shipping_address.same_as?(billing_address)
114
+ shipping_details_id ||= transaction.billing_details.id
115
+ else
116
+ transaction.billing_details.id
117
+ end
118
+
119
+ shipping_address.update_attribute(:braintree_id, shipping_details_id)
120
+ billing_address.update_attribute(:braintree_id, details_id)
121
+ end
122
+
123
+ def update_source(response, source)
124
+ return unless source.present?
125
+ transaction = response.transaction
126
+ if (risk_data = transaction.risk_data).present?
127
+ source.update(transaction_id: transaction.id, state: transaction.status,
128
+ risk_id: risk_data.id, risk_decision: risk_data.decision)
129
+ else
130
+ source.update(transaction_id: transaction.id, state: transaction.status)
131
+ end
132
+ end
133
+
134
+ def add_order_errors(response, order)
135
+ response.errors.each { |e| order.errors.add(:base, I18n.t(e.message), scope: 'braintree.error') }
136
+ return unless response.errors.size.zero? && response.transaction.try(:gateway_rejection_reason)
137
+ order.errors.add(:base, I18n.t(response.transaction.gateway_rejection_reason, scope: 'braintree.error'))
138
+ end
139
+
140
+ def find_identifier_hash(payment, _utils)
141
+ if (token = payment[:braintree_token]).present?
142
+ { payment_method_token: token }
143
+ else
144
+ { payment_method_nonce: payment[:braintree_nonce] }
145
+ end
146
+ end
147
+
148
+ def invalid_payment_error(data)
149
+ # We want only direct choice of payment method (token or nonce), not by customer_id
150
+ message = 'Payment method identification was not specified'
151
+ errors = { errors: [{ code: '0', attribute: '', message: message }] }
152
+ Braintree::ErrorResult.new(:transaction, params: data, errors: { transaction: errors }, message: message)
153
+ end
154
+
155
+ def braintree_user(provider, user, order)
156
+ Gateway::BraintreeVzeroBase::BraintreeUser.new(provider, user, order).user
157
+ end
158
+
159
+ def token_params(provider, user, order)
160
+ token_params = {}
161
+ token_params[:customer_id] = user.id if braintree_user(provider, user, order)
162
+ currency = order.try(:currency)
163
+ merchant_account_id = currency ? get_merchant_account(currency) : nil
164
+ token_params[:merchant_account_id] = merchant_account_id if merchant_account_id
165
+ token_params
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,33 @@
1
+ module Spree
2
+ class Gateway
3
+ class BraintreeVzeroBase
4
+ class Address
5
+ attr_reader :user, :utils, :request
6
+
7
+ def initialize(provider, order)
8
+ @utils = Utils.new(provider, order)
9
+ @user = order.user
10
+ @request = provider::Address
11
+ end
12
+
13
+ def create
14
+ @request.create(@utils.address_data('billing', utils.order).merge!(customer_id: user.id.to_s))
15
+ end
16
+
17
+ def find(braintree_address)
18
+ address_id = braintree_address.try(:id) || braintree_address
19
+ @request.find(user.id.to_s, address_id.to_s)
20
+ rescue Braintree::NotFoundError
21
+ end
22
+
23
+ def update(braintree_address, params)
24
+ @request.update(user.id.to_s, braintree_address.id.to_s, params)
25
+ end
26
+
27
+ def delete(braintree_address)
28
+ @request.delete(user.id.to_s, braintree_address.id.to_s)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module Spree
2
+ class Gateway
3
+ class BraintreeVzeroBase
4
+ class BraintreeUser
5
+ attr_reader :user, :spree_user, :request, :utils
6
+
7
+ delegate :shipping_address, :billing_address, to: :spree_user
8
+
9
+ def initialize(provider, spree_user, order)
10
+ @utils = Utils.new(provider, order)
11
+ @spree_user = spree_user
12
+ @request = provider::Customer
13
+ begin
14
+ @user = @request.find(spree_user.try(:id))
15
+ rescue
16
+ end
17
+ end
18
+
19
+ def register_user
20
+ @request.create(@utils.customer_data(spree_user))
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ module Spree
2
+ class Gateway
3
+ class BraintreeVzeroBase
4
+ module PurchaseData
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def set_purchase_data(identifier_hash, order, money_in_cents, source)
10
+ data = set_basic_purchase_data(identifier_hash, order, @utils, money_in_cents)
11
+ merchant_account_id = get_merchant_account(order.currency)
12
+ data[:merchant_account_id] = merchant_account_id if merchant_account_id
13
+ data[:descriptor] = { name: preferred_descriptor_name.to_s.tr('/', '*') }
14
+ data[:options] = {
15
+ submit_for_settlement: auto_capture?,
16
+ add_billing_address_to_payment_method: preferred_pass_billing_and_shipping_address ? true : false,
17
+ three_d_secure: {
18
+ required: (try(:preferred_3dsecure) unless source.admin_payment?)
19
+ }
20
+ }.merge!(@utils.payment_in_vault(data))
21
+ return data if source.admin_payment? || !preferred_advanced_fraud_tools
22
+ data.merge!(device_data: source.advanced_fraud_data)
23
+ end
24
+
25
+ def set_basic_purchase_data(identifier_hash, order, utils, money_in_cents)
26
+ data = { channel: I18n.t('braintree.channel_parameter') }
27
+ data.merge!(utils.get_customer)
28
+ data.merge!(utils.order_data(identifier_hash, money_in_cents.to_f / 100))
29
+ return data unless preferred_pass_billing_and_shipping_address
30
+
31
+ data.merge!(utils.get_address('billing'))
32
+ data.merge!(utils.get_address('shipping'))
33
+ end
34
+
35
+ def get_merchant_account(currency)
36
+ preferred_currency_merchant_accounts[currency]
37
+ end
38
+
39
+ def order_data_from_options(options)
40
+ order_number, payment_number = options[:order_id].split('-')
41
+ order = Spree::Order.find_by(number: order_number)
42
+ payment = order.payments.find_by(number: payment_number)
43
+ [order, payment]
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ module Spree
2
+ class Gateway
3
+ class BraintreeVzeroBase
4
+ class Transaction
5
+ attr_reader :transaction_id, :request
6
+
7
+ def initialize(provider, transaction_id = nil)
8
+ @transaction_id = transaction_id
9
+ @request = provider::Transaction
10
+ end
11
+
12
+ def submit_for_settlement(amount)
13
+ @request.submit_for_settlement(transaction_id, amount)
14
+ end
15
+
16
+ def clone
17
+ t = @request.find(transaction_id)
18
+ sale(payment_method_token: t.credit_card_details.token, amount: t.amount, options: { submit_for_settlement: true })
19
+ end
20
+
21
+ def sale(data)
22
+ @request.sale(data)
23
+ end
24
+
25
+ def status
26
+ @request.find(transaction_id).status
27
+ end
28
+
29
+ def void
30
+ @request.void(transaction_id)
31
+ end
32
+
33
+ def refund(cents)
34
+ @request.refund(transaction_id, cents)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,108 @@
1
+ module Spree
2
+ class Gateway
3
+ class BraintreeVzeroBase
4
+ class Utils
5
+ attr_reader :order, :customer, :gateway
6
+
7
+ def initialize(gateway, order)
8
+ @order = order
9
+ begin
10
+ @customer = gateway.provider::Customer.find(order.user.id) if order.user
11
+ rescue
12
+ end
13
+ @gateway = gateway
14
+ end
15
+
16
+ def get_address(address_type)
17
+ if order.user && (address = order.user.send("#{address_type}_address"))
18
+ braintree_address = BraintreeVzeroBase::Address.new(gateway.provider, order)
19
+ vaulted_duplicate = Spree::Address.vaulted_duplicates(address).first
20
+
21
+ if vaulted_duplicate && braintree_address.find(vaulted_duplicate.braintree_id)
22
+ { "#{address_type}_address_id" => vaulted_duplicate.braintree_id }
23
+ else
24
+ { address_type => address_data(address_type, order.user) }
25
+ end
26
+ else
27
+ { address_type => address_data(address_type, order) }
28
+ end
29
+ end
30
+
31
+ def get_customer
32
+ if @customer
33
+ { customer_id: @customer.id }
34
+ else
35
+ { customer: (payment_in_vault[:store_shipping_address_in_vault] && order.user) ? customer_data(order.user) : {} }
36
+ end
37
+ end
38
+
39
+ def order_data(identifier, amount)
40
+ identifier.merge(
41
+ amount: amount,
42
+ order_id: order.number
43
+ )
44
+ end
45
+
46
+ def address_data(address_type, target)
47
+ address = target.send("#{address_type}_address")
48
+ country = address.country
49
+
50
+ {
51
+ company: address.company,
52
+ country_code_alpha2: country.iso,
53
+ country_code_alpha3: country.iso3,
54
+ country_code_numeric: country.numcode,
55
+ country_name: country.name,
56
+ first_name: address.first_name,
57
+ last_name: address.last_name,
58
+ locality: address.city,
59
+ postal_code: address.zipcode,
60
+ region: address.state.try(:abbr),
61
+ street_address: address.address1,
62
+ extended_address: address.address2
63
+ }
64
+ end
65
+
66
+ def customer_data(user)
67
+ address_data('billing', user).slice(:first_name, :last_name, :company, :phone).merge!(id: user.id, email: user.email)
68
+ end
69
+
70
+ def customer_payment_methods(payment_method_type)
71
+ payment_methods = @customer.try(:payment_methods) || []
72
+
73
+ if payment_method_type.eql?('custom')
74
+ payment_methods.select { |pm| pm.is_a?(Braintree::CreditCard) }
75
+ elsif payment_method_type.eql?('paypal')
76
+ payment_methods.select { |pm| pm.is_a?(Braintree::PayPalAccount) }
77
+ else
78
+ payment_methods
79
+ end
80
+ end
81
+
82
+ def payment_in_vault(data = {})
83
+ store_ship_address = data['shipping_address_id'].blank?
84
+ if gateway.preferred_store_payments_in_vault == 'store_only_on_success'
85
+ { store_in_vault_on_success: true, store_shipping_address_in_vault: store_ship_address }
86
+ elsif gateway.preferred_store_payments_in_vault == 'store_all'
87
+ { store_in_vault: true, store_shipping_address_in_vault: store_ship_address }
88
+ else
89
+ { store_in_vault: false }
90
+ end
91
+ end
92
+
93
+ def map_payment_status(braintree_status)
94
+ case braintree_status
95
+ when 'authorized', 'settlement_pending'
96
+ 'pending'
97
+ when 'voided'
98
+ 'void'
99
+ when 'settled', 'submitted_for_settlement', 'settling'
100
+ 'completed'
101
+ else
102
+ 'failed'
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ class Gateway::BraintreeVzeroDropInUi < Spree::Gateway::BraintreeVzeroBase
3
+ preference :dropin_container, :string, default: 'payment-form'
4
+ preference :checkout_form_id, :string, default: 'checkout_form_payment'
5
+ preference :error_messages_container_id, :string, default: 'content'
6
+ preference :store_payments_in_vault, :select, default: -> { { values: [:do_not_store, :store_only_on_success, :store_all] } }
7
+ preference :'3dsecure', :boolean_select, default: false
8
+
9
+ after_save :disable_hosted_gateways, if: proc {
10
+ active? && (saved_changes.keys & %w[active id]).any?
11
+ }
12
+
13
+ def method_type
14
+ 'braintree_vzero_dropin_ui'
15
+ end
16
+
17
+ private
18
+
19
+ # we cannot have Hosted and DropInUI both active at the same time
20
+ def disable_hosted_gateways
21
+ Spree::Gateway::BraintreeVzeroHostedFields.update_all(active: false)
22
+ end
23
+ end
24
+ end