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,28 @@
1
+ module Spree
2
+ class Gateway::BraintreeVzeroHostedFields < Spree::Gateway::BraintreeVzeroBase
3
+ preference :checkout_form_id, :string, default: 'checkout_form_payment'
4
+ preference :error_messages_container_id, :string, default: 'content'
5
+ preference :number_selector, :string, default: '#hosted-fields-number'
6
+ preference :number_placeholder, :string, default: 'Card Number'
7
+ preference :cvv_selector, :string, default: '#hosted-fields-cvv'
8
+ preference :cvv_placeholder, :string, default: 'Cvv code'
9
+ preference :expiration_date_selector, :string, default: '#hosted-fields-expiration-date'
10
+ preference :expiration_date_placeholder, :string, default: 'Card Expiration Date'
11
+ preference :store_payments_in_vault, :select, default: -> { { values: [:do_not_store, :store_only_on_success, :store_all] } }
12
+ preference :'3dsecure', :boolean_select, default: false
13
+
14
+ after_save :disable_dropin_gateways, if: proc {
15
+ active? && (saved_changes.keys & %w[active id]).any?
16
+ }
17
+
18
+ def method_type
19
+ 'braintree_vzero_hosted_fields'
20
+ end
21
+
22
+ private
23
+
24
+ def disable_dropin_gateways
25
+ Spree::Gateway::BraintreeVzeroDropInUi.update_all(active: false)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ module Spree
2
+ class Gateway::BraintreeVzeroPaypalExpress < Spree::Gateway::BraintreeVzeroBase
3
+ preference :paypal_display_on_cart, :boolean_select, default: true
4
+ preference :store_payments_in_vault, :select, default: -> { { values: [:do_not_store, :store_all] } }
5
+ preference :paypal_display_name, :string
6
+ preference :checkout_form_id, :string, default: 'checkout_form_payment'
7
+ preference :error_messages_container_id, :string, default: 'content'
8
+
9
+ def method_type
10
+ 'braintree_vzero_paypal_express'
11
+ end
12
+
13
+ def push_order_to_state(order, state, email)
14
+ order.update_column(:email, email)
15
+ order.next! until order.state.eql?(state)
16
+ order.update_column(:email, nil)
17
+ end
18
+
19
+ def find_identifier_hash(payment, utils)
20
+ token = payment[:braintree_token] || vaulted_token_by_email(payment, utils)
21
+ if token.present?
22
+ { payment_method_token: token }
23
+ else
24
+ { payment_method_nonce: payment[:braintree_nonce] }
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def vaulted_token_by_email(payment, utils)
31
+ utils.customer_payment_methods('paypal').find do |customer_payment|
32
+ customer_payment.try(:email).eql?(payment.source.paypal_email)
33
+ end.try(:token)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,153 @@
1
+ module Spree
2
+ module OrderDecorator
3
+ def self.prepended(base)
4
+ base.state_machine.before_transition to: :complete, do: :process_paypal_express_payments
5
+ end
6
+
7
+ def save_paypal_address(type, address_hash)
8
+ return if address_hash.blank?
9
+ address = Spree::Address.new(prepare_address_hash(address_hash))
10
+ return unless address.save
11
+
12
+ update_column("#{type}_id", address.id)
13
+ end
14
+
15
+ def save_paypal_payment(options)
16
+ options[:source] = Spree::BraintreeCheckout.create!(options.slice(:paypal_email, :advanced_fraud_data))
17
+ payments.create(options.slice(:braintree_nonce, :payment_method_id, :source))
18
+ end
19
+
20
+ def set_billing_address
21
+ return if bill_address_id
22
+ return unless ship_address_id
23
+
24
+ address = Spree::Address.create(shipping_address.attributes.except('id', 'updated_at', 'created_at', 'braintree_id'))
25
+ update_column(:bill_address_id, address.try(:id))
26
+ end
27
+
28
+ # override needed to add braintree source attribute
29
+ def update_from_params(params, permitted_params, request_env = {})
30
+ success = false
31
+ @updating_params = params
32
+ run_callbacks :updating_from_params do
33
+ # Set existing card after setting permitted parameters because
34
+ # rails would slice parameters containg ruby objects, apparently
35
+ existing_card_id = @updating_params[:order] ? @updating_params[:order].delete(:existing_card) : nil
36
+
37
+ attributes = @updating_params[:order] ? @updating_params[:order].permit(permitted_params).delete_if { |_k, v| v.nil? } : {}
38
+ payment_attributes = attributes[:payments_attributes].first if attributes[:payments_attributes].present?
39
+
40
+ if existing_card_id.present?
41
+ credit_card = Spree::CreditCard.find existing_card_id
42
+ if credit_card.user_id != user_id || credit_card.user_id.blank?
43
+ raise Spree::Core::GatewayError, Spree.t(:invalid_credit_card)
44
+ end
45
+
46
+ credit_card.verification_value = params[:cvc_confirm] if params[:cvc_confirm].present?
47
+
48
+ attributes[:payments_attributes].first[:source] = credit_card
49
+ attributes[:payments_attributes].first[:payment_method_id] = credit_card.payment_method_id
50
+ attributes[:payments_attributes].first.delete :source_attributes
51
+ end
52
+
53
+ if payment_attributes.present?
54
+ payment_attributes[:request_env] = request_env
55
+
56
+ if (token = payment_attributes[:braintree_token]).present?
57
+ payment_attributes[:source] = Spree::BraintreeCheckout.create_from_token(token, payment_attributes[:payment_method_id])
58
+ elsif payment_attributes[:braintree_nonce].present?
59
+ payment_attributes[:source] = Spree::BraintreeCheckout.create_from_params(params)
60
+ end
61
+ end
62
+
63
+ success = update(attributes)
64
+ set_shipments_cost if shipments.any?
65
+ end
66
+
67
+ @updating_params = nil
68
+ success
69
+ end
70
+
71
+ def payment_required?
72
+ # default payment processing requires order to have state == payment
73
+ # so there is no need to divide this method for checkout steps and actual payment processing
74
+ return false if paid_with_paypal_express?
75
+ total.to_f > 0.0
76
+ end
77
+
78
+ def confirmation_required?
79
+ Spree::Config[:always_include_confirm_step] ||
80
+ payments.valid.map(&:payment_method).compact.any?(&:payment_profiles_supported?) ||
81
+ # setting payment_profiles_supported? for braintree gateways would require few additional changes in payments profiles system
82
+ braintree_confirmation_required? || state == 'confirm'
83
+ end
84
+
85
+ def paid_with_braintree?
86
+ payments.valid.map(&:payment_method).compact.any? { |p| p.is_a?(Spree::Gateway::BraintreeVzeroBase) }
87
+ end
88
+
89
+ def paid_with_paypal_express?
90
+ payments.valid.map(&:payment_method).compact.any? { |p| p.is_a?(Spree::Gateway::BraintreeVzeroPaypalExpress) }
91
+ end
92
+
93
+ def invalidate_paypal_express_payments
94
+ return unless paid_with_paypal_express?
95
+
96
+ payments.valid.each do |payment|
97
+ payment.invalidate! if payment.payment_method.is_a?(Spree::Gateway::BraintreeVzeroPaypalExpress)
98
+ end
99
+ end
100
+
101
+ def no_phone_number?
102
+ [ship_address, bill_address].each do |address|
103
+ return true if address.try(:phone).eql?(I18n.t('braintree.phone_number_placeholder'))
104
+ end
105
+ false
106
+ end
107
+
108
+ def remove_phone_number_placeholder
109
+ [ship_address, bill_address].each do |address|
110
+ address.update_column(:phone, nil) if address.try(:phone).eql?(I18n.t('braintree.phone_number_placeholder'))
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ def braintree_confirmation_required?
117
+ paid_with_braintree? && state.eql?('payment')
118
+ end
119
+
120
+ def prepare_address_hash(hash)
121
+ hash.delete_if { |e| hash[e].eql?('undefined') }
122
+ country_id = Spree::Country.find_by(iso: hash.delete(:country)).try(:id)
123
+
124
+ hash[:country_id] = country_id
125
+ state_param = hash.delete(:state)
126
+ state = Spree::State.where('spree_states.abbr = :abbr OR upper(spree_states.name) = :name',
127
+ abbr: state_param, name: state_param.upcase).find_by(country_id: country_id)
128
+ hash[:state_id] = state.try(:id)
129
+ hash[:phone] ||= I18n.t('braintree.phone_number_placeholder')
130
+
131
+ return hash if hash[:full_name].blank?
132
+
133
+ full_name = hash.delete(:full_name).split(' ')
134
+ hash[:lastname] = full_name.slice!(-1)
135
+ hash[:firstname] = full_name.join(' ')
136
+ hash
137
+ end
138
+
139
+ def process_paypal_express_payments
140
+ return unless paid_with_paypal_express?
141
+
142
+ if payments.valid.empty?
143
+ order.errors.add(:base, Spree.t(:no_payment_found))
144
+ false
145
+ else
146
+ payments.valid.last.update(amount: order_total_after_store_credit)
147
+ process_payments!
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ ::Spree::Order.prepend(Spree::OrderDecorator)
@@ -0,0 +1,10 @@
1
+ module Spree
2
+ module PaymentDecorator
3
+ def update_order
4
+ # without reload order was updated with inaccurate data
5
+ order.reload && super
6
+ end
7
+ end
8
+ end
9
+
10
+ ::Spree::Payment.prepend(Spree::PaymentDecorator)
@@ -0,0 +1,61 @@
1
+ module Spree
2
+ module PaymentProcessingDecorator
3
+ def self.prepended(base)
4
+ base.delegate :settle, to: :provider
5
+ end
6
+
7
+ def settle!
8
+ handle_payment_preconditions { process_settle }
9
+ end
10
+
11
+ def gateway_action(source, action, success_state)
12
+ protect_from_connection_error do
13
+ response = payment_method.send(action, money.money.cents,
14
+ source,
15
+ gateway_options)
16
+ success_state = set_proper_state(success_state, response, action)
17
+ handle_response(response, success_state, :failure)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def process_settle
24
+ started_processing!
25
+ gateway_action(source, :settle, :started_processing)
26
+ end
27
+
28
+ def gateway_error(error)
29
+ if error.is_a? ActiveMerchant::Billing::Response
30
+ text = error.params['message'] || error.params['response_reason_text'] || error.message
31
+ elsif error.is_a? ActiveMerchant::ConnectionError
32
+ text = Spree.t(:unable_to_connect_to_gateway)
33
+ elsif error.is_a? Braintree::ErrorResult
34
+ text = error.message
35
+ else
36
+ text = error.to_s
37
+ end
38
+ logger.error(Spree.t(:gateway_error))
39
+ logger.error(" #{error.to_yaml}")
40
+ raise Spree::Core::GatewayError, text
41
+ end
42
+
43
+ def set_proper_state(current_state, response, action)
44
+ return current_state unless action.eql?(:purchase)
45
+ return current_state unless source.is_a?(Spree::BraintreeCheckout)
46
+ utils = Spree::Gateway::BraintreeVzeroBase::Utils.new(payment_method, order)
47
+ state = utils.map_payment_status(response.try(:transaction).try(:status))
48
+
49
+ case state
50
+ when 'completed'
51
+ 'complete'
52
+ when 'pending'
53
+ 'pend'
54
+ else
55
+ current_state
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ ::Spree::Payment.prepend(Spree::PaymentProcessingDecorator)
@@ -0,0 +1,54 @@
1
+ module Spree
2
+ module Preferences
3
+ module PreferableDecorator
4
+ private
5
+
6
+ def convert_preference_value(value, type)
7
+ case type
8
+ when :string, :text, :select
9
+ value.to_s
10
+ when :password
11
+ value.to_s
12
+ when :decimal
13
+ BigDecimal.new(value.to_s)
14
+ when :integer
15
+ value.to_i
16
+ when :boolean, :boolean_select
17
+ if value.is_a?(FalseClass) ||
18
+ value.nil? ||
19
+ value == 0 ||
20
+ value =~ /^(f|false|0)$/i ||
21
+ (value.respond_to?(:empty?) && value.empty?)
22
+ false
23
+ else
24
+ true
25
+ end
26
+ when :array
27
+ value.is_a?(Array) ? value : Array.wrap(value)
28
+ when :hash
29
+ case value.class.to_s
30
+ when 'Hash'
31
+ value
32
+ when 'String'
33
+ # only works with hashes whose keys are strings
34
+ JSON.parse value.gsub('=>', ':')
35
+ when 'Array'
36
+ begin
37
+ value.try(:to_h)
38
+ rescue TypeError
39
+ Hash[*value]
40
+ rescue ArgumentError
41
+ raise 'An even count is required when passing an array to be converted to a hash'
42
+ end
43
+ else
44
+ value.class.ancestors.include?(Hash) ? value : {}
45
+ end
46
+ else
47
+ value
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ ::Spree::Preferences::Preferable.prepend(Spree::Preferences::PreferableDecorator)
@@ -0,0 +1,8 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/orders/customer_details/_form',
3
+ name: 'Add warning for braintree admins',
4
+ insert_after: '[data-hook="customer_fields"]',
5
+ text: '<div class="alert alert-warning">
6
+ <%= I18n.t("braintree.admin.guest_checkout_warning") %>
7
+ </div>'
8
+ )
@@ -0,0 +1,10 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/payment_methods/_form',
3
+ name: 'Use custom form partial for braintree vzero payment method',
4
+ surround: '[data-hook="admin_payment_method_form_fields"]',
5
+ text: '<% if @object.kind_of?(Spree::Gateway::BraintreeVzeroBase) %>
6
+ <%= render "braintree_vzero_form", f: f %>
7
+ <% else %>
8
+ <%= render_original %>
9
+ <% end %>'
10
+ )
@@ -0,0 +1,23 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/shared/_order_summary',
3
+ name: 'Add Risk ID & Risk Decision to Order Summary',
4
+ insert_bottom: 'tbody.additional-info',
5
+ text: '<% if @order.paid_with_braintree? %>
6
+ <tr>
7
+ <td data-hook="admin_order_tab_risk_id">
8
+ <strong><%= Spree.t("admin.risk_id") %>:</strong>
9
+ </td>
10
+ <td id="risk_id">
11
+ <%= @order.payments.valid.take.try(:source).try(:risk_id) %>
12
+ </td>
13
+ </tr>
14
+ <tr>
15
+ <td data-hook="admin_order_tab_risk_decision">
16
+ <strong><%= Spree.t("admin.risk_decision") %>:</strong>
17
+ </td>
18
+ <td id="risk_id">
19
+ <%= @order.payments.valid.take.try(:source).try(:risk_decision) %>
20
+ </td>
21
+ </tr>
22
+ <% end %>'
23
+ )
@@ -0,0 +1,13 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/shared/_refunds',
3
+ name: 'Remove refund edit button',
4
+ surround: 'erb[loud]:contains("edit_admin_order_payment_refund_path")',
5
+ text: '<% unless refund.payment.source_type.eql?(Spree::BraintreeCheckout.to_s) %><%= render_original %><% end %>'
6
+ )
7
+
8
+ Deface::Override.new(
9
+ virtual_path: 'spree/admin/shared/_refunds',
10
+ name: 'Fix spree identifier search',
11
+ replace: 'erb[loud]:contains("refund.payment.identifier")',
12
+ text: '<%= refund.payment.number %>'
13
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/checkout/_new_user',
3
+ name: 'Set proper email',
4
+ insert_after: 'erb[loud]:contains("form_for")',
5
+ text: '<% @user.email ||= params[:paypal_email] %>'
6
+ )
@@ -0,0 +1,20 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/checkout/_payment',
3
+ name: 'Modifies Paypal Express payment method on checkout',
4
+ surround: 'erb[loud]:contains("Spree.t(method.name, :scope => :payment_methods, :default => method.name)")',
5
+ text: %{
6
+ <% if method.is_a?(Spree::Gateway::BraintreeVzeroPaypalExpress) %>
7
+ <img src="https://www.paypalobjects.com/webstatic/mktg/logo/pp_cc_mark_37x23.jpg" border="0" alt="PayPal Logo">
8
+ <a href="https://www.paypal.com/webapps/mpp/paypal-popup" title="<%= Spree.t(:how_paypal_works) %>" onclick="javascript:window.open('https://www.paypal.com/webapps/mpp/paypal-popup', 'WIPaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=1060, height=700'); return false;"> <%= Spree.t(:what_is_paypal) %></a>
9
+ <% else %>
10
+ <%= render_original %>
11
+ <% end %>
12
+ }
13
+ )
14
+
15
+ Deface::Override.new(
16
+ virtual_path: 'spree/checkout/_payment',
17
+ name: 'Adds necessary buttons for Braintree payment methods',
18
+ insert_after: 'erb[loud]:contains("submit_tag")',
19
+ partial: 'spree/checkout/payment/braintree_vzero/buttons'
20
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/checkout/registration',
3
+ name: 'Set proper email',
4
+ insert_after: 'erb[loud]:contains("form_for")',
5
+ text: '<% @order.email ||= params[:paypal_email] %>'
6
+ )