diff --git a/Gemfile b/Gemfile index dbe522fb71..871a08794c 100644 --- a/Gemfile +++ b/Gemfile @@ -20,9 +20,9 @@ gem 'pg' # OFN-maintained and patched version of Spree v2.0.4. See # https://github.com/openfoodfoundation/openfoodnetwork/wiki/Spree-2.0-upgrade # for details. -gem 'spree_core', github: 'openfoodfoundation/spree', branch: '2-0-4-stable' gem 'spree_api', github: 'openfoodfoundation/spree', branch: '2-0-4-stable' gem 'spree_backend', github: 'openfoodfoundation/spree', branch: '2-0-4-stable' +gem 'spree_core', github: 'openfoodfoundation/spree', branch: '2-0-4-stable' gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '2-0-stable' gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable' diff --git a/app/controllers/spree/checkout_controller.rb b/app/controllers/spree/checkout_controller.rb index 1d7e11c587..a01750072f 100644 --- a/app/controllers/spree/checkout_controller.rb +++ b/app/controllers/spree/checkout_controller.rb @@ -1,93 +1,93 @@ require 'open_food_network/address_finder' -class Spree::CheckoutController < Spree::StoreController - include CheckoutHelper +module Spree + class CheckoutController < Spree::StoreController + include CheckoutHelper - ssl_required + ssl_required - before_filter :load_order + before_filter :load_order - before_filter :ensure_order_not_completed - before_filter :ensure_checkout_allowed - before_filter :ensure_sufficient_stock_lines + before_filter :ensure_order_not_completed + before_filter :ensure_checkout_allowed + before_filter :ensure_sufficient_stock_lines - before_filter :associate_user - before_filter :check_authorization - before_filter :enable_embedded_shopfront + before_filter :associate_user + before_filter :check_authorization + before_filter :enable_embedded_shopfront - helper 'spree/orders' + helper 'spree/orders' - rescue_from Spree::Core::GatewayError, :with => :rescue_from_spree_gateway_error + rescue_from Spree::Core::GatewayError, :with => :rescue_from_spree_gateway_error - def edit - flash.keep - redirect_to main_app.checkout_path - end - - private - - def load_order - @order = current_order - redirect_to main_app.cart_path and return unless @order - - if params[:state] - redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state]) - @order.state = params[:state] + def edit + flash.keep + redirect_to main_app.checkout_path end - setup_for_current_state - end - def ensure_checkout_allowed - unless @order.checkout_allowed? - redirect_to main_app.cart_path + private + + def load_order + @order = current_order + redirect_to main_app.cart_path && return unless @order + + if params[:state] + redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state]) + @order.state = params[:state] + end + setup_for_current_state end - end - def ensure_order_not_completed - redirect_to main_app.cart_path if @order.completed? - end - - def ensure_sufficient_stock_lines - if @order.insufficient_stock_lines.present? - flash[:error] = Spree.t(:inventory_error_flash_for_insufficient_quantity) - redirect_to main_app.cart_path + def ensure_checkout_allowed + redirect_to main_app.cart_path unless @order.checkout_allowed? end - end - def setup_for_current_state - method_name = :"before_#{@order.state}" - send(method_name) if respond_to?(method_name, true) - end + def ensure_order_not_completed + redirect_to main_app.cart_path if @order.completed? + end - # Adapted from spree_last_address gem: https://github.com/TylerRick/spree_last_address - # Originally, we used a forked version of this gem, but encountered strange errors where - # it worked in dev but only intermittently in staging/prod. - def before_address - associate_user + def ensure_sufficient_stock_lines + if @order.insufficient_stock_lines.present? + flash[:error] = Spree.t(:inventory_error_flash_for_insufficient_quantity) + redirect_to main_app.cart_path + end + end - finder = OpenFoodNetwork::AddressFinder.new(@order.email) + def setup_for_current_state + method_name = :"before_#{@order.state}" + send(method_name) if respond_to?(method_name, true) + end - @order.bill_address = finder.bill_address - @order.ship_address = finder.ship_address - end + # Adapted from spree_last_address gem: https://github.com/TylerRick/spree_last_address + # Originally, we used a forked version of this gem, but encountered strange errors where + # it worked in dev but only intermittently in staging/prod. + def before_address + associate_user - def before_delivery - return if params[:order].present? + finder = OpenFoodNetwork::AddressFinder.new(@order.email) - packages = @order.shipments.map { |s| s.to_package } - @differentiator = Spree::Stock::Differentiator.new(@order, packages) - end + @order.bill_address = finder.bill_address + @order.ship_address = finder.ship_address + end - def before_payment - current_order.payments.destroy_all if request.put? - end + def before_delivery + return if params[:order].present? - def rescue_from_spree_gateway_error - flash[:error] = Spree.t(:spree_gateway_error_flash_for_checkout) - render :edit - end + packages = @order.shipments.map(&:to_package) + @differentiator = Spree::Stock::Differentiator.new(@order, packages) + end - def check_authorization - authorize!(:edit, current_order, session[:access_token]) + def before_payment + current_order.payments.destroy_all if request.put? + end + + def rescue_from_spree_gateway_error + flash[:error] = Spree.t(:spree_gateway_error_flash_for_checkout) + render :edit + end + + def check_authorization + authorize!(:edit, current_order, session[:access_token]) + end end end diff --git a/app/controllers/spree/home_controller.rb b/app/controllers/spree/home_controller.rb index 8ce796b0c7..9fbdabe940 100644 --- a/app/controllers/spree/home_controller.rb +++ b/app/controllers/spree/home_controller.rb @@ -2,7 +2,6 @@ module Spree class HomeController < Spree::StoreController respond_to :html - def index - end + def index; end end end diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index cdf236ce94..d2de15441c 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -1,222 +1,226 @@ require 'spree/core/controller_helpers/order_decorator' require 'spree/core/controller_helpers/auth_decorator' -class Spree::OrdersController < Spree::StoreController - include OrderCyclesHelper - layout 'darkswarm' +module Spree + class OrdersController < Spree::StoreController + include OrderCyclesHelper + layout 'darkswarm' - ssl_required :show + ssl_required :show - before_filter :check_authorization - rescue_from ActiveRecord::RecordNotFound, :with => :render_404 - helper 'spree/products', 'spree/orders' + before_filter :check_authorization + rescue_from ActiveRecord::RecordNotFound, :with => :render_404 + helper 'spree/products', 'spree/orders' - respond_to :html - respond_to :json + respond_to :html + respond_to :json - before_filter :update_distribution, only: :update - before_filter :filter_order_params, only: :update - before_filter :enable_embedded_shopfront + before_filter :update_distribution, only: :update + before_filter :filter_order_params, only: :update + before_filter :enable_embedded_shopfront - prepend_before_filter :require_order_authentication, only: :show - prepend_before_filter :require_order_cycle, only: :edit - prepend_before_filter :require_distributor_chosen, only: :edit - before_filter :check_hub_ready_for_checkout, only: :edit - before_filter :check_at_least_one_line_item, only: :update + prepend_before_filter :require_order_authentication, only: :show + prepend_before_filter :require_order_cycle, only: :edit + prepend_before_filter :require_distributor_chosen, only: :edit + before_filter :check_hub_ready_for_checkout, only: :edit + before_filter :check_at_least_one_line_item, only: :update - def show - @order = Spree::Order.find_by_number!(params[:id]) - end - - def empty - if @order = current_order - @order.empty! + def show + @order = Spree::Order.find_by_number!(params[:id]) end - redirect_to main_app.cart_path - end - - def check_authorization - session[:access_token] ||= params[: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 - - # 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[:error] = t("spree.orders.error_flash_for_unavailable_items") + def empty + if @order = current_order + @order.empty! end - end - end - def update - @insufficient_stock_lines = [] - @order = order_to_update - unless @order - flash[:error] = t(:order_not_found) - redirect_to(root_path) && return + redirect_to main_app.cart_path end - if @order.update_attributes(params[:order]) - discard_empty_line_items - with_open_adjustments { update_totals_and_taxes } + def check_authorization + session[:access_token] ||= params[:token] + order = Spree::Order.find_by_number(params[:id]) || current_order - if @order == current_order - fire_event('spree.order.contents_changed') + if order + authorize! :edit, order, session[:access_token] else - @order.update_distribution_charge! + authorize! :create, Spree::Order end + end - respond_with(@order) do |format| - format.html do - if params.key?(:checkout) - @order.next_transition.run_callbacks if @order.cart? - redirect_to checkout_state_path(@order.checkout_steps.first) - elsif @order.complete? - redirect_to order_path(@order) - else - 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[:error] = t("spree.orders.error_flash_for_unavailable_items") end end - else - # Show order with original values, not newly entered ones - @insufficient_stock_lines = @order.insufficient_stock_lines - @order.line_items(true) - respond_with(@order) end - end - def update_distribution - @order = current_order(true) + def update + @insufficient_stock_lines = [] + @order = order_to_update + unless @order + flash[:error] = t(:order_not_found) + redirect_to(root_path) && return + end - if params[:commit] == 'Choose Hub' - distributor = Enterprise.is_distributor.find params[:order][:distributor_id] - @order.set_distributor! distributor + if @order.update_attributes(params[:order]) + discard_empty_line_items + with_open_adjustments { update_totals_and_taxes } - flash[:notice] = I18n.t(:order_choosing_hub_notice) - redirect_to request.referer + if @order == current_order + fire_event('spree.order.contents_changed') + else + @order.update_distribution_charge! + end - elsif params[:commit] == 'Choose Order Cycle' - @order.empty! # empty cart - order_cycle = OrderCycle.active.find params[:order][:order_cycle_id] - @order.set_order_cycle! order_cycle - - flash[:notice] = I18n.t(:order_choosing_hub_notice) - redirect_to request.referer + respond_with(@order) do |format| + format.html do + if params.key?(:checkout) + @order.next_transition.run_callbacks if @order.cart? + redirect_to checkout_state_path(@order.checkout_steps.first) + elsif @order.complete? + redirect_to 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(true) + respond_with(@order) + end end - 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]) + def update_distribution + @order = current_order(true) + + if params[:commit] == 'Choose Hub' + distributor = Enterprise.is_distributor.find params[:order][:distributor_id] + @order.set_distributor! distributor + + flash[:notice] = I18n.t(:order_choosing_hub_notice) + redirect_to request.referer + + elsif params[:commit] == 'Choose Order Cycle' + @order.empty! # empty cart + order_cycle = OrderCycle.active.find params[:order][:order_cycle_id] + @order.set_order_cycle! order_cycle + + flash[:notice] = I18n.t(:order_choosing_hub_notice) + redirect_to request.referer + end end - end - def remove_missing_line_items(attrs) - attrs.select do |_i, line_item| - Spree::LineItem.find_by_id(line_item[:id]) + 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 - end - def clear - @order = current_order(true) - @order.empty! - @order.set_order_cycle! nil - redirect_to main_app.enterprise_path(@order.distributor.id) - end - - def order_cycle_expired - @order_cycle = OrderCycle.find session[:expired_order_cycle_id] - end - - def cancel - @order = Spree::Order.find_by_number!(params[:id]) - authorize! :cancel, @order - - if @order.cancel - flash[:success] = I18n.t(:orders_your_order_has_been_cancelled) - else - flash[:error] = I18n.t(:orders_could_not_cancel) + def remove_missing_line_items(attrs) + attrs.select do |_i, line_item| + Spree::LineItem.find_by_id(line_item[:id]) + end end - redirect_to request.referer || order_path(@order) - end - private - - # Updates the various denormalized total attributes of the order and - # recalculates the shipment taxes - def update_totals_and_taxes - @order.updater.update_totals - @order.shipment.ensure_correct_adjustment_with_included_tax if @order.shipment - end - - # Sets the adjustments to open to perform the block's action and restores - # their state to whatever the they had. Note that it does not change any new - # adjustments that might get created in the yielded block. - def with_open_adjustments - previous_states = @order.adjustments.each_with_object({}) do |adjustment, hash| - hash[adjustment.id] = adjustment.state + def clear + @order = current_order(true) + @order.empty! + @order.set_order_cycle! nil + redirect_to main_app.enterprise_path(@order.distributor.id) end - @order.adjustments.each(&:open) - yield - - @order.adjustments.each do |adjustment| - previous_state = previous_states[adjustment.id] - adjustment.update_attribute(:state, previous_state) if previous_state + def order_cycle_expired + @order_cycle = OrderCycle.find session[:expired_order_cycle_id] end - end - def discard_empty_line_items - @order.line_items = @order.line_items.select { |li| li.quantity > 0 } - end + def cancel + @order = Spree::Order.find_by_number!(params[:id]) + authorize! :cancel, @order - def require_order_authentication - return if session[:access_token] || params[:token] || spree_current_user + if @order.cancel + flash[:success] = I18n.t(:orders_your_order_has_been_cancelled) + else + flash[:error] = I18n.t(:orders_could_not_cancel) + end + redirect_to request.referer || order_path(@order) + end - flash[:error] = I18n.t("spree.orders.edit.login_to_view_order") - require_login_then_redirect_to request.env['PATH_INFO'] - end + private - 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 + # Updates the various denormalized total attributes of the order and + # recalculates the shipment taxes + def update_totals_and_taxes + @order.updater.update_totals + @order.shipment.ensure_correct_adjustment_with_included_tax if @order.shipment + 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.andand.changes_allowed? && can?(:update, order) - order - end + # Sets the adjustments to open to perform the block's action and restores + # their state to whatever the they had. Note that it does not change any new + # adjustments that might get created in the yielded block. + def with_open_adjustments + previous_states = @order.adjustments.each_with_object({}) do |adjustment, hash| + hash[adjustment.id] = adjustment.state + end + @order.adjustments.each(&:open) - def check_at_least_one_line_item - return unless order_to_update.andand.complete? + yield - items = params[:order][:line_items_attributes] - .andand.select{ |_k, attrs| attrs["quantity"].to_i > 0 } + @order.adjustments.each do |adjustment| + previous_state = previous_states[adjustment.id] + adjustment.update_attribute(:state, previous_state) if previous_state + end + end - if items.empty? - flash[:error] = I18n.t(:orders_cannot_remove_the_final_item) - redirect_to order_path(order_to_update) + 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[:token] || spree_current_user + + flash[:error] = I18n.t("spree.orders.edit.login_to_view_order") + require_login_then_redirect_to 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.andand.changes_allowed? && can?(:update, order) + order + end + + def check_at_least_one_line_item + return unless order_to_update.andand.complete? + + items = params[:order][:line_items_attributes] + .andand.select{ |_k, attrs| attrs["quantity"].to_i > 0 } + + if items.empty? + flash[:error] = I18n.t(:orders_cannot_remove_the_final_item) + redirect_to order_path(order_to_update) + end end end end diff --git a/app/controllers/spree/store_controller.rb b/app/controllers/spree/store_controller.rb index c8d4c0c308..42b2dd337f 100644 --- a/app/controllers/spree/store_controller.rb +++ b/app/controllers/spree/store_controller.rb @@ -1,12 +1,14 @@ -class Spree::StoreController < Spree::BaseController - layout 'darkswarm' +module Spree + class StoreController < Spree::BaseController + layout 'darkswarm' - include Spree::Core::ControllerHelpers::Order + include Spree::Core::ControllerHelpers::Order - include I18nHelper - before_filter :set_locale + include I18nHelper + before_filter :set_locale - def unauthorized - render 'shared/unauthorized', status: :unauthorized + def unauthorized + render 'shared/unauthorized', status: :unauthorized + end end end