From 96462325d2158a6e5caadcba6a4d2a9402a7d692 Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Thu, 3 Dec 2020 15:07:58 -0800 Subject: [PATCH 1/2] fix #5829 --- app/models/spree/gateway/stripe_sca.rb | 7 ++++++- spec/support/request/stripe_stubs.rb | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/models/spree/gateway/stripe_sca.rb b/app/models/spree/gateway/stripe_sca.rb index 02681ae210..200dbd4a0e 100644 --- a/app/models/spree/gateway/stripe_sca.rb +++ b/app/models/spree/gateway/stripe_sca.rb @@ -61,7 +61,7 @@ module Spree payment_intent_response = Stripe::PaymentIntent.retrieve(payment_intent_id, stripe_account: stripe_account_id) gateway_options[:stripe_account] = stripe_account_id - provider.refund(payment_intent_response.amount_received, response_code, gateway_options) + provider.refund(refundable_amount(payment_intent_response), response_code, gateway_options) end # NOTE: the name of this method is determined by Spree::Payment::Processing @@ -79,6 +79,11 @@ module Spree private + def refundable_amount(payment_intent_response) + payment_intent_response.amount_received - + payment_intent_response.charges.data.map(&:amount_refunded).sum + end + # In this gateway, what we call 'secret_key' is the 'login' def options options = super diff --git a/spec/support/request/stripe_stubs.rb b/spec/support/request/stripe_stubs.rb index 909604b9ae..ba9f877e59 100644 --- a/spec/support/request/stripe_stubs.rb +++ b/spec/support/request/stripe_stubs.rb @@ -75,7 +75,9 @@ module StripeStubs amount_received: 2000, status: options[:intent_status] || "requires_capture", last_payment_error: nil, - charges: { data: [{ id: "ch_1234", amount: 2000 }] }) } + charges: { + data: [{ id: "ch_1234", amount: 2000, amount_refunded: 0 }] }) + } end def payment_intent_redirect_response_mock(redirect_url) From e866e983f60c0a9b23259802c82263d27f4e66d8 Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Mon, 7 Dec 2020 14:51:47 -0800 Subject: [PATCH 2/2] add spec for partially refunded SCA orders --- .../payments_controller_refunds_spec.rb | 25 +++++++++++++++++-- spec/support/request/stripe_stubs.rb | 5 ++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb index f6fc3fa225..d7b67a7988 100644 --- a/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb +++ b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb @@ -154,12 +154,11 @@ describe Spree::Admin::PaymentsController, type: :controller do before do allow(Stripe).to receive(:api_key) { "sk_test_12345" } allow(StripeAccount).to receive(:find_by) { stripe_account } - - stub_payment_intent_get_request end context "where the request succeeds" do before do + stub_payment_intent_get_request # Issues the refund stub_request(:post, "https://api.stripe.com/v1/charges/ch_1234/refunds"). with(basic_auth: ["sk_test_12345", ""]). @@ -181,6 +180,7 @@ describe Spree::Admin::PaymentsController, type: :controller do context "where the request fails" do before do + stub_payment_intent_get_request stub_request(:post, "https://api.stripe.com/v1/charges/ch_1234/refunds"). with(basic_auth: ["sk_test_12345", ""]). to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) @@ -198,6 +198,27 @@ describe Spree::Admin::PaymentsController, type: :controller do expect(flash[:error]).to eq "Bup-bow!" end end + + context "when a partial refund has already been issued" do + before do + stub_payment_intent_get_request(response: { amount_refunded: 200 }) + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1234/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, + body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) + end + + it "can still void the payment" do + order.reload + expect(order.payment_total).to_not eq 0 + expect(order.outstanding_balance).to eq 0 + spree_put :fire, params + expect(payment.reload.state).to eq 'void' + order.reload + expect(order.payment_total).to eq 0 + expect(order.outstanding_balance).to_not eq 0 + end + end end end diff --git a/spec/support/request/stripe_stubs.rb b/spec/support/request/stripe_stubs.rb index ba9f877e59..d4c678415c 100644 --- a/spec/support/request/stripe_stubs.rb +++ b/spec/support/request/stripe_stubs.rb @@ -68,6 +68,7 @@ module StripeStubs private def payment_intent_authorize_response_mock(options) + chargedata = [{ id: "ch_1234", amount: 2000, amount_refunded: options[:amount_refunded] || 0 }] { status: options[:code] || 200, body: JSON.generate(id: "pi_123", object: "payment_intent", @@ -75,9 +76,7 @@ module StripeStubs amount_received: 2000, status: options[:intent_status] || "requires_capture", last_payment_error: nil, - charges: { - data: [{ id: "ch_1234", amount: 2000, amount_refunded: 0 }] }) - } + charges: { data: chargedata }) } end def payment_intent_redirect_response_mock(redirect_url)