Files
openfoodnetwork/app/controllers/split_checkout_controller.rb
2021-09-01 15:04:33 +01:00

195 lines
5.1 KiB
Ruby

# frozen_string_literal: true
require 'open_food_network/address_finder'
class SplitCheckoutController < ::BaseController
layout 'darkswarm'
include OrderStockCheck
include Spree::BaseHelper
include CheckoutCallbacks
helper 'terms_and_conditions'
helper 'checkout'
helper 'spree/orders'
helper OrderHelper
def edit
return handle_redirect_from_stripe if valid_payment_intent_provided?
redirect_to_step unless checkout_step
OrderWorkflow.new(@order).next if @order.cart?
# 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
@order.errors.clear
@order.bill_address.errors.clear
@order.ship_address.errors.clear
rescue Spree::Core::GatewayError => e
rescue_from_spree_gateway_error(e)
end
def update
load_shipping_method
handle_shipping_method_selection
if confirm_order || update_order
clear_invalid_payments
redirect_to_step
else
if @shipping_method_id.blank?
@order.errors.add(:base, "no_shipping_method_selected")
end
flash.now[:error] = "#{I18n.t('split_checkout.errors.global')}"
render :edit
end
end
private
def handle_shipping_method_selection
return unless @shipping_method
populate_ship_address_params
end
def load_shipping_method
if params[:shipping_method_id]
@shipping_method = Spree::ShippingMethod.where(id: params[:shipping_method_id]).first
@shipping_method_id = params[:shipping_method_id]
else
@shipping_method = @order.shipping_method
@shipping_method_id = @shipping_method&.id
end
end
def populate_ship_address_params
return unless params.dig(:order, :ship_address_attributes).present? &&
params.dig(:order, :bill_address_attributes).present?
if params.dig(:order, "Checkout.ship_address_same_as_billing") == "1"
params[:order][:ship_address_attributes] = params[:order][:bill_address_attributes]
return
end
address_attrs = [
:firstname,
:lastname,
:phone,
:address1,
:address2,
:city,
:state_id,
:zipcode,
:country_id,
:id
]
address_attrs.each do |attr|
next if params[:order][:ship_address_attributes][attr].present?
params[:order][:ship_address_attributes][attr] = params[:order][:bill_address_attributes][attr]
end
end
def clear_invalid_payments
@order.payments.with_state(:invalid).delete_all
end
def confirm_order
return unless @order.confirmation? && params[:confirm_order]
return unless validate_terms_and_conditions!
@order.confirm!
end
def update_order
return unless params[:order]
return if @order.state == "address" && params[:shipping_method_id].blank?
@order.update(order_params) && advance_order_state
end
def advance_order_state
return true if @order.complete?
OrderWorkflow.new(@order).advance_checkout(raw_params.slice(:shipping_method_id))
end
def checkout_step
@checkout_step ||= params[:step]
end
def validate_terms_and_conditions!
return true if params[:accept_terms]
@order.errors.add(:terms_and_conditions, t("split_checkout.errors.terms_not_accepted"))
false
end
def order_params
return @order_params unless @order_params.nil?
@order_params = params.require(:order).permit(
:email, :shipping_method_id, :special_instructions,
bill_address_attributes: PermittedAttributes::Address.attributes,
ship_address_attributes: PermittedAttributes::Address.attributes,
payments_attributes: [:payment_method_id]
)
set_payment_amount
@order_params
end
def set_payment_amount
return unless @order_params[:payments_attributes]
@order_params[:payments_attributes].first[:amount] = @order.total
end
def redirect_to_step
case @order.state
when "cart", "address", "delivery"
redirect_to checkout_step_path(:details)
when "payment"
redirect_to checkout_step_path(:payment)
when "confirmation"
redirect_to checkout_step_path(:summary)
else
redirect_to order_path(@order)
end
end
def valid_payment_intent_provided?
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
def handle_redirect_from_stripe
return checkout_failed unless @order.process_payments!
if OrderWorkflow.new(@order).next && order_complete?
checkout_succeeded
redirect_to(order_path(@order)) && return
else
checkout_failed
end
end
def order_complete?
@order.state == "complete" || @order.completed?
end
def rescue_from_spree_gateway_error(error)
flash[:error] = t(:spree_gateway_error_flash_for_checkout, error: error.message)
action_failed(error)
end
end