From a82f7ced44108878ad587f5bae0206632f7b5c93 Mon Sep 17 00:00:00 2001 From: Szymon Iwacz <szymon@iwacz.pl> Date: Thu, 1 Oct 2020 16:21:50 +0200 Subject: [PATCH] Fix order outstanding balance when store credit is without auto capture (#10516) * Fix order outstanding_balance when store credit is without auto capture * rubocop fix * Do not use .map{ _1 } syntax --- core/app/models/spree/order/payments.rb | 10 +++- core/spec/models/spree/order/payment_spec.rb | 60 ++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/core/app/models/spree/order/payments.rb b/core/app/models/spree/order/payments.rb index ccabe5a94ef..2420af9bd10 100644 --- a/core/app/models/spree/order/payments.rb +++ b/core/app/models/spree/order/payments.rb @@ -52,7 +52,7 @@ def process_payments_with(method) payment.public_send(method) - if payment.completed? && payment_total != total + if payment.completed? && payment_total != total_without_pending_store_credits self.payment_total += payment.amount end end @@ -60,6 +60,14 @@ def process_payments_with(method) result = !!Spree::Config[:allow_checkout_on_gateway_error] errors.add(:base, e.message) && (return result) end + + # Pending store credits are not added to `self.payment_total`. + # It can cause a situation where the amount of the credit card payment reduced with store credits + # may be added twice to `self.payment_total` causing wrong `order.outstanding_balance` + # calculations and thus an incorrect payment state. + def total_without_pending_store_credits + total - payments.map { |p| p.amount if p.source.is_a?(Spree::StoreCredit) && p.pending? }.sum(&:to_f) + end end end end diff --git a/core/spec/models/spree/order/payment_spec.rb b/core/spec/models/spree/order/payment_spec.rb index d00c2f6c8b2..3915760938f 100644 --- a/core/spec/models/spree/order/payment_spec.rb +++ b/core/spec/models/spree/order/payment_spec.rb @@ -27,6 +27,66 @@ module Spree expect(payment_2).to be_completed end + context 'processes all checkout payments along with store credits' do + context 'with store credits payment method auto capture turned on' do + it 'order should be paid' do + store_credit = create(:store_credit_payment, amount: 50) + payment = create(:payment, amount: 50) + + expect(order).to receive(:unprocessed_payments).and_return([store_credit, payment]).at_least(:once) + + order.process_payments! + updater.update_payment_state + expect(order.payment_state).to eq('paid') + + expect(payment).to be_completed + expect(store_credit).to be_completed + end + end + + context 'with store credits payment method auto capture turned off' do + let!(:payment) { create(:payment, amount: payment_amount) } + let!(:store_credit_payment) do + create( + :store_credit_payment, + amount: store_credit_amount, + payment_method: create(:store_credit_payment_method, auto_capture: false) + ) + end + + before do + payments = [store_credit_payment, payment] + expect(order).to receive(:payments).and_return(payments).at_least(:once) + expect(order.payments).to receive(:valid).and_return(payments) + + order.process_payments! + updater.update_payment_state + expect(payment).to be_completed + expect(store_credit_payment).to be_pending + end + + context 'order payment state should be balance due' do + let!(:payment_amount) { 70.00 } + let!(:store_credit_amount) { 30.00 } + + it do + expect(order.payment_state).to eq('balance_due') + expect(order.outstanding_balance).to eq(30.00) + end + end + + context 'order payment state should be balance due' do + let!(:payment_amount) { 90.00 } + let!(:store_credit_amount) { 10.00 } + + it do + expect(order.payment_state).to eq('balance_due') + expect(order.outstanding_balance).to eq(10.00) + end + end + end + end + it 'does not go over total for order' do payment_1 = create(:payment, amount: 50) payment_2 = create(:payment, amount: 50)