Skip to content

Commit

Permalink
Fix order outstanding balance when store credit is without auto captu…
Browse files Browse the repository at this point in the history
…re (spree#10516)

* Fix order outstanding_balance when store credit is without auto capture

* rubocop fix

* Do not use .map{ _1 } syntax
  • Loading branch information
szymoniwacz authored Oct 1, 2020
1 parent 4a0c4f4 commit a82f7ce
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
10 changes: 9 additions & 1 deletion core/app/models/spree/order/payments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,22 @@ 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
rescue Core::GatewayError => e
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
Expand Down
60 changes: 60 additions & 0 deletions core/spec/models/spree/order/payment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit a82f7ce

Please sign in to comment.