spree_braintree_vzero 3.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +15 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +63 -0
- data/Appraisals +45 -0
- data/CONTRIBUTING.md +28 -0
- data/Gemfile +14 -0
- data/LICENSE +26 -0
- data/README.md +83 -0
- data/Rakefile +21 -0
- data/app/assets/images/credit_cards/icons/jcb.png +0 -0
- data/app/assets/javascripts/spree/backend/payments.js +19 -0
- data/app/assets/javascripts/spree/backend/spree_braintree_vzero.js +81 -0
- data/app/assets/javascripts/spree/frontend/spree_braintree_vzero.js +68 -0
- data/app/assets/stylesheets/spree/backend/spree_braintree_vzero.css +5 -0
- data/app/controllers/spree/admin/payments_controller_decorator.rb +43 -0
- data/app/controllers/spree/api/v1/braintree_client_token_controller.rb +31 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +38 -0
- data/app/controllers/spree/orders_controller_decorator.rb +62 -0
- data/app/controllers/spree/user_sessions_controller_decorator.rb +15 -0
- data/app/helpers/spree/admin/decorated_navigation_helper.rb +10 -0
- data/app/helpers/spree/admin/payment_methods_helper.rb +101 -0
- data/app/helpers/spree/braintree_helper.rb +27 -0
- data/app/models/braintree/successful_result_decorator.rb +21 -0
- data/app/models/spree/address_decorator.rb +18 -0
- data/app/models/spree/braintree_checkout.rb +105 -0
- data/app/models/spree/gateway/braintree_vzero_base.rb +168 -0
- data/app/models/spree/gateway/braintree_vzero_base/address.rb +33 -0
- data/app/models/spree/gateway/braintree_vzero_base/braintree_user.rb +25 -0
- data/app/models/spree/gateway/braintree_vzero_base/purchase_data.rb +48 -0
- data/app/models/spree/gateway/braintree_vzero_base/transaction.rb +39 -0
- data/app/models/spree/gateway/braintree_vzero_base/utils.rb +108 -0
- data/app/models/spree/gateway/braintree_vzero_drop_in_ui.rb +24 -0
- data/app/models/spree/gateway/braintree_vzero_hosted_fields.rb +28 -0
- data/app/models/spree/gateway/braintree_vzero_paypal_express.rb +36 -0
- data/app/models/spree/order_decorator.rb +153 -0
- data/app/models/spree/payment_decorator.rb +10 -0
- data/app/models/spree/payment_processing_decorator.rb +61 -0
- data/app/models/spree/preferences/preferable_decorator.rb +54 -0
- data/app/overrides/spree/admin/orders/customer_details/_form.rb +8 -0
- data/app/overrides/spree/admin/payment_methods/_form.rb +10 -0
- data/app/overrides/spree/admin/shared/_order_summary.rb +23 -0
- data/app/overrides/spree/admin/shared/_refunds.rb +13 -0
- data/app/overrides/spree/checkout/_new_user.rb +6 -0
- data/app/overrides/spree/checkout/_payment.rb +20 -0
- data/app/overrides/spree/checkout/registration.rb +6 -0
- data/app/overrides/spree/orders/edit.rb +6 -0
- data/app/overrides/spree/shared/_order_details.rb +13 -0
- data/app/overrides/spree/shared/_payment.rb +28 -0
- data/app/views/spree/admin/payment_methods/_braintree_vzero_form.html.erb +83 -0
- data/app/views/spree/admin/payments/source_forms/_braintree_vzero_dropin_ui.html.erb +1 -0
- data/app/views/spree/admin/payments/source_forms/_braintree_vzero_hosted_fields.html.erb +1 -0
- data/app/views/spree/admin/payments/source_forms/_braintree_vzero_paypal_express.html.erb +1 -0
- data/app/views/spree/admin/payments/source_forms/braintree_vzero/_payments.html.erb +87 -0
- data/app/views/spree/admin/payments/source_views/_braintree_vzero_dropin_ui.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_braintree_vzero_hosted_fields.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_braintree_vzero_paypal_express.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/braintree_vzero/_payment.html.erb +17 -0
- data/app/views/spree/braintree_vzero/_paypal_checkout.html.erb +87 -0
- data/app/views/spree/checkout/payment/_braintree_vzero_dropin_ui.html.erb +4 -0
- data/app/views/spree/checkout/payment/_braintree_vzero_hosted_fields.html.erb +4 -0
- data/app/views/spree/checkout/payment/_braintree_vzero_paypal_express.html.erb +4 -0
- data/app/views/spree/checkout/payment/braintree_vzero/_buttons.html.erb +11 -0
- data/app/views/spree/checkout/payment/braintree_vzero/_dropin_on_error_callback.js.erb +3 -0
- data/app/views/spree/checkout/payment/braintree_vzero/_dropin_on_ready_callback.js.erb +1 -0
- data/app/views/spree/checkout/payment/braintree_vzero/_hosted_fields_on_field_event_callback.js.erb +12 -0
- data/app/views/spree/checkout/payment/braintree_vzero/_hosted_fields_styles.js.erb +29 -0
- data/app/views/spree/checkout/payment/braintree_vzero/_payment.html.erb +84 -0
- data/app/views/spree/checkout/payment/braintree_vzero/_three_d_secure.html.erb +218 -0
- data/app/views/spree/shared/braintree_vzero/_dropin.js.erb +70 -0
- data/app/views/spree/shared/braintree_vzero/_hosted.js.erb +66 -0
- data/app/views/spree/shared/braintree_vzero/_paypal.js.erb +39 -0
- data/bin/rails +7 -0
- data/config/initializers/extend_spree_permitted_checkout_attributes.rb +5 -0
- data/config/initializers/prepend_helpers.rb +1 -0
- data/config/locales/en.yml +79 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20150904143013_create_spree_braintree_checkouts.rb +9 -0
- data/db/migrate/20151002094655_add_braintree_id_to_spree_addresses.rb +5 -0
- data/db/migrate/20151018123907_add_braintree_token_and_nonce_to_spree_payments.rb +6 -0
- data/db/migrate/20151027135109_add_paypal_email_to_spree_braintree_checkout.rb +5 -0
- data/db/migrate/20151028095515_add_advanced_fraud_data_to_spree_braintree_checkout.rb +5 -0
- data/db/migrate/20151202095956_add_risk_id_and_risk_decision_to_spree_braintree_checkouts.rb +6 -0
- data/db/migrate/20151211100203_add_braintree_last_digits_and_braintree_card_type_to_spree_braintree_checkouts.rb +6 -0
- data/db/migrate/20160112153422_add_admin_payment_to_spree_braintree_checkout.rb +5 -0
- data/gemfiles/spree_3_5.gemfile +12 -0
- data/gemfiles/spree_3_5_spree_auth_devise.gemfile +13 -0
- data/gemfiles/spree_3_7.gemfile +12 -0
- data/gemfiles/spree_3_7_spree_auth_devise.gemfile +13 -0
- data/gemfiles/spree_4_0.gemfile +11 -0
- data/gemfiles/spree_4_0_spree_auth_devise.gemfile +12 -0
- data/gemfiles/spree_master.gemfile +11 -0
- data/gemfiles/spree_master_spree_auth_devise.gemfile +12 -0
- data/lib/generators/spree_braintree_vzero/install/install_generator.rb +34 -0
- data/lib/spree_braintree_vzero.rb +6 -0
- data/lib/spree_braintree_vzero/engine.rb +28 -0
- data/lib/spree_braintree_vzero/factories.rb +10 -0
- data/lib/spree_braintree_vzero/railtie.rb +8 -0
- data/lib/spree_braintree_vzero/version.rb +17 -0
- data/lib/tasks/spree_braintree_vzero.rake +6 -0
- data/spec/controllers/spree/api/v1/braintree_client_token_controller_spec.rb +49 -0
- data/spec/controllers/spree/checkout_controller_spec.rb +85 -0
- data/spec/controllers/spree/orders_controller_spec.rb +97 -0
- data/spec/factories/braintree_checkout_factory.rb +7 -0
- data/spec/factories/braintree_gateway_factory.rb +35 -0
- data/spec/factories/payment_factory_decorator.rb +28 -0
- data/spec/features/spree/admin/log_entries_spec.rb +63 -0
- data/spec/models/gateway/braintree_vzero_base/address_spec.rb +28 -0
- data/spec/models/gateway/braintree_vzero_base/purchase_data_spec.rb +57 -0
- data/spec/models/gateway/braintree_vzero_base_spec.rb +346 -0
- data/spec/models/gateway/braintree_vzero_dropin_ui_spec.rb +35 -0
- data/spec/models/gateway/braintree_vzero_hosted_fields_spec.rb +35 -0
- data/spec/models/spree/order_spec.rb +186 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/support/vcr.rb +10 -0
- data/spec/vcr/Log_entries/with_a_failed_log_entry/shows_a_failed_attempt.yml +91 -0
- data/spec/vcr/Log_entries/with_a_successful_log_entry/shows_a_successful_attempt.yml +113 -0
- data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/guest_checkout/returns_proper_json_data_when_gateway_not_specified.yml +90 -0
- data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/guest_checkout/returns_proper_json_data_when_gateway_specified.yml +90 -0
- data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/user_checkout/returns_proper_json_data_when_gateway_not_specified.yml +191 -0
- data/spec/vcr/Spree_Api_V1_BraintreeClientTokenController/POST_create/user_checkout/returns_proper_json_data_when_gateway_specified.yml +191 -0
- data/spec/vcr/Spree_CheckoutController/_update/braintree_payment/advanced_fraud_data_in_source_should_be_updated.yml +71 -0
- data/spec/vcr/Spree_CheckoutController/_update/braintree_payment/when_token_credit_card_data_in_source_should_be_updated_from_Braintree_Vault.yml +139 -0
- data/spec/vcr/Spree_CheckoutController/_update/braintree_paypal_express_payment/amount_in_payment_should_be_updated.yml +280 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_capture/captures_authorized_amount/updates_Payment_state.yml +206 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_credit/with_refundable_state/should_be_a_success.yml +211 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_credit/with_unrefundable_state/should_not_be_a_success.yml +177 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/data_from_admin_panel/should_include_only_essential_data.yml +78 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/does_not_store_Transaction_in_Vault_by_default.yml +111 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_false_with_invalid_nonce.yml +88 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_false_with_invalid_token.yml +88 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_success_with_valid_token.yml +113 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/returns_suceess_with_valid_nonce.yml +111 -0
- 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
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/using_Vault/saves_unique_Braintree_Addresses_ids.yml +143 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/using_Vault/sends_empty_address_id_when_address_is_already_in_vault.yml +553 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/using_Vault/stores_Transaction.yml +181 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_3DSecure_option_turned_on/performs_3DSecure_check.yml +112 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_3DSecure_option_turned_on/returns_error.yml +112 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_advanced_fraud_tool_enabled/returns_fraud_data.yml +111 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_purchase/with_advanced_fraud_tool_enabled/returns_success.yml +111 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/does_not_update_Order_payment_state.yml +204 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/prepares_Checkout_for_status_updating.yml +204 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/submits_Transaction_for_settlement.yml +377 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_settle/settles_authorized_amount/updates_Payment_state.yml +203 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/does_not_update_completed_Checkout_on_subsequent_runs.yml +202 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/updates_Order_payment_state_when_Checkout_is_updated.yml +202 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/updates_Payment_state_when_Checkout_is_updated.yml +202 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_update_states/updates_payment_State.yml +202 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_void/with_unvoidable_state/should_not_change_payment_source_state.yml +178 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/_void/with_voidable_state/should_change_payment_source_state_to_voided.yml +199 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/generates_token_for_User_registered_in_Braintree.yml +356 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/generates_token_for_new_User.yml +189 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/valid_credentials/generates_token_without_User.yml +89 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase/with_invalid_credentials/raises_Braintree_error.yml +62 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/creates_Braintree_Address.yml +84 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/deletes_Braintree_Address.yml +141 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/finds_Braintree_Address.yml +148 -0
- data/spec/vcr/Spree_Gateway_BraintreeVzeroBase_Address/_create/updates_Braintree_Address.yml +154 -0
- data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/with_auto_capture/should_complete_payment.yml +116 -0
- data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/with_auto_capture/should_update_payment_s_response_code.yml +111 -0
- 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
- data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/without_auto_capture/should_pend_payment.yml +111 -0
- data/spec/vcr/Spree_Order/complete_with_braintree_vzero_standard_payment/without_auto_capture/should_update_payment_s_response_code.yml +111 -0
- 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
- data/spree_braintree_vzero.gemspec +52 -0
- data/vendor/assets/javascripts/maskedinput/jquery.maskedinput.min.js +7 -0
- metadata +643 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
module PaymentsControllerDecorator
|
4
|
+
def create
|
5
|
+
invoke_callbacks(:create, :before)
|
6
|
+
@payment ||= @order.payments.build(object_params)
|
7
|
+
# not only credit card may require source
|
8
|
+
if @payment.payment_method.source_required?
|
9
|
+
if params[:card].present? && params[:card] != 'new'
|
10
|
+
@payment.source = @payment.payment_method.payment_source_class.find_by_id(params[:card])
|
11
|
+
elsif @payment.payment_source.is_a?(Spree::Gateway::BraintreeVzeroBase)
|
12
|
+
@payment.braintree_token = params[:payment_method_token]
|
13
|
+
@payment.braintree_nonce = params[:payment_method_nonce]
|
14
|
+
@payment.source = Spree::BraintreeCheckout.create!(admin_payment: true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
if @payment.save
|
20
|
+
invoke_callbacks(:create, :after)
|
21
|
+
# Transition order as far as it will go.
|
22
|
+
while @order.next; end
|
23
|
+
# If "@order.next" didn't trigger payment processing already (e.g. if the order was
|
24
|
+
# already complete) then trigger it manually now
|
25
|
+
@payment.process! if @order.completed? && @payment.checkout?
|
26
|
+
flash[:success] = flash_message_for(@payment, :successfully_created)
|
27
|
+
redirect_to admin_order_payments_path(@order)
|
28
|
+
else
|
29
|
+
invoke_callbacks(:create, :fails)
|
30
|
+
flash[:error] = Spree.t(:payment_could_not_be_created)
|
31
|
+
render :new
|
32
|
+
end
|
33
|
+
rescue Spree::Core::GatewayError => e
|
34
|
+
invoke_callbacks(:create, :fails)
|
35
|
+
flash[:error] = e.message.to_s
|
36
|
+
redirect_to new_admin_order_payment_path(@order)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
::Spree::Admin::PaymentsController.prepend(Spree::Admin::PaymentsControllerDecorator)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Spree
|
2
|
+
module Api
|
3
|
+
module V1
|
4
|
+
class BraintreeClientTokenController < Spree::Api::BaseController
|
5
|
+
skip_before_action :authenticate_user
|
6
|
+
|
7
|
+
before_action :find_order, only: :create
|
8
|
+
|
9
|
+
def create
|
10
|
+
gateway = if params[:payment_method_id]
|
11
|
+
Spree::Gateway::BraintreeVzeroBase.find(params[:payment_method_id])
|
12
|
+
else
|
13
|
+
Spree::Gateway::BraintreeVzeroBase.active.first
|
14
|
+
end
|
15
|
+
|
16
|
+
render json: {
|
17
|
+
client_token: gateway.client_token(@order, @current_api_user),
|
18
|
+
payment_method_id: gateway.id
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# We're skipping permission check for order, because it is needed only to get a currency
|
25
|
+
def find_order
|
26
|
+
@order = Spree::Order.find_by(number: params[:order_number])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Spree
|
2
|
+
module CheckoutControllerDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.include Spree::BraintreeHelper
|
5
|
+
base.helper_method [:asset_available?, :options_from_braintree_payments]
|
6
|
+
base.after_action :allow_braintree_iframe
|
7
|
+
base.after_action :update_source_data, only: :update, if: proc { params[:state].eql?('payment') }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def allow_braintree_iframe
|
13
|
+
response.headers['X-Frame-Options'] = 'ALLOW-FROM https://assets.braintreegateway.com'
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_registration
|
17
|
+
return unless Spree::Auth::Config[:registration_step]
|
18
|
+
return if spree_current_user || current_order.email
|
19
|
+
store_location
|
20
|
+
redirect_to spree.checkout_registration_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_source_data
|
24
|
+
return true unless current_order
|
25
|
+
payment = current_order.payments.last
|
26
|
+
return true unless payment
|
27
|
+
source = payment.source
|
28
|
+
return true unless source.is_a?(Spree::BraintreeCheckout)
|
29
|
+
update_advanced_fraud_data(source)
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_advanced_fraud_data(source)
|
33
|
+
source.update(advanced_fraud_data: params[:device_data])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
::Spree::CheckoutController.prepend(Spree::CheckoutControllerDecorator)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Spree
|
2
|
+
module OrdersControllerDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.include Spree::BraintreeHelper
|
5
|
+
base.helper_method [:asset_available?, :options_from_braintree_payments]
|
6
|
+
base.before_action :process_paypal_express, only: :update
|
7
|
+
end
|
8
|
+
|
9
|
+
def process_paypal_express
|
10
|
+
if params[:paypal].blank? || params[:paypal][:payment_method_nonce].blank?
|
11
|
+
# when user goes back from checkout, paypal express payments should be invalidated to ensure standard checkout flow
|
12
|
+
current_order.invalidate_paypal_express_payments
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
payment_method = Spree::PaymentMethod.find_by_id(params[:paypal][:payment_method_id])
|
16
|
+
return true unless payment_method
|
17
|
+
|
18
|
+
email = params[:order][:email]
|
19
|
+
# when user goes back from checkout, order's state should be resetted to ensure paypal checkout flow
|
20
|
+
current_order.state = 'cart'
|
21
|
+
payment_method.push_order_to_state(current_order, 'address', email)
|
22
|
+
current_order.save_paypal_payment(payment_params)
|
23
|
+
|
24
|
+
manage_paypal_addresses
|
25
|
+
current_order.remove_phone_number_placeholder
|
26
|
+
|
27
|
+
redirect_to checkout_state_path(current_order.state, paypal_email: email)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def address_params(key)
|
33
|
+
params[:order].require(key).permit(:firstname, :lastname, :zipcode, :city, :address1, :address2, :phone, :full_name, :country, :state)
|
34
|
+
end
|
35
|
+
|
36
|
+
def payment_params
|
37
|
+
{
|
38
|
+
braintree_nonce: params[:paypal][:payment_method_nonce],
|
39
|
+
payment_method_id: params[:paypal][:payment_method_id],
|
40
|
+
paypal_email: params[:order][:email],
|
41
|
+
advanced_fraud_data: params[:device_data]
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def manage_paypal_addresses
|
46
|
+
# addresses need to be cleared for restarted checkout orders
|
47
|
+
current_order.ship_address_id = nil
|
48
|
+
current_order.bill_address_id = nil
|
49
|
+
|
50
|
+
%w(ship_address bill_address).each do |address_type|
|
51
|
+
next if params[:order][address_type].blank?
|
52
|
+
current_order.save_paypal_address(address_type, address_params(address_type))
|
53
|
+
end
|
54
|
+
current_order.set_billing_address
|
55
|
+
return false if current_order.no_phone_number?
|
56
|
+
|
57
|
+
current_order.ship_address && current_order.bill_address
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
::Spree::OrdersController.prepend(Spree::OrdersControllerDecorator)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Spree
|
2
|
+
module UserSessionsControllerDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.before_action :associate_user, only: :create
|
5
|
+
end
|
6
|
+
|
7
|
+
def current_order_params
|
8
|
+
{ currency: current_currency, guest_token: cookies.signed[:guest_token], store_id: current_store.id }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
if defined?(::Spree::UserSessionsController)
|
14
|
+
::Spree::UserSessionsController.prepend(Spree::UserSessionsControllerDecorator)
|
15
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
module PaymentMethodsHelper
|
4
|
+
def preference_field_for(form, field, options)
|
5
|
+
case options[:type]
|
6
|
+
when :integer
|
7
|
+
form.text_field(field, preference_field_options(options))
|
8
|
+
when :boolean
|
9
|
+
form.check_box(field, preference_field_options(options))
|
10
|
+
when :string
|
11
|
+
if field.eql?('preferred_descriptor_name')
|
12
|
+
content_tag(:div,
|
13
|
+
Spree.t('descriptor_name_information_box_text').html_safe,
|
14
|
+
class: 'alert alert-warning'
|
15
|
+
)
|
16
|
+
end.to_s.html_safe +
|
17
|
+
form.text_field(field, preference_field_options(options))
|
18
|
+
when :password
|
19
|
+
form.password_field(field, preference_field_options(options))
|
20
|
+
when :text
|
21
|
+
form.text_area(field, preference_field_options(options))
|
22
|
+
when :boolean_select
|
23
|
+
label_tag(field, Spree.t(field))
|
24
|
+
form.select(field, {
|
25
|
+
Spree.t(:enabled) => true,
|
26
|
+
Spree.t(:disabled) => false
|
27
|
+
},
|
28
|
+
{},
|
29
|
+
class: 'select2')
|
30
|
+
when :select
|
31
|
+
label_tag(field, Spree.t(field))
|
32
|
+
form.select(field, options_for_select(options[:values].map { |key| [I18n.t(key, scope: 'braintree.preferences'), key] }, options[:selected]), {}, class: 'select2')
|
33
|
+
else
|
34
|
+
form.text_field(field, preference_field_options(options))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def preference_field_tag(name, value, options)
|
39
|
+
case options[:type]
|
40
|
+
when :integer
|
41
|
+
text_field_tag(name, value, preference_field_options(options))
|
42
|
+
when :boolean
|
43
|
+
hidden_field_tag(name, 0, id: "#{name}_hidden") +
|
44
|
+
check_box_tag(name, 1, value, preference_field_options(options))
|
45
|
+
when :string
|
46
|
+
text_field_tag(name, value, preference_field_options(options))
|
47
|
+
when :password
|
48
|
+
password_field_tag(name, value, preference_field_options(options))
|
49
|
+
when :text
|
50
|
+
text_area_tag(name, value, preference_field_options(options))
|
51
|
+
when :boolean_select
|
52
|
+
select_tag(name, value, preference_field_options(options))
|
53
|
+
when :select
|
54
|
+
select_tag(name, value, preference_field_options(options))
|
55
|
+
else
|
56
|
+
text_field_tag(name, value, preference_field_options(options))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def preference_fields(object, form)
|
61
|
+
return unless object.respond_to?(:preferences)
|
62
|
+
|
63
|
+
get_preference_fields(object, object.preferences.keys, form)
|
64
|
+
end
|
65
|
+
|
66
|
+
def braintree_basic_preference_fields(object, form)
|
67
|
+
return unless object.respond_to?(:preferences)
|
68
|
+
|
69
|
+
keys = object.preferences.slice(*basic_braintree_preference_keys).keys
|
70
|
+
get_preference_fields(object, keys, form)
|
71
|
+
end
|
72
|
+
|
73
|
+
def braintree_advanced_preference_fields(object, form)
|
74
|
+
return unless object.respond_to?(:preferences)
|
75
|
+
|
76
|
+
keys = object.preferences.keys.reverse - basic_braintree_preference_keys
|
77
|
+
keys_left, keys_right = keys.each_slice((keys.size / 2.0).ceil).to_a
|
78
|
+
|
79
|
+
content_tag(:div, get_preference_fields(object, keys_left, form), class: 'col-md-6') +
|
80
|
+
content_tag(:div, get_preference_fields(object, keys_right, form), class: 'col-md-6')
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_preference_fields(object, keys, form)
|
84
|
+
keys.reject { |k| k == :currency_merchant_accounts }.map do |key|
|
85
|
+
next unless object.has_preference?(key)
|
86
|
+
|
87
|
+
content_tag(:div, class: 'form-group', 'data-hook' => "preferred_#{key}") do
|
88
|
+
form.label("preferred_#{key}", Spree.t(key) + ': ') +
|
89
|
+
preference_field_for(form, "preferred_#{key}", type: object.preference_type(key),
|
90
|
+
values: object.send("preferred_#{key}_default").is_a?(Hash) ? object.send("preferred_#{key}_default")[:values] : nil,
|
91
|
+
selected: object.preferences[key])
|
92
|
+
end
|
93
|
+
end.join(' ').html_safe
|
94
|
+
end
|
95
|
+
|
96
|
+
def basic_braintree_preference_keys
|
97
|
+
%i[merchant_id public_key private_key server test_mode]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spree
|
2
|
+
module BraintreeHelper
|
3
|
+
def options_from_braintree_payments(payment_methods, include_empty = false)
|
4
|
+
additional_options = if include_empty
|
5
|
+
["<option value=''>#{t('braintree.checkout.blank_saved_payment_method')}</option>"]
|
6
|
+
else
|
7
|
+
[]
|
8
|
+
end
|
9
|
+
additional_options + payment_methods.map do |method|
|
10
|
+
text = if method.is_a?(Braintree::CreditCard)
|
11
|
+
Spree.t('admin.vaulted_payments.credit_card', card_type: method.card_type, last_4: method.last_4)
|
12
|
+
elsif method.is_a?(Braintree::PayPalAccount)
|
13
|
+
Spree.t('admin.vaulted_payments.paypal', email: method.email)
|
14
|
+
end
|
15
|
+
"<option value='#{method.token}'>#{text}</option>"
|
16
|
+
end.join.html_safe
|
17
|
+
end
|
18
|
+
|
19
|
+
def asset_available?(logical_path)
|
20
|
+
if Rails.configuration.assets.compile
|
21
|
+
Rails.application.precompiled_assets.include? logical_path
|
22
|
+
else
|
23
|
+
Rails.application.assets_manifest.assets[logical_path].present?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Braintree
|
2
|
+
module SuccessfulResultDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.mattr_reader :authorization, :message
|
5
|
+
end
|
6
|
+
|
7
|
+
def authorization
|
8
|
+
transaction.id
|
9
|
+
end
|
10
|
+
|
11
|
+
def avs_result
|
12
|
+
{ code: transaction.avs_street_address_response_code }.with_indifferent_access
|
13
|
+
end
|
14
|
+
|
15
|
+
def cvv_result
|
16
|
+
{ code: transaction.cvv_response_code, message: nil }.with_indifferent_access
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
::Braintree::SuccessfulResult.prepend(Braintree::SuccessfulResultDecorator)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Spree
|
2
|
+
module AddressDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.scope :vaulted_duplicates, ->(address) do
|
5
|
+
where.not(id: address.id).
|
6
|
+
where.not(braintree_id: nil).
|
7
|
+
where(address.attributes.except('id', 'updated_at', 'created_at', 'braintree_id'))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def same_as?(other)
|
12
|
+
return false if other.nil?
|
13
|
+
attributes.except('id', 'updated_at', 'created_at', 'braintree_id') == other.attributes.except('id', 'updated_at', 'created_at', 'braintree_id')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
::Spree::Address.prepend(Spree::AddressDecorator)
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Spree
|
2
|
+
class BraintreeCheckout < ActiveRecord::Base
|
3
|
+
scope :in_state, ->(state) { where(state: state) }
|
4
|
+
scope :not_in_state, ->(state) { where.not(state: state) }
|
5
|
+
|
6
|
+
after_commit :update_payment_and_order
|
7
|
+
|
8
|
+
FINAL_STATES = %w(authorization_expired processor_declined gateway_rejected failed voided settled settlement_declined refunded released).freeze
|
9
|
+
|
10
|
+
has_one :payment, foreign_key: :source_id, as: :source, class_name: 'Spree::Payment'
|
11
|
+
has_one :order, through: :payment
|
12
|
+
|
13
|
+
def self.create_from_params(params)
|
14
|
+
type = braintree_card_type_to_spree(params[:braintree_card_type])
|
15
|
+
create!(paypal_email: params[:paypal_email],
|
16
|
+
braintree_last_digits: params[:braintree_last_two],
|
17
|
+
braintree_card_type: type)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.create_from_token(token, payment_method_id)
|
21
|
+
gateway = Spree::PaymentMethod.find(payment_method_id)
|
22
|
+
vaulted_payment_method = gateway.vaulted_payment_method(token)
|
23
|
+
type = braintree_card_type_to_spree(vaulted_payment_method.try(:card_type))
|
24
|
+
create!(paypal_email: vaulted_payment_method.try(:email),
|
25
|
+
braintree_last_digits: vaulted_payment_method.try(:last_4),
|
26
|
+
braintree_card_type: type)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.update_states
|
30
|
+
braintree = Gateway::BraintreeVzeroBase.first.provider
|
31
|
+
result = { changed: 0, unchanged: 0 }
|
32
|
+
not_in_state(FINAL_STATES).find_each do |checkout|
|
33
|
+
checkout.state = braintree::Transaction.find(checkout.transaction_id).status
|
34
|
+
if checkout.state_changed?
|
35
|
+
result[:changed] += 1
|
36
|
+
checkout.save
|
37
|
+
else
|
38
|
+
result[:unchanged] += 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_state
|
45
|
+
status = Transaction.new(Gateway::BraintreeVzeroBase.first.provider, transaction_id).status
|
46
|
+
payment.send(payment_action(status))
|
47
|
+
status
|
48
|
+
end
|
49
|
+
|
50
|
+
def actions
|
51
|
+
%w(void settle credit)
|
52
|
+
end
|
53
|
+
|
54
|
+
def can_void?(_payment)
|
55
|
+
%w(authorized submitted_for_settlement).include? state
|
56
|
+
end
|
57
|
+
|
58
|
+
def can_settle?(_)
|
59
|
+
%w(authorized).include? state
|
60
|
+
end
|
61
|
+
|
62
|
+
def can_credit?(_payment)
|
63
|
+
%w(settled settling).include? state
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def update_payment_and_order
|
69
|
+
return unless (changes = previous_changes[:state])
|
70
|
+
return unless changes[0] != changes[1]
|
71
|
+
return unless payment
|
72
|
+
|
73
|
+
utils = Gateway::BraintreeVzeroBase::Utils.new(Gateway::BraintreeVzeroBase.first, order)
|
74
|
+
payment_state = utils.map_payment_status(state)
|
75
|
+
payment.send(payment_action(payment_state))
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.braintree_card_type_to_spree(type)
|
79
|
+
return '' unless type
|
80
|
+
case type
|
81
|
+
when 'AmericanExpress'
|
82
|
+
'american_express'
|
83
|
+
when 'Diners Club'
|
84
|
+
'diners_club'
|
85
|
+
when 'MasterCard'
|
86
|
+
'master'
|
87
|
+
else
|
88
|
+
type.downcase
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def payment_action(state)
|
93
|
+
case state
|
94
|
+
when 'pending'
|
95
|
+
'pend'
|
96
|
+
when 'void'
|
97
|
+
'void'
|
98
|
+
when 'completed'
|
99
|
+
'complete'
|
100
|
+
else
|
101
|
+
'failure'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|