Files
openfoodnetwork/app/controllers/spree/orders_controller.rb
Matt-Yorkley 9f49a84e7f Clarify use of access tokens used for viewing order details as a guest user
There are 4 or 5 different places in the app where we reference a :token and params[:token] for completely different purposes (they're not even vaguely the *same* token).

This is an attempt to clarify the places in the app where we use params[:token] in relation to *orders*, for allowing guest users (who are not logged in) to view details of an order they have placed (like after checkout completion), and differentiate it from the various other places where params[:token] can actually be used for something entirely different!
2021-12-16 13:35:55 +00:00

199 lines
6.0 KiB
Ruby

# frozen_string_literal: true
module Spree
class OrdersController < ::BaseController
include OrderCyclesHelper
include Rails.application.routes.url_helpers
layout 'darkswarm'
before_action :check_authorization
rescue_from ActiveRecord::RecordNotFound, with: :render_404
helper 'spree/products', 'spree/orders'
respond_to :html
respond_to :json
before_action :set_current_order, only: :update
before_action :filter_order_params, only: :update
before_action :enable_embedded_shopfront
prepend_before_action :require_order_authentication, only: :show
prepend_before_action :require_order_cycle, only: :edit
prepend_before_action :require_distributor_chosen, only: :edit
before_action :check_hub_ready_for_checkout, only: :edit
before_action :check_at_least_one_line_item, only: :update
def show
@order = Spree::Order.find_by!(number: params[:id])
handle_stripe_response
end
def empty
if @order = current_order
@order.empty!
end
redirect_to main_app.cart_path
end
# Patching to redirect to shop if order is empty
def edit
@order = current_order(true)
@insufficient_stock_lines = @order.insufficient_stock_lines
@unavailable_order_variants = OrderCycleDistributedVariants.
new(current_order_cycle, current_distributor).unavailable_order_variants(@order)
if @order.line_items.empty?
redirect_to main_app.shop_path
else
associate_user
if @order.insufficient_stock_lines.present? || @unavailable_order_variants.present?
flash.now[:error] = t("spree.orders.error_flash_for_unavailable_items")
end
end
end
def update
@insufficient_stock_lines = []
@order = order_to_update
unless @order
flash[:error] = t(:order_not_found)
redirect_to(main_app.root_path) && return
end
# This action is called either from the cart page when the order is not yet complete, or from
# the edit order page (frontoffice) if the hub allows users to update completed orders.
if @order.contents.update_cart(order_params)
@order.recreate_all_fees! # Enterprise fees on line items and on the order itself
if @order.complete?
@order.update_payment_fees!
@order.create_tax_charge!
end
respond_with(@order) do |format|
format.html do
if params.key?(:checkout)
@order.next_transition.run_callbacks if @order.cart?
redirect_to main_app.checkout_state_path(@order.checkout_steps.first)
elsif @order.complete?
redirect_to main_app.order_path(@order)
else
redirect_to main_app.cart_path
end
end
end
else
# Show order with original values, not newly entered ones
@insufficient_stock_lines = @order.insufficient_stock_lines
@order.line_items.reload
respond_with(@order)
end
end
def cancel
@order = Spree::Order.find_by!(number: params[:id])
authorize! :cancel, @order
if CustomerOrderCancellation.new(@order).call
flash[:success] = I18n.t(:orders_your_order_has_been_cancelled)
else
flash[:error] = I18n.t(:orders_could_not_cancel)
end
redirect_to request.referer || main_app.order_path(@order)
end
private
def set_current_order
@order = current_order(true)
end
def check_authorization
session[:access_token] ||= params[:order_token]
order = Spree::Order.find_by(number: params[:id]) || current_order
if order
authorize! :edit, order, session[:access_token]
else
authorize! :create, Spree::Order
end
end
# Stripe can redirect here after a payment is processed in the backoffice.
# We verify if it was successful here and persist the changes.
def handle_stripe_response
return unless params.key?("payment_intent")
result = ProcessPaymentIntent.new(params["payment_intent"], @order).call!
unless result.ok?
flash.now[:error] = "#{I18n.t('payment_could_not_process')}. #{result.error}"
end
@order.reload
end
def filter_order_params
if params[:order] && params[:order][:line_items_attributes]
params[:order][:line_items_attributes] =
remove_missing_line_items(params[:order][:line_items_attributes])
end
end
def remove_missing_line_items(attrs)
attrs.select do |_i, line_item|
Spree::LineItem.find_by(id: line_item[:id])
end
end
def discard_empty_line_items
@order.line_items = @order.line_items.select { |li| li.quantity > 0 }
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 main_app.root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}")
end
def order_to_update
return @order_to_update if defined? @order_to_update
return @order_to_update = current_order unless params[:id]
@order_to_update = changeable_order_from_number
end
# If a specific order is requested, return it if it is COMPLETE and
# changes are allowed and the user has access. Return nil if not.
def changeable_order_from_number
order = Spree::Order.complete.find_by(number: params[:id])
return nil unless order&.changes_allowed? && can?(:update, order)
order
end
def check_at_least_one_line_item
return unless order_to_update&.complete?
items = params[:order][:line_items_attributes]
&.select{ |_k, attrs| attrs["quantity"].to_i > 0 }
if items.empty?
flash[:error] = I18n.t(:orders_cannot_remove_the_final_item)
redirect_to main_app.order_path(order_to_update)
end
end
def order_params
params.require(:order).permit(
:distributor_id, :order_cycle_id,
line_items_attributes: [:id, :quantity]
)
end
end
end