# frozen_string_literal: true module PaymentGateways class StripeController < BaseController include OrderStockCheck include OrderCompletion before_action :load_checkout_order, only: :confirm before_action :validate_payment_intent, only: :confirm before_action -> { check_order_cycle_expiry(should_empty_order: false) }, only: :confirm def confirm validate_stock return redirect_to order_failed_route if @any_out_of_stock == true process_payment_completion! end def authorize load_order_for_authorization return unless params.key?("payment_intent") result = ProcessPaymentIntent.new(params["payment_intent"], @order).call! unless result.success? flash.now[:error] = "#{I18n.t('payment_could_not_process')}. #{result.error}" end redirect_to order_path(@order) end private def load_order_for_authorization require_order_authentication! session[:access_token] ||= params[:order_token] @order = Spree::Order.find_by(number: params[:order_number]) || current_order if @order authorize! :edit, @order, session[:access_token] else authorize! :create, Spree::Order end end def require_order_authentication! return if session[:access_token] || params[:order_token] || spree_current_user flash[:error] = I18n.t("spree.orders.edit.login_to_view_order") redirect_to root_path(anchor: "login", after_login: request.original_fullpath) end def validate_stock return if sufficient_stock? cancel_incomplete_payments handle_insufficient_stock end def validate_payment_intent return if valid_payment_intent? processing_failed redirect_to order_failed_route end def valid_payment_intent? @valid_payment_intent ||= params["payment_intent"]&.starts_with?("pi_") && order_and_payment_valid? end def order_and_payment_valid? @order.state.in?(["payment", "confirmation"]) && last_payment&.state == "requires_authorization" && last_payment&.response_code == params["payment_intent"] end def last_payment @last_payment ||= Orders::FindPaymentService.new(@order).last_payment 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 end