From 9928a9e8a21e10385c45ec67f3d0967ec985cae7 Mon Sep 17 00:00:00 2001 From: Kevin Attfield Date: Mon, 25 Jul 2016 15:49:04 -0700 Subject: [PATCH] Do not attempt to cancel fully refunded payments Cancelling a payment can result in a refund, which will fail if the payment has already been fully refunded. --- core/app/models/spree/order.rb | 2 +- core/app/models/spree/payment.rb | 5 +++++ core/spec/models/spree/order_spec.rb | 17 ++++++++++++++++- core/spec/models/spree/payment_spec.rb | 19 +++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/core/app/models/spree/order.rb b/core/app/models/spree/order.rb index 11c7b3e8d2f..73293511733 100644 --- a/core/app/models/spree/order.rb +++ b/core/app/models/spree/order.rb @@ -852,7 +852,7 @@ def ensure_available_shipping_rates def after_cancel shipments.each(&:cancel!) - payments.completed.each(&:cancel!) + payments.completed.each { |payment| payment.cancel! unless payment.fully_refunded? } payments.store_credits.pending.each(&:void_transaction!) send_cancel_email diff --git a/core/app/models/spree/payment.rb b/core/app/models/spree/payment.rb index 2b8e71d052f..5ce5ce340b4 100644 --- a/core/app/models/spree/payment.rb +++ b/core/app/models/spree/payment.rb @@ -146,6 +146,11 @@ def can_credit? credit_allowed > 0 end + # @return [Boolean] true when this payment has been fully refunded + def fully_refunded? + refunds.map(&:amount).sum == amount + end + # @return [Array] the actions available on this payment def actions sa = source_actions diff --git a/core/spec/models/spree/order_spec.rb b/core/spec/models/spree/order_spec.rb index 5796b20206a..4cd55973d8a 100644 --- a/core/spec/models/spree/order_spec.rb +++ b/core/spec/models/spree/order_spec.rb @@ -43,6 +43,8 @@ end describe "#cancel!" do + subject { order.cancel! } + context "with captured store credit" do let!(:store_credit_payment_method) { create(:store_credit_payment_method) } let(:order_total) { 500.00 } @@ -55,7 +57,20 @@ order.capture_payments! end - subject { order.cancel! } + it "cancels the order" do + expect{ subject }.to change{ order.can_cancel? }.from(true).to(false) + expect(order).to be_canceled + end + end + + context "with fully refunded payment" do + let(:order) { create(:completed_order_with_totals) } + let(:payment_amount) { 50 } + let(:payment) { create(:payment, order: order, amount: payment_amount, state: 'completed') } + + before do + create(:refund, payment: payment, amount: payment_amount) + end it "cancels the order" do expect{ subject }.to change{ order.can_cancel? }.from(true).to(false) diff --git a/core/spec/models/spree/payment_spec.rb b/core/spec/models/spree/payment_spec.rb index ea5faf0537b..89f86c8a1b5 100644 --- a/core/spec/models/spree/payment_spec.rb +++ b/core/spec/models/spree/payment_spec.rb @@ -630,6 +630,25 @@ end end + describe "#fully_refunded?" do + subject { payment.fully_refunded? } + + before { payment.amount = 100 } + + context 'before refund' do + it { is_expected.to be false } + end + + context 'when refund total equals payment amount' do + before do + create(:refund, payment: payment, amount: 50) + create(:refund, payment: payment, amount: 50) + end + + it { is_expected.to be true } + end + end + describe "#save" do context "captured payments" do it "update order payment total" do