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