diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index 52c3ba9543..90bc4357d2 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -170,6 +170,7 @@ class CheckoutController < Spree::StoreController def redirect_to_payment_gateway redirect_path = Checkout::PaypalRedirect.new(params).path + redirect_path = Checkout::StripeRedirect.new(params, @order).path if redirect_path.blank? return if redirect_path.blank? render json: { path: redirect_path }, status: :ok diff --git a/app/services/checkout/stripe_redirect.rb b/app/services/checkout/stripe_redirect.rb new file mode 100644 index 0000000000..0fe6b90f09 --- /dev/null +++ b/app/services/checkout/stripe_redirect.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Provides the redirect path if a redirect to the payment gateway is needed +module Checkout + class StripeRedirect + def initialize(params, order) + @params = params + @order = order + end + + # Returns the path to the authentication form if a redirect is needed + def path + return unless stripe_payment_method? + + payment = @order.pending_payments.last + return unless payment&.checkout? + + payment.authorize! + raise unless payment.pending? + + payment.cvv_response_message if url?(payment.cvv_response_message) + end + + private + + def stripe_payment_method? + return unless @params[:order][:payments_attributes] + + payment_method_id = @params[:order][:payments_attributes].first[:payment_method_id] + payment_method = Spree::PaymentMethod.find(payment_method_id) + payment_method.is_a?(Spree::Gateway::StripeSCA) + end + + def url?(string) + return false if string.blank? + + string.starts_with?("http") + end + end +end diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index a2ac420a2e..8f9b429d2e 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -251,7 +251,7 @@ describe CheckoutController, type: :controller do end it "should check the payment method for Paypalness if we've selected one" do - expect(Spree::PaymentMethod).to receive(:find).with(payment_method.id.to_s) { payment_method } + expect(Spree::PaymentMethod).to receive(:find).twice.with(payment_method.id.to_s) { payment_method } allow(order).to receive(:update_attributes) { true } allow(order).to receive(:state) { "payment" } spree_post :update, order: { payments_attributes: [{ payment_method_id: payment_method.id }] } diff --git a/spec/services/checkout/paypal_redirect_spec.rb b/spec/services/checkout/paypal_redirect_spec.rb index 40545f2588..e028be4486 100644 --- a/spec/services/checkout/paypal_redirect_spec.rb +++ b/spec/services/checkout/paypal_redirect_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Checkout::PaypalRedirect do - describe '#order_params' do + describe '#path' do let(:params) { { order: { order_id: "123" } } } let(:redirect) { Checkout::PaypalRedirect.new(params) } diff --git a/spec/services/checkout/stripe_redirect_spec.rb b/spec/services/checkout/stripe_redirect_spec.rb new file mode 100644 index 0000000000..d85152ecbf --- /dev/null +++ b/spec/services/checkout/stripe_redirect_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Checkout::StripeRedirect do + describe '#path' do + let(:order) { create(:order) } + let(:params) { { order: { order_id: order.id } } } + + let(:redirect) { Checkout::StripeRedirect.new(params, order) } + + it "returns nil if payment_attributes are not provided" do + expect(redirect.path).to be nil + end + + describe "when payment_attributes are provided" do + it "raises an error if payment method does not exist" do + params[:order][:payments_attributes] = [{ payment_method_id: "123" }] + + expect { redirect.path }.to raise_error ActiveRecord::RecordNotFound + end + + describe "when payment method provided exists" do + before { params[:order][:payments_attributes] = [{ payment_method_id: payment_method.id }] } + + describe "and the payment method is not a stripe payment method" do + let(:payment_method) { create(:payment_method) } + + it "returns nil" do + expect(redirect.path).to be nil + end + end + + describe "and the payment method is a stripe method" do + let(:distributor) { create(:distributor_enterprise) } + let(:payment_method) { create(:stripe_sca_payment_method) } + + it "returns the redirect path" do + stripe_payment = create(:payment, payment_method_id: payment_method.id) + order.payments << stripe_payment + allow(stripe_payment).to receive(:authorize!) do + # Authorization moves the payment state from checkout/processing to pending + stripe_payment.state = 'pending' + true + end + test_redirect_url = "http://stripe_auth_url/" + allow(stripe_payment).to receive(:cvv_response_message).and_return(test_redirect_url) + + expect(redirect.path).to eq test_redirect_url + end + end + end + end + end +end