spree_braintree_vzero 3.5.1

Sign up to get free protection for your applications and to get access to all the features.
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,7 @@
1
+ FactoryBot.define do
2
+ factory :braintree_checkout, class: Spree::BraintreeCheckout do
3
+ factory :braintree_checkout_with_fraud_data, class: Spree::BraintreeCheckout do
4
+ advanced_fraud_data { '{"device_session_id":"9cc1d185d71768c185c06622b7ca7cfe","fraud_merchant_id":"600000","correlation_id":"7343097f536f584bfded32f9d229ec6d"}' }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ FactoryBot.define do
2
+ factory :vzero_gateway, class: Spree::Gateway::BraintreeVzeroDropInUi do
3
+ name { 'Braintree Vzero DropInUI' }
4
+
5
+ # to write new specs please provide proper credentials
6
+ # either here or in dummy secrets.yml file. Values will
7
+ # be recorded on VCR, so they can be safely replaced with
8
+ # placeholder afterwards
9
+ transient do
10
+ merchant_id { Rails.application.secrets.merchant_id || 'change me' }
11
+ public_key { Rails.application.secrets.public_key || 'change me' }
12
+ private_key { Rails.application.secrets.private_key || 'change me' }
13
+ end
14
+
15
+ before(:create) do |gateway, s|
16
+ %w(merchant_id private_key public_key).each do |preference|
17
+ gateway.send "preferred_#{preference}=", s.send(preference)
18
+ end
19
+ gateway.send 'preferred_server=', :sandbox
20
+ gateway.preferences[:currency_merchant_accounts] = { 'EUR' => 'sparksolutions_EUR' }
21
+ end
22
+
23
+ factory :vzero_paypal_gateway, class: Spree::Gateway::BraintreeVzeroPaypalExpress do
24
+ name { 'Braintree Vzero PayPal Express' }
25
+ end
26
+
27
+ factory :vzero_dropin_ui_gateway, class: Spree::Gateway::BraintreeVzeroDropInUi do
28
+ name { 'Braintree Vzero DropIn UI' }
29
+ end
30
+
31
+ factory :vzero_hosted_fields_gateway, class: Spree::Gateway::BraintreeVzeroHostedFields do
32
+ name { 'Braintree Vzero Hosted Fields' }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,28 @@
1
+ FactoryBot.define do
2
+ factory :braintree_vzero_payment, class: Spree::Payment do
3
+ amount { 12.73 }
4
+ association(:payment_method, factory: :vzero_gateway)
5
+ association(:source, factory: :braintree_checkout)
6
+ order
7
+ state { 'checkout' }
8
+ braintree_nonce { 'fake-valid-nonce' }
9
+ end
10
+
11
+ factory :braintree_vzero_paypal_payment, class: Spree::Payment do
12
+ amount { 0 }
13
+ association(:payment_method, factory: :vzero_paypal_gateway)
14
+ association(:source, factory: :braintree_checkout)
15
+ order
16
+ state { 'checkout' }
17
+ braintree_nonce { 'fake-valid-nonce' }
18
+ end
19
+
20
+ factory :braintree_vzero_failed_paypal_payment, class: Spree::Payment do
21
+ amount { 0 }
22
+ association(:payment_method, factory: :vzero_paypal_gateway)
23
+ association(:source, factory: :braintree_checkout)
24
+ order
25
+ state { 'checkout' }
26
+ braintree_nonce { 'fake-invalid-nonce' }
27
+ end
28
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Log entries', :vcr, type: :feature do
4
+ include Spree::BaseHelper
5
+
6
+ stub_authorization!
7
+
8
+ let(:payment) { order.payments.last }
9
+ let(:entry) { payment.log_entries.last }
10
+ let(:message) { entry.parsed_details.message }
11
+
12
+ context 'with a successful log entry' do
13
+ let!(:order) do
14
+ order = OrderWalkthrough.up_to(:payment)
15
+ order.payments << create(:braintree_vzero_paypal_payment, order: order)
16
+ order.next!
17
+ order.next
18
+ order
19
+ end
20
+
21
+ it 'shows a successful attempt' do
22
+ expect(message).to be_blank
23
+
24
+ visit spree.admin_order_payments_path(order)
25
+ if Spree.version.to_f < 4.0
26
+ find("#payment_#{payment.id} a").click
27
+ else
28
+ find_all("#payment_#{payment.id} a")[0].click
29
+ end
30
+
31
+ click_link 'Logs'
32
+ within('#listing_log_entries') do
33
+ expect(page).to have_css('.log_entry.success')
34
+ expect(page).not_to have_css('.log_entry.fail')
35
+ expect(page).to have_content(pretty_time(entry.created_at).gsub(' ', ' '))
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'with a failed log entry' do
41
+ let!(:order) do
42
+ order = OrderWalkthrough.up_to(:payment)
43
+ order.payments << create(:braintree_vzero_failed_paypal_payment, order: order)
44
+ order.next!
45
+ order.next
46
+ order
47
+ end
48
+
49
+ it 'shows a failed attempt' do
50
+ expect(message).to be_present
51
+
52
+ visit spree.admin_order_payments_path(order)
53
+ find("#payment_#{payment.id} a").click
54
+ click_link 'Logs'
55
+ within('#listing_log_entries') do
56
+ expect(page).not_to have_css('.log_entry.success')
57
+ expect(page).to have_css('.log_entry.fail')
58
+ expect(page).to have_content(pretty_time(entry.created_at).gsub(' ', ' '))
59
+ expect(page).to have_content(message)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Gateway::BraintreeVzeroBase::Address, :vcr do
4
+ let(:gateway) { create(:vzero_gateway, auto_capture: true) }
5
+ let(:user) { create(:user) }
6
+ let(:order) { create(:order) }
7
+ let(:braintree_address) { Spree::Gateway::BraintreeVzeroBase::Address.new(gateway.provider, order) }
8
+
9
+ context '#create' do
10
+ it 'creates Braintree Address' do
11
+ expect(braintree_address.create.address.id).to_not be_nil
12
+ end
13
+
14
+ it 'finds Braintree Address' do
15
+ expect(braintree_address.find(braintree_address.create.address)).to_not be_nil
16
+ end
17
+
18
+ it 'updates Braintree Address' do
19
+ result = braintree_address.update(braintree_address.create.address, first_name: 'new_name')
20
+ expect(result.address.first_name).to eq 'new_name'
21
+ end
22
+
23
+ it 'deletes Braintree Address' do
24
+ result = braintree_address.create
25
+ expect(braintree_address.delete(result.address).success?).to be true
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Gateway::BraintreeVzeroBase::PurchaseData do
4
+ let(:gateway) { create(:vzero_gateway, auto_capture: true) }
5
+ let(:payment) { create(:braintree_vzero_payment, payment_method: gateway) }
6
+ let(:payment_source) { payment.payment_source }
7
+ let(:order) { OrderWalkthrough.up_to(:payment) }
8
+ let(:identifier_hash) { { payment_method_nonce: '123' } }
9
+ let(:utils) { Spree::Gateway::BraintreeVzeroBase::Utils.new(gateway, order) }
10
+ let(:set_data) { gateway.send(:set_purchase_data, identifier_hash, order, 113, payment_source) }
11
+
12
+ before do
13
+ gateway.preferred_3dsecure = true
14
+ payment.update(braintree_nonce: 'fake-valid-debit-nonce')
15
+ gateway.preferred_advanced_fraud_tools = true
16
+ payment.source.update(advanced_fraud_data: '{\"device_session_id\":\"5a0c416f74a6044e4693204b4373b9e1\",\"fraud_merchant_id\":\"abcc\"}')
17
+ gateway.instance_variable_set(:@utils, utils)
18
+ end
19
+
20
+ context 'data from admin panel' do
21
+ before { payment_source.update(admin_payment: true) }
22
+
23
+ it 'should include only essential data' do
24
+ data = set_data
25
+ expect(data[:payment_method_nonce]).to eq identifier_hash[:payment_method_nonce]
26
+ expect(data[:channel]).to eq 'SpreeCommerceInc_Cart_Braintree'
27
+ expect(data[:device_data]).to be_blank
28
+ expect(data[:options][:three_d_secure][:required]).to be_blank
29
+ end
30
+ end
31
+
32
+ context 'data from checkout' do
33
+ it 'should include all data' do
34
+ data = set_data
35
+ expect(data[:payment_method_nonce]).to eq identifier_hash[:payment_method_nonce]
36
+ expect(data[:channel]).to eq 'SpreeCommerceInc_Cart_Braintree'
37
+ expect(data[:device_data]).to eq payment.source.advanced_fraud_data
38
+ expect(data[:options][:three_d_secure][:required]).to be true
39
+ end
40
+ end
41
+
42
+ context 'multi-currency' do
43
+ it 'should not include merchant account when currency
44
+ is not included in preferred currency merchant accounts' do
45
+ expect(gateway.preferred_currency_merchant_accounts[order.currency]).to be_nil
46
+ data = set_data
47
+ expect(data.include?(:merchant_account_id)).to be false
48
+ end
49
+
50
+ it 'should include merchant account id based on order currency' do
51
+ Spree::Price.first.update currency: 'EUR'
52
+ order.update currency: 'EUR'
53
+ data = set_data
54
+ expect(data[:merchant_account_id]).to eq 'sparksolutions_EUR'
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,346 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Gateway::BraintreeVzeroBase, :vcr do
4
+ context 'valid credentials' do
5
+ let(:gateway) { create(:vzero_gateway, auto_capture: true) }
6
+ let(:payment) { create(:braintree_vzero_payment, payment_method: gateway) }
7
+ let(:payment_source) { payment.payment_source }
8
+ let(:order) { OrderWalkthrough.up_to(:payment) }
9
+ let(:add_payment_to_order!) { order.payments << payment }
10
+ let(:complete_order!) do
11
+ add_payment_to_order!
12
+ until order.completed? do order.next! end
13
+ end
14
+
15
+ it 'generates token without User' do
16
+ expect(gateway.client_token).to_not be_nil
17
+ end
18
+
19
+ it 'generates token for new User' do
20
+ expect(gateway.client_token(order, create(:user))).to_not be_nil
21
+ end
22
+
23
+ it 'generates token for User registered in Braintree' do
24
+ user = create(:user, billing_address: create(:address))
25
+ Spree::Gateway::BraintreeVzeroBase::BraintreeUser.new(gateway.provider, user, order).register_user
26
+ expect(gateway.client_token(order, user)).to_not be_nil
27
+ end
28
+
29
+ describe '#purchase' do
30
+ let(:gateway_options) { { order_id: "#{order.number}-#{payment.number}" } }
31
+ let(:purchase) { gateway.purchase(10_000, payment_source, gateway_options) }
32
+ let(:other_order) { OrderWalkthrough.up_to(:payment) }
33
+
34
+ before do
35
+ gateway.preferred_3dsecure = false
36
+ add_payment_to_order!
37
+ end
38
+
39
+ it 'returns suceess with valid nonce' do
40
+ expect(purchase.success?).to be true
41
+ end
42
+
43
+ it 'returns false with invalid nonce' do
44
+ payment.update(braintree_nonce: 'fake-invalid-nonce')
45
+ expect(purchase.success?).to be false
46
+ end
47
+
48
+ it 'does not store Transaction in Vault by default' do
49
+ expect(purchase.transaction.credit_card_details.token).to be_nil
50
+ end
51
+
52
+ it 'returns success with valid token' do
53
+ gateway.preferred_store_payments_in_vault = :store_all
54
+ token = purchase.transaction.credit_card_details.token
55
+ payment.update(braintree_token: token)
56
+
57
+ expect(purchase.success?).to be true
58
+ end
59
+
60
+ it 'returns false when neither nonce nor token is present' do
61
+ payment.update(braintree_nonce: nil, braintree_token: nil)
62
+ expect(purchase.success?).to be false
63
+ end
64
+
65
+ it 'returns false with invalid token' do
66
+ token = 'sometoken'
67
+ payment.update(braintree_token: token)
68
+ expect(purchase.success?).to be false
69
+ end
70
+
71
+ context 'with advanced fraud tool enabled' do
72
+ before do
73
+ gateway.preferences[:advanced_fraud_data] = true
74
+ payment_source = create(:braintree_checkout_with_fraud_data)
75
+ end
76
+
77
+ it 'returns success' do
78
+ expect(purchase).to be_success
79
+ end
80
+
81
+ it 'returns fraud data' do
82
+ risk_data = purchase.transaction.risk_data
83
+ expect(risk_data.id.present? && risk_data.decision.present?).to be true
84
+ end
85
+ end
86
+
87
+ context 'with 3DSecure option turned on' do
88
+ before do
89
+ gateway.preferred_3dsecure = true
90
+ payment.update(braintree_nonce: 'fake-valid-debit-nonce')
91
+ end
92
+
93
+ it 'performs 3DSecure check' do
94
+ expect(purchase.success?).to be false
95
+ end
96
+
97
+ it 'returns error' do
98
+ response = purchase
99
+ expect(response.errors.size.zero?).to be true
100
+ expect(response.transaction.try(:gateway_rejection_reason)).to eq 'three_d_secure'
101
+ end
102
+ end
103
+
104
+ context 'using Vault' do
105
+ let(:user) { create(:user) }
106
+ before do
107
+ order.user = user
108
+ gateway.preferred_store_payments_in_vault = :store_all
109
+ end
110
+
111
+ it 'stores Transaction' do
112
+ card_vault_token = purchase.transaction.credit_card_details.token
113
+ expect { Braintree::PaymentMethod.find(card_vault_token) }.not_to raise_error
114
+ end
115
+
116
+ it 'saves Braintree::Address id to Spree::Address when address is being saved' do
117
+ gateway.preferred_pass_billing_and_shipping_address = true
118
+ address = create(:address)
119
+ order.ship_address = address
120
+ order.bill_address = address
121
+ order.save
122
+ purchase
123
+ order.reload
124
+
125
+ bill_id = order.billing_address.braintree_id
126
+ ship_id = order.shipping_address.braintree_id
127
+ expect(order.billing_address.braintree_id).to_not be_nil
128
+ expect(order.shipping_address.braintree_id).to_not be_nil
129
+ expect(bill_id).to eq ship_id
130
+ end
131
+
132
+ it 'saves unique Braintree::Addresses ids' do
133
+ gateway.preferred_pass_billing_and_shipping_address = true
134
+ ship_address = create(:address, first_name: 'foo')
135
+ bill_address = create(:address, first_name: 'bar')
136
+ order.ship_address = ship_address
137
+ order.bill_address = bill_address
138
+ order.save
139
+ purchase
140
+ order.reload
141
+
142
+ bill_id = order.billing_address.braintree_id
143
+ ship_id = order.shipping_address.braintree_id
144
+ expect(bill_id).to_not be_nil
145
+ expect(ship_id).to_not be_nil
146
+ expect(bill_id).to_not eq ship_id
147
+ end
148
+
149
+ it 'sends address data when address is new' do
150
+ gateway.preferred_pass_billing_and_shipping_address = true
151
+ ship_address = create(:address, first_name: 'foo')
152
+ bill_address = create(:address, first_name: 'bar')
153
+ order.ship_address = ship_address
154
+ order.bill_address = bill_address
155
+ order.save
156
+
157
+ utils = Spree::Gateway::BraintreeVzeroBase::Utils.new(gateway, order)
158
+ data = gateway.send('set_basic_purchase_data', {}, order, utils, order.total * 100)
159
+
160
+ expect(data['billing'][:first_name]).to eq bill_address.first_name
161
+ expect(data['shipping'][:first_name]).to eq ship_address.first_name
162
+ expect(data['billing_address_id']).to eq nil
163
+ expect(data['shipping_address_id']).to eq nil
164
+ end
165
+
166
+ it 'sends empty address id when address is already in vault' do
167
+ gateway.preferred_pass_billing_and_shipping_address = true
168
+ old_bill_address = create(:address, first_name: 'bar')
169
+ old_ship_address = create(:address, first_name: 'foo')
170
+ user = create(:user, bill_address_id: old_bill_address.id, ship_address_id: old_ship_address.id)
171
+ order.update(user_id: user.id)
172
+ order.ship_address = old_ship_address
173
+ order.bill_address = old_bill_address
174
+ order.save
175
+ purchase
176
+
177
+ ship_address = create(:address, old_ship_address.attributes.except('id', 'updated_at', 'created_at', 'braintree_id'))
178
+ bill_address = create(:address, old_bill_address.attributes.except('id', 'updated_at', 'created_at', 'braintree_id'))
179
+ other_order.ship_address = ship_address
180
+ other_order.bill_address = bill_address
181
+ other_order.save
182
+ user.update(bill_address_id: bill_address.id, ship_address_id: ship_address.id)
183
+ other_order.update(user_id: user.id)
184
+
185
+ utils = Spree::Gateway::BraintreeVzeroBase::Utils.new(gateway, other_order)
186
+ data = gateway.send('set_basic_purchase_data', {}, other_order, utils, other_order.total * 100)
187
+
188
+ expect(data['billing_address_id']).to eq old_bill_address.reload.braintree_id
189
+ expect(data['shipping_address_id']).to eq old_ship_address.reload.braintree_id
190
+ expect(data['billing']).to eq nil
191
+ expect(data['shipping']).to eq nil
192
+ end
193
+ end
194
+ end
195
+
196
+ describe '#update_states' do
197
+ before do
198
+ gateway.preferred_3dsecure = false
199
+ payment.update(amount: order.reload.total)
200
+ complete_order!
201
+ order.payments.first.source.update_attribute(:transaction_id, 'dw49zp') # use already settled transaction
202
+ end
203
+
204
+ let!(:result) { Spree::BraintreeCheckout.update_states }
205
+
206
+ it 'updates payment State' do
207
+ expect(result[:changed]).to eq 1
208
+ end
209
+
210
+ it 'does not update completed Checkout on subsequent runs' do
211
+ expect(result[:changed]).to eq 1
212
+ expect(Spree::BraintreeCheckout.update_states[:changed]).to eq 0
213
+ end
214
+
215
+ it 'updates Order payment_state when Checkout is updated' do
216
+ expect(order.reload.payment_state).to eq 'paid'
217
+ end
218
+
219
+ it 'updates Payment state when Checkout is updated' do
220
+ expect(order.reload.payments.first.state).to eq 'completed'
221
+ end
222
+ end
223
+
224
+ describe '#void' do
225
+ let(:void) { gateway.void(payment_source.reload.transaction_id, {}) }
226
+ let!(:prepare_gateway) { gateway.preferred_3dsecure = false }
227
+
228
+ context 'with voidable state' do
229
+ before do
230
+ complete_order!
231
+ void
232
+ end
233
+
234
+ it 'should change payment_source state to voided' do
235
+ expect(payment_source.reload.state).to eq 'voided'
236
+ end
237
+
238
+ it 'should change payment_source state to voided' do
239
+ expect(payment.reload.state).to eq 'void'
240
+ end
241
+ end
242
+
243
+ context 'with unvoidable state' do
244
+ before do
245
+ payment.update(braintree_nonce: 'fake-paypal-one-time-nonce')
246
+ complete_order!
247
+ void
248
+ end
249
+
250
+ it 'should not change payment_source state' do
251
+ expect(payment_source.reload.state).to eq 'settling'
252
+ end
253
+
254
+ it 'should not change payment_source state' do
255
+ expect(payment.reload.state).to eq 'completed'
256
+ end
257
+ end
258
+ end
259
+
260
+ describe '#settle' do
261
+ before do
262
+ gateway.update(auto_capture: false)
263
+ complete_order!
264
+ payment.reload
265
+ end
266
+
267
+ context 'settles authorized amount' do
268
+ it 'does not update Order payment_state' do
269
+ expect(order.payment_state).to eq 'balance_due'
270
+ payment.reload.settle!
271
+ expect(order.reload.payment_state).to eq 'balance_due'
272
+ end
273
+
274
+ it 'updates Payment state' do
275
+ expect(payment.state).to eq 'pending'
276
+ payment.reload.settle!
277
+ expect(payment.state).to eq 'processing'
278
+ end
279
+
280
+ it 'submits Transaction for settlement' do
281
+ expect(gateway.provider::Transaction.find(payment.response_code).status).to eq 'authorized'
282
+ payment.reload.settle!
283
+ expect(gateway.provider::Transaction.find(payment.response_code).status).to eq 'submitted_for_settlement'
284
+ end
285
+
286
+ it 'prepares Checkout for status updating' do
287
+ payment.reload.settle!
288
+ expect(Spree::BraintreeCheckout.not_in_state(Spree::BraintreeCheckout::FINAL_STATES).count).to eq 1
289
+ end
290
+ end
291
+ end
292
+
293
+ describe '#capture' do
294
+ # for Spree::Config.auto_capture_on_dispatch = true
295
+
296
+ before do
297
+ gateway.update(auto_capture: false)
298
+ complete_order!
299
+ payment.reload
300
+ end
301
+
302
+ context 'captures authorized amount' do
303
+ it 'updates Payment state' do
304
+ expect(payment).to be_pending
305
+ payment.reload.capture!
306
+ expect(payment).to be_completed
307
+ end
308
+ end
309
+ end
310
+
311
+ describe '#credit' do
312
+ let(:refund) { gateway.credit(1317, payment_source.reload.transaction_id, {}) }
313
+ let!(:prepare_gateway) { gateway.preferred_3dsecure = false }
314
+
315
+ context 'with refundable state' do
316
+ before do
317
+ payment.update(braintree_nonce: 'fake-paypal-one-time-nonce')
318
+ complete_order!
319
+ end
320
+
321
+ it 'should be a success' do
322
+ expect(refund.success?).to be true
323
+ expect(refund.transaction.amount).to eq 13.17
324
+ end
325
+ end
326
+
327
+ context 'with unrefundable state' do
328
+ before do
329
+ complete_order!
330
+ end
331
+
332
+ it 'should not be a success' do
333
+ expect(refund.success?).to be false
334
+ end
335
+ end
336
+ end
337
+ end
338
+
339
+ context 'with invalid credentials' do
340
+ let(:gateway) { create(:vzero_gateway, merchant_id: 'invalid_id') }
341
+
342
+ it 'raises Braintree error' do
343
+ expect { gateway.client_token }.to raise_error('Braintree::AuthenticationError')
344
+ end
345
+ end
346
+ end