From 9bcf0d5b38cade71e772167303e65bbdfc40d4b0 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 11 Jun 2021 15:08:11 +0100 Subject: [PATCH] Handle Stripe payments when checkout fails due to stock issues This can occur when stock is reduced after the user is redirected to Stripe and before they are redirected back. The stock is insufficient, the order is not complete, the user is bounced back to the cart, but a *pending* Stripe payment is left on the order. --- app/controllers/checkout_controller.rb | 20 +++++++++++++++++--- config/locales/en.yml | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index 13b6654782..37bdff3954 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -37,7 +37,7 @@ class CheckoutController < ::BaseController # This is only required because of spree_paypal_express. If we implement # a version of paypal that uses this controller, and more specifically # the #action_failed method, then we can remove this call - OrderCheckoutRestart.new(@order).call + reset_order_to_cart rescue Spree::Core::GatewayError => e rescue_from_spree_gateway_error(e) end @@ -82,7 +82,7 @@ class CheckoutController < ::BaseController @order = current_order redirect_to(main_app.shop_path) && return if redirect_to_shop? - redirect_to_cart_path && return unless valid_order_line_items? + handle_invalid_stock && return unless valid_order_line_items? before_address setup_for_current_state @@ -100,7 +100,10 @@ class CheckoutController < ::BaseController distributes_order_variants?(@order) end - def redirect_to_cart_path + def handle_invalid_stock + cancel_incomplete_payments if valid_payment_intent_provided? + reset_order_to_cart + respond_to do |format| format.html do redirect_to main_app.cart_path @@ -112,6 +115,17 @@ class CheckoutController < ::BaseController end end + def cancel_incomplete_payments + # The checkout could not complete due to stock running out. We void any pending (incomplete) + # Stripe payments here as the order will need to be changed and resubmitted (or abandoned). + @order.payments.pending.each(&:void!) + flash[:notice] = I18n.t("checkout.payment_cancelled_due_to_stock") + end + + def reset_order_to_cart + OrderCheckoutRestart.new(@order).call + end + def setup_for_current_state method_name = :"before_#{@order.state}" __send__(method_name) if respond_to?(method_name, true) diff --git a/config/locales/en.yml b/config/locales/en.yml index 84140e72bc..76943a0815 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1315,6 +1315,7 @@ en: message_html: "I agree to the seller's %{terms_and_conditions_link} and the platform %{tos_link}." terms_and_conditions: "Terms and Conditions" failed: "The checkout failed. Please let us know so that we can process your order." + payment_cancelled_due_to_stock: "Payment cancelled: the checkout could not be completed due to stock issues." shops: hubs: show_closed_shops: "Show closed shops"