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,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