Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cancel authorized (pending) payments when cancelling an order (cont.) #3662

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions core/app/models/spree/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -914,9 +914,8 @@ def ensure_available_shipping_rates
end

def after_cancel
shipments.each(&:cancel!)
payments.completed.each { |payment| payment.cancel! unless payment.fully_refunded? }
payments.store_credits.pending.each(&:void_transaction!)
cancel_shipments!
cancel_payments!

send_cancel_email
# rubocop:disable Rails/SkipsModelValidations
Expand All @@ -925,6 +924,19 @@ def after_cancel
recalculate
end

def cancel_shipments!
shipments.each(&:cancel!)
end

def cancel_payments!
payments.each do |payment|
next if payment.fully_refunded?
next unless payment.pending? || payment.completed?

payment.cancel!
end
end

def send_cancel_email
Spree::Config.order_mailer_class.cancel_email(self).deliver_later
end
Expand Down
105 changes: 49 additions & 56 deletions core/spec/models/spree/order_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,20 @@
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 }
let(:store_credit) { create(:store_credit, amount: order_total) }
let(:order) { create(:order_with_line_items, user: store_credit.user, line_items_price: order_total) }
context 'when the payment is completed' do
let(:order) { create(:order_ready_to_ship) }
let(:payment) { order.payments.first }

before do
order.add_store_credit_payments
order.finalize!
order.capture_payments!
it 'voids the payment' do
expect { subject }.to change { payment.reload.state }.from('completed').to('void')
end

it "cancels the order" do
expect{ subject }.to change{ order.can_cancel? }.from(true).to(false)
expect(order).to be_canceled
end

it 'should save canceled_at' do
it 'saves canceled_at' do
subject
expect(order.reload.canceled_at).to_not be_nil
end
Expand All @@ -121,20 +117,58 @@
end
end

context "with fully refunded payment" do
context "when the payment is fully refunded" 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).perform!
end

it "cancels the order" do
create(:refund, payment: payment, amount: payment_amount)

expect{ subject }.to change{ order.can_cancel? }.from(true).to(false)
expect(order).to be_canceled
end
end

context 'when the payment is pending' do
let(:order) { create(:completed_order_with_pending_payment) }
let(:payment) { order.payments.first }

it 'voids the pending payment' do
expect { subject }.to change { payment.reload.state }.from('pending').to('void')
end
end

context 'with a store credit payment' do
let(:order) { create(:completed_order_with_totals) }
let(:payment) { create(:store_credit_payment, amount: order.total, order: order) }

context 'when the payment is pending' do
let(:store_credit) { payment.source }

before do
payment.authorize!
end

it 'voids the payment' do
expect { subject }.to change { payment.reload.state }.from('pending').to('void')
end

it 'releases the pending store credit authorization' do
expect { subject }.to change { store_credit.reload.amount_authorized }.from(110).to(0)
end
end

context 'when the payment is completed' do
before do
payment.purchase!
end

it 'refunds the payment' do
expect { subject }.to change { Spree::Refund.count }.by(1)
end
end
end
end

context "#canceled_by" do
Expand Down Expand Up @@ -1604,47 +1638,6 @@ def generate
expect(subject.display_store_credit_remaining_after_capture.money.cents).to eq(amount_remaining * 100.0)
end
end

context 'when not capturing at order completion' do
let!(:store_credit_payment_method) do
create(
:store_credit_payment_method,
auto_capture: false, # not capturing at completion time
)
end

describe '#after_cancel' do
let(:user) { create(:user) }
let!(:store_credit) do
create(:store_credit, amount: 100, user: user)
end
let(:order) do
create(
:order_with_line_items,
user: user,
line_items_count: 1,
# order will be $20 total:
line_items_price: 10,
shipment_cost: 10
)
end

before do
order.contents.advance
order.complete!
end

it 'releases the pending store credit authorization' do
expect {
order.cancel!
}.to change {
store_credit.reload.amount_authorized
}.from(20).to(0)

expect(store_credit.amount_remaining).to eq 100
end
end
end
end

context 'update_params_payment_source' do
Expand Down