From c72976b1e22e4b91a67df6f5ea4db7870e2da97e Mon Sep 17 00:00:00 2001 From: Greg Austic Date: Fri, 27 Mar 2026 09:05:47 -0400 Subject: [PATCH] Fix guest order cancellation redirecting to home page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a guest places an order and tries to cancel it from the order confirmation page, the cancellation silently failed and redirected to the home page. The guest was left unsure whether the order was cancelled, and the hub received no cancellation notification. Root cause: two missing pieces for guest (token-based) authorization: 1. The `:cancel` ability in Ability#add_shopping_abilities only checked `order.user == user`, ignoring the guest token. The `:read` and `:update` abilities already support `order.token && token == order.token` as a fallback — `:cancel` now does the same. 2. The `cancel` action called `authorize! :cancel, @order` without passing `session[:access_token]`, so even with the corrected ability the token was never evaluated. Fixes #13817 Co-Authored-By: Claude Sonnet 4.6 --- app/controllers/spree/orders_controller.rb | 2 +- app/models/spree/ability.rb | 6 +++++- .../spree/orders_controller_spec.rb | 20 +++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index cb1cf63d64..d982d5a0e8 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -107,7 +107,7 @@ module Spree def cancel @order = Spree::Order.find_by!(number: params[:id]) - authorize! :cancel, @order + authorize! :cancel, @order, session[:access_token] if Orders::CustomerCancellationService.new(@order).call flash[:success] = I18n.t(:orders_your_order_has_been_cancelled) diff --git a/app/models/spree/ability.rb b/app/models/spree/ability.rb index f94e511337..702e0c3481 100644 --- a/app/models/spree/ability.rb +++ b/app/models/spree/ability.rb @@ -113,7 +113,11 @@ module Spree item.order.changes_allowed? end - can [:cancel, :bulk_cancel], Spree::Order do |order| + can :cancel, Spree::Order do |order, token| + order.user == user || (order.token && token == order.token) + end + + can :bulk_cancel, Spree::Order do |order| order.user == user end diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb index 630a73eade..88b4bbb523 100644 --- a/spec/controllers/spree/orders_controller_spec.rb +++ b/spec/controllers/spree/orders_controller_spec.rb @@ -461,6 +461,26 @@ RSpec.describe Spree::OrdersController do end end + context "when a guest user has the order token in session" do + let(:order) { + create(:completed_order_with_totals, user: nil, email: "guest@example.com", + distributor: create(:distributor_enterprise)) + } + + before do + allow(controller).to receive(:spree_current_user) { nil } + session[:access_token] = order.token + end + + it "cancels the order and redirects to the order page" do + spree_put :cancel, params + + expect(response).to have_http_status(:found) + expect(response.body).to match(order_path(order)).and match("redirect") + expect(flash[:success]).to eq 'Your order has been cancelled' + end + end + context "when the user has permission to cancel the order" do before { allow(controller).to receive(:spree_current_user) { user } }