Merge pull request #13902 from mkllnk/refund-simple

Simplify refund logic
This commit is contained in:
Rachel Arnould
2026-02-19 11:06:00 +01:00
committed by GitHub
9 changed files with 39 additions and 124 deletions

View File

@@ -95,8 +95,7 @@ module Spree
private
def load_payment_source
if @payment.payment_method.is_a?(Spree::Gateway) &&
@payment.payment_method.payment_profiles_supported? &&
if @payment.payment_method.is_a?(Gateway::StripeSCA) &&
params[:card].present? &&
(params[:card] != 'new')
@payment.source = CreditCard.find_by(id: params[:card])

View File

@@ -5,7 +5,7 @@ module Spree
acts_as_taggable
include PaymentMethodDistributors
delegate :authorize, :purchase, :capture, :void, :credit, to: :provider
delegate :authorize, :purchase, :capture, :void, :credit, :refund, to: :provider
validates :name, :type, presence: true
@@ -35,6 +35,10 @@ module Spree
end
def method_missing(method, *)
message = "Deprecated delegation of Gateway##{method}"
Alert.raise(message)
raise message if Rails.env.local?
if @provider.nil? || !@provider.respond_to?(method)
super
else
@@ -42,10 +46,6 @@ module Spree
end
end
def payment_profiles_supported?
false
end
def method_type
'gateway'
end

View File

@@ -35,10 +35,6 @@ module Spree
ActiveMerchant::Billing::StripePaymentIntentsGateway
end
def payment_profiles_supported?
true
end
def stripe_account_id
StripeAccount.find_by(enterprise_id: preferred_enterprise_id)&.stripe_user_id
end
@@ -84,7 +80,7 @@ module Spree
end
# NOTE: this method is required by Spree::Payment::Processing
def void(payment_intent_id, _creditcard, gateway_options)
def void(payment_intent_id, gateway_options)
payment_intent_response = Stripe::PaymentIntent.retrieve(
payment_intent_id, stripe_account: stripe_account_id
)
@@ -101,7 +97,13 @@ module Spree
end
# NOTE: this method is required by Spree::Payment::Processing
def credit(money, _creditcard, payment_intent_id, gateway_options)
def credit(money, payment_intent_id, gateway_options)
gateway_options[:stripe_account] = stripe_account_id
provider.refund(money, payment_intent_id, gateway_options)
end
# NOTE: this method is required by Spree::Payment::Processing
def refund(money, payment_intent_id, gateway_options)
gateway_options[:stripe_account] = stripe_account_id
provider.refund(money, payment_intent_id, gateway_options)
end

View File

@@ -34,7 +34,7 @@ module Spree
# invalidate previously entered payments
after_create :invalidate_old_payments
after_save :create_payment_profile, if: :profiles_supported?
after_save :create_payment_profile
# update the order totals, etc.
after_save :ensure_correct_adjustment, :update_order
@@ -217,18 +217,13 @@ module Spree
errors.blank?
end
def profiles_supported?
payment_method.respond_to?(:payment_profiles_supported?) &&
payment_method.payment_profiles_supported?
end
def create_payment_profile
return unless source.is_a?(CreditCard)
return unless source.try(:save_requested_by_customer?)
return unless source.number || source.gateway_payment_profile_id
return unless source.gateway_customer_profile_id.nil?
payment_method.create_profile(self)
payment_method.try(:create_profile, self)
rescue ActiveMerchant::ConnectionError => e
gateway_error e
end

View File

@@ -58,16 +58,7 @@ module Spree
protect_from_connection_error do
check_environment
response = if payment_method.payment_profiles_supported?
# Gateways supporting payment profiles will need access to credit
# card object because this stores the payment profile information
# so supply the authorization itself as well as the credit card,
# rather than just the authorization code
payment_method.void(response_code, source, gateway_options)
else
# Standard ActiveMerchant void usage
payment_method.void(response_code, gateway_options)
end
response = payment_method.void(response_code, gateway_options)
record_response(response)
@@ -86,20 +77,11 @@ module Spree
credit_amount = calculate_refund_amount(credit_amount)
response = if payment_method.payment_profiles_supported?
payment_method.credit(
(credit_amount * 100).round,
source,
response_code,
gateway_options
)
else
payment_method.credit(
(credit_amount * 100).round,
response_code,
gateway_options
)
end
response = payment_method.credit(
(credit_amount * 100).round,
response_code,
gateway_options
)
record_response(response)
@@ -125,20 +107,11 @@ module Spree
refund_amount = calculate_refund_amount(refund_amount)
response = if payment_method.payment_profiles_supported?
payment_method.refund(
(refund_amount * 100).round,
source,
response_code,
gateway_options
)
else
payment_method.refund(
(refund_amount * 100).round,
response_code,
gateway_options
)
end
response = payment_method.refund(
(refund_amount * 100).round,
response_code,
gateway_options
)
record_response(response)

View File

@@ -93,10 +93,6 @@ module Spree
unscoped { find(*) }
end
def payment_profiles_supported?
false
end
def source_required?
true
end

View File

@@ -109,7 +109,7 @@ RSpec.describe Spree::Gateway::StripeSCA, :vcr, :stripe_version do
end
it "refunds the payment" do
response = subject.void(payment_intent.id, nil, {})
response = subject.void(payment_intent.id, {})
expect(response.success?).to eq true
end
@@ -131,7 +131,7 @@ RSpec.describe Spree::Gateway::StripeSCA, :vcr, :stripe_version do
end
it "void the payment" do
response = subject.void(payment_intent.id, nil, {})
response = subject.void(payment_intent.id, {})
expect(response.success?).to eq true
end
@@ -162,7 +162,7 @@ RSpec.describe Spree::Gateway::StripeSCA, :vcr, :stripe_version do
stripe_account: stripe_test_account
)
response = subject.credit(1000, nil, payment_intent.id, {})
response = subject.credit(1000, payment_intent.id, {})
expect(response.success?).to eq true
end

View File

@@ -14,8 +14,14 @@ RSpec.describe Spree::Gateway do
end
it "passes through all arguments on a method_missing call" do
expect(Rails.env).to receive(:local?).and_return(false)
gateway = test_gateway.new
expect(gateway.provider).to receive(:imaginary_method).with('foo')
gateway.imaginary_method('foo')
end
it "raises an error in test env" do
gateway = test_gateway.new
expect { gateway.imaginary_method('foo') }.to raise_error StandardError
end
end

View File

@@ -345,24 +345,6 @@ RSpec.describe Spree::Payment do
allow(payment_method).to receive(:void).and_return(success_response)
end
context "when profiles are supported" do
it "should call payment_enterprise.void with the payment's response_code" do
allow(payment_method).to receive(:payment_profiles_supported) { true }
expect(payment_method).to receive(:void).with('123', card,
anything).and_return(success_response)
payment.void_transaction!
end
end
context "when profiles are not supported" do
it "should call payment_gateway.void with the payment's response_code" do
allow(payment_method).to receive(:payment_profiles_supported) { false }
expect(payment_method).to receive(:void).with('123', card,
anything).and_return(success_response)
payment.void_transaction!
end
end
it "should log the response" do
payment.void_transaction!
expect(payment).to have_received(:record_response)
@@ -437,7 +419,7 @@ RSpec.describe Spree::Payment do
end
it "should call credit on the gateway with the credit amount and response_code" do
expect(payment_method).to receive(:credit).with(1000, card, '123',
expect(payment_method).to receive(:credit).with(1000, '123',
anything).and_return(success_response)
payment.credit!
end
@@ -463,7 +445,7 @@ RSpec.describe Spree::Payment do
it "should call credit on the gateway with the credit amount and response_code" do
expect(payment_method).to receive(:credit).with(
amount_in_cents, card, '123', anything
amount_in_cents, '123', anything
).and_return(success_response)
payment.credit!
end
@@ -476,7 +458,7 @@ RSpec.describe Spree::Payment do
it "should call credit on the gateway with original payment amount and response_code" do
expect(payment_method).to receive(:credit).with(
amount_in_cents.to_f, card, '123', anything
amount_in_cents.to_f, '123', anything
).and_return(success_response)
payment.credit!
end
@@ -658,7 +640,6 @@ RSpec.describe Spree::Payment do
context "when profiles are supported" do
before do
allow(payment_method).to receive(:payment_profiles_supported?) { true }
allow(payment.source).to receive(:has_payment_profile?) { false }
end
@@ -700,26 +681,6 @@ RSpec.describe Spree::Payment do
end
end
context "when profiles are not supported" do
before do
allow(payment_method).to receive(:payment_profiles_supported?) { false }
end
it "should not create a payment profile" do
payment_method.name = 'Gateway'
payment_method.distributors << create(:distributor_enterprise)
payment_method.save!
expect(payment_method).not_to receive :create_profile
payment = Spree::Payment.create(
amount: 100,
order: create(:order),
source: card,
payment_method:
)
end
end
context 'when the payment was completed but now void' do
let(:payment) { create(:payment, :completed, amount: 100, order:) }
@@ -877,23 +838,6 @@ RSpec.describe Spree::Payment do
end
end
describe "performing refunds" do
before do
allow(payment).to receive(:calculate_refund_amount) { 123 }
expect(payment.payment_method).to receive(:refund).and_return(success)
end
it "performs the refund without payment profiles" do
allow(payment.payment_method).to receive(:payment_profiles_supported?) { false }
payment.refund!
end
it "performs the refund with payment profiles" do
allow(payment.payment_method).to receive(:payment_profiles_supported?) { true }
payment.refund!
end
end
it "records the response" do
allow(payment).to receive(:calculate_refund_amount) { 123 }
allow(payment.payment_method).to receive(:refund).and_return(success)