diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index 5d4eeb4d1a..fe0ffb8301 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -30,12 +30,7 @@ class CheckoutController < ::BaseController helper 'spree/orders' - def edit - return handle_redirect_from_stripe if valid_payment_intent_provided? - rescue Spree::Core::GatewayError => e - gateway_error(e) - action_failed(e) - end + def edit; end def update params_adapter = Checkout::FormDataAdapter.new(permitted_params, @order, spree_current_user) @@ -63,14 +58,12 @@ class CheckoutController < ::BaseController return order_invalid! if order_invalid_for_checkout? return handle_invalid_stock unless valid_order_line_items? - return if valid_payment_intent_provided? before_address setup_for_current_state end def handle_invalid_stock - cancel_incomplete_payments if valid_payment_intent_provided? reset_order_to_cart respond_to do |format| @@ -84,16 +77,6 @@ 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.incomplete.each do |payment| - payment.void_transaction! - payment.adjustment&.update_columns(eligible: false, state: "finalized") - end - flash[:notice] = I18n.t("checkout.payment_cancelled_due_to_stock") - end - def setup_for_current_state method_name = :"before_#{@order.state}" __send__(method_name) if respond_to?(method_name, true) @@ -112,28 +95,6 @@ class CheckoutController < ::BaseController current_order.payments.destroy_all if request.put? end - def valid_payment_intent_provided? - @valid_payment_intent_provided ||= begin - return false unless params["payment_intent"]&.starts_with?("pi_") - - last_payment = OrderPaymentFinder.new(@order).last_payment - @order.state == "payment" && - last_payment&.state == "requires_authorization" && - last_payment&.response_code == params["payment_intent"] - end - end - - def handle_redirect_from_stripe - return processing_failed unless @order.process_payments! - - if OrderWorkflow.new(@order).next && order_complete? - processing_succeeded - redirect_to order_completion_route - else - processing_failed - end - end - def checkout_workflow(shipping_method_id) while @order.state != "complete" if @order.state == "payment" diff --git a/app/controllers/payment_gateways/stripe_controller.rb b/app/controllers/payment_gateways/stripe_controller.rb new file mode 100644 index 0000000000..686535dc80 --- /dev/null +++ b/app/controllers/payment_gateways/stripe_controller.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +class StripeController < BaseController + include OrderStockCheck + include OrderCompletion + + before_action :load_order, only: :confirm + + def confirm + return processing_failed unless valid_payment_intent? + + process_payment_completion + end + + private + + def load_order + @order = current_order + + return order_invalid! if order_invalid_for_checkout? + + (cancel_incomplete_payments && handle_insufficient_stock) unless sufficient_stock? + end + + def valid_payment_intent? + @valid_payment_intent ||= begin + return false unless params["payment_intent"]&.starts_with?("pi_") + + last_payment = OrderPaymentFinder.new(@order).last_payment + + @order.state == "payment" && + last_payment&.state == "requires_authorization" && + last_payment&.response_code == params["payment_intent"] + end + end + + def process_payment_completion + return processing_failed unless @order.process_payments! + + if OrderWorkflow.new(@order).next && @order.complete? + processing_succeeded + redirect_to order_completion_route + else + processing_failed + redirect_to order_failed_route + end + rescue Spree::Core::GatewayError => e + gateway_error(e) + processing_failed + 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.incomplete.each do |payment| + payment.void_transaction! + payment.adjustment&.update_columns(eligible: false, state: "finalized") + end + flash[:notice] = I18n.t("checkout.payment_cancelled_due_to_stock") + end +end diff --git a/app/services/checkout/stripe_redirect.rb b/app/services/checkout/stripe_redirect.rb index 760db74615..3188971de2 100644 --- a/app/services/checkout/stripe_redirect.rb +++ b/app/services/checkout/stripe_redirect.rb @@ -3,7 +3,7 @@ # Provides the redirect path if a redirect to the payment gateway is needed module Checkout class StripeRedirect - include FullUrlHelper + include Rails.application.routes.url_helpers def initialize(payment_method, order) @payment_method = payment_method @@ -34,7 +34,7 @@ module Checkout end def return_url - full_checkout_path + payment_gateways_confirm_stripe_url end # Stripe::AuthorizeResponsePatcher patches the Stripe authorization response diff --git a/config/routes.rb b/config/routes.rb index 5585813d25..6c637f306e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -73,6 +73,8 @@ Openfoodnetwork::Application.routes.draw do get "/paypal", to: "paypal#express", as: :paypal_express get "/paypal/confirm", to: "paypal#confirm", as: :confirm_paypal get "/paypal/cancel", to: "paypal#cancel", as: :cancel_paypal + + get "/stripe/confirm", to: "stripe#confirm", as: :confirm_stripe end constraints SplitCheckoutConstraint.new do