diff --git a/app/services/orders/workflow_service.rb b/app/services/orders/workflow_service.rb index 99eec1bd17..f0e84fbe18 100644 --- a/app/services/orders/workflow_service.rb +++ b/app/services/orders/workflow_service.rb @@ -92,7 +92,10 @@ module Orders # Verifies if the in-memory payment state is different from the one stored in the database # This is be done without reloading the payment so that in-memory data is not changed def different_from_db_payment_state?(in_memory_payment_state, payment_id) - in_memory_payment_state != Spree::Payment.find(payment_id).state + # Re-load payment from the DB (unless it was cleared by clear_invalid_payments) + db_payment = Spree::Payment.find_by(id: payment_id) + + db_payment.present? && in_memory_payment_state != db_payment.state end end end diff --git a/app/views/checkout/_tabs.html.haml b/app/views/checkout/_tabs.html.haml index e4c027c895..8ec938cc9d 100644 --- a/app/views/checkout/_tabs.html.haml +++ b/app/views/checkout/_tabs.html.haml @@ -1,4 +1,5 @@ -.flex +-# Prevent Turbo pre-fetch which changes cart state +.flex{'data-turbo-prefetch': "false"} .columns.three.text-center.checkout-tab{"class": [("selected" if checkout_step?(:details)), ("success" unless checkout_step?(:details))]} %div %span.checkout-tab-number diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index acef705a0c..4adbffa9df 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -328,6 +328,52 @@ RSpec.describe CheckoutController, type: :controller do expect_cable_ready_redirect(response) end end + + context "with existing invalid payments" do + let(:invalid_payments) { + [ + create(:payment, state: :failed), + create(:payment, state: :void), + ] + } + + before do + order.payments = invalid_payments + end + + it "deletes invalid payments" do + expect{ + put(:update, params:) + }.to change { order.payments.to_a }.from(invalid_payments) + end + end + + context "with different payment method previously chosen" do + let(:other_payment_method) { build(:payment_method, distributors: [distributor]) } + let(:other_payment) { + build(:payment, amount: order.total, payment_method: other_payment_method) + } + + before do + order.payments = [other_payment] + end + + context "and order is in an earlier state" do + # This revealed obscure bug #12693. If you progress to order summary, go back to payment + # method, then open delivery details in a new tab (or hover over the link with Turbo + # enabled), then submit new payment details, this happens. + + before do + order.back_to_address + end + + it "deletes invalid (old) payments" do + put(:update, params:) + order.payments.reload + expect(order.payments).not_to include other_payment + end + end + end end context "with no payment source" do