From 9f6c14973589a83766478336d90fe3c0977172d9 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 17 Oct 2025 05:25:45 +0500 Subject: [PATCH] Add check for payment authorization state in StripeScaPaymentAuthorize and corresponding spec --- .../order/stripe_sca_payment_authorize.rb | 2 + .../stripe_sca_payment_authorize_spec.rb | 9 ++++ .../services/checkout/stripe_redirect_spec.rb | 46 ++++++++++++++----- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb b/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb index 0763a32b1a..37cc00fa55 100644 --- a/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb +++ b/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb @@ -18,6 +18,8 @@ module OrderManagement end def call!(return_url = off_session_return_url) + # if the payment requires_authorization (3D Secure), can't be authorized again + return payment if payment&.requires_authorization? return unless payment&.checkout? payment.authorize!(return_url) diff --git a/engines/order_management/spec/services/order_management/order/stripe_sca_payment_authorize_spec.rb b/engines/order_management/spec/services/order_management/order/stripe_sca_payment_authorize_spec.rb index 81876ad376..ab1a17293f 100644 --- a/engines/order_management/spec/services/order_management/order/stripe_sca_payment_authorize_spec.rb +++ b/engines/order_management/spec/services/order_management/order/stripe_sca_payment_authorize_spec.rb @@ -19,6 +19,15 @@ module OrderManagement end end + context "when the payment already requires 3D Secure authorization" do + let(:payment) { create(:payment, amount: 10, state: 'requires_authorization') } + before { allow(order).to receive(:pending_payments).once { [payment] } } + + it "returns the payment without authorizing because it has already been authorized" do + expect(payment_authorize.call!).to eq payment + end + end + context "when a payment is present" do let(:payment) { create(:payment, amount: 10) } diff --git a/spec/services/checkout/stripe_redirect_spec.rb b/spec/services/checkout/stripe_redirect_spec.rb index 49b68149ea..6c3635cde2 100644 --- a/spec/services/checkout/stripe_redirect_spec.rb +++ b/spec/services/checkout/stripe_redirect_spec.rb @@ -17,28 +17,52 @@ RSpec.describe Checkout::StripeRedirect do context "when the payment method is a Stripe method" do let(:payment_method) { create(:stripe_sca_payment_method) } - let(:stripe_payment) { create(:payment, payment_method_id: payment_method.id) } let(:test_redirect_url) { "http://stripe_auth_url/" } before do order.payments << stripe_payment end - it "authorizes the payment and returns the redirect path" do - expect(Orders::FindPaymentService).to receive_message_chain(:new, :last_pending_payment). - and_return(stripe_payment) + context "when payment is in checkout state" do + let(:stripe_payment) { create(:payment, payment_method_id: payment_method.id) } - expect(OrderManagement::Order::StripeScaPaymentAuthorize).to receive(:new).and_call_original + it "authorizes the payment and returns the redirect path" do + expect(Orders::FindPaymentService).to receive_message_chain(:new, :last_pending_payment). + and_return(stripe_payment) - expect(stripe_payment).to receive(:authorize!) do - # Authorization moves the payment state from checkout/processing to pending - stripe_payment.state = 'pending' - true + expect( + OrderManagement::Order::StripeScaPaymentAuthorize + ).to receive(:new).and_call_original + expect(stripe_payment).to receive(:authorize!) do + # Authorization moves the payment state from checkout/processing to pending + stripe_payment.state = 'pending' + true + end + expect(stripe_payment).to receive(:redirect_auth_url).and_return(test_redirect_url) + expect(service.path).to eq test_redirect_url end + end - expect(stripe_payment).to receive(:redirect_auth_url).and_return(test_redirect_url) + context "when payment is in requires_authorization state" do + let(:stripe_payment) { + create( + :payment, + payment_method_id: payment_method.id, + state: 'requires_authorization', + redirect_auth_url: test_redirect_url + ) + } - expect(service.path).to eq test_redirect_url + it "returns the redirect path without authorizing the payment again" do + expect(Orders::FindPaymentService).to receive_message_chain(:new, :last_pending_payment). + and_return(stripe_payment) + + expect( + OrderManagement::Order::StripeScaPaymentAuthorize + ).to receive(:new).and_call_original + expect(stripe_payment).not_to receive(:authorize!) + expect(service.path).to eq test_redirect_url + end end end end