<Checkout>Redirected to address step with a free order in the cart
We are trying to assign to a single user a promotion that allow to have a free order (order + shipping) but from the delivery step, we are redirected to the address step.
Note: The Store Tax rate is equal to 0 by default.
Solidus Version: All solidus versions
To Reproduce
-
Create a promotion with these two rules to get a free order (Order with Flat Rate 100% + Shipment free)

-
Set a tax rate to 0

-
Make sure the pre-selected shipping method doesn't cost 0

- Proceed with a checkout
Current behavior
From the delivery step, you will be redirected to the step address because Solidus tries to render the payment step, which shouldn't be enabled.
Expected behavior Skip the payment step and go to the confirm step.
Additional context
If you try to set the first shipping method cost to 0, you will be able to finalize the order. This is because the rendered order's default total will be equal to 0, and therefore the payment step will be correctly excluded.
The problem is also related to not having a tax rate.
In this case, we will certainly not have a payment step.
So when Solidus render the delivery step, we have a shipment promotion that will be applied immediately after the delivery:
https://github.com/solidusio/solidus/blob/cff5fc0e67592ee87d85e4ae1dc8710c65bcbd18/core/lib/spree/core/state_machines/order.rb#L105
https://github.com/solidusio/solidus/blob/cff5fc0e67592ee87d85e4ae1dc8710c65bcbd18/core/app/models/spree/order.rb#L504-L507
The first shipping method pre-assigned (with an amount > 0), initialize the checkout_steps with the payment state because the order has a total > 0:
https://github.com/solidusio/solidus/blob/cff5fc0e67592ee87d85e4ae1dc8710c65bcbd18/core/app/models/spree/order.rb#L49
https://github.com/solidusio/solidus/blob/cff5fc0e67592ee87d85e4ae1dc8710c65bcbd18/core/app/models/spree/order.rb#L227-L230
So, the step will be considered during the @order.next, but it will be invalidated by:
https://github.com/solidusio/solidus/blob/cff5fc0e67592ee87d85e4ae1dc8710c65bcbd18/frontend/app/controllers/spree/checkout_controller.rb#L12
Thank you for such a good outline of the problem @rainerdema. I looked into the problem more and wanted to add additional context. You were right about the initial total, checkout steps, and the shipment promotion being applied afterward. It seems however the checkout process is becoming invalidated because of CheckoutController#ensure_valid_state.
Implementing a fix for within this area is a bit beyond my understanding as of right now, but I thought I would make a clear outline of exactly why the problem is occurring for anyone who wants to make a PR:
Scenario of the user adding an item, applying a promotion for free order (100% flat rate), and free shipping:
-
order's state isaddress, and itstotalis 0 as the 100% flat rate promotion has been applied to the line item, but shipping has not been added yet. Because of this the order'scheckout_stepsare["address", "delivery", "confirm", "complete"] - User clicks 'save and continue'
- The
order's state becomesdeliveryby the#transition_forward->@order.nexthttps://github.com/solidusio/solidus/blob/63501e77bbc66d7a55b7b34650c44659041842fc/frontend/app/controllers/spree/checkout_controller.rb#L34 - Now a
shipmenthas been added to the order and the total becomes higher than 0. Theorder'scheckout_stepschanges to:["address", "delivery", "payment", "confirm", "complete"] - User clicks 'save and continue'
-
Ordergoes into#transition_forward -
#apply_shipping_promotionsoccurs andtotalbecomes 0 https://github.com/solidusio/solidus/blob/cff5fc0e67592ee87d85e4ae1dc8710c65bcbd18/core/lib/spree/core/state_machines/order.rb#L105 - Order's state becomes
payment -
order'scheckout_statebecomes["address", "delivery", "confirm", "complete"] - GET request occurs for '/payment'
-
CheckoutControllerinvalidates order by `#ensure_valid_state' making the order go back to the state of 'address' https://github.com/solidusio/solidus/blob/63501e77bbc66d7a55b7b34650c44659041842fc/frontend/app/controllers/spree/checkout_controller.rb#L119-L126
Note, changing this https://github.com/solidusio/solidus/blob/63501e77bbc66d7a55b7b34650c44659041842fc/core/lib/spree/core/state_machines/order.rb#L101-L106 To:
if states[:delivery]
before_transition to: :delivery, do: :ensure_shipping_address
before_transition to: :delivery, do: :create_proposed_shipments
before_transition to: :delivery, do: :ensure_available_shipping_rates
before_transition to: :delivery, do: :apply_shipping_promotions
before_transition from: :delivery, do: :apply_shipping_promotions
end
Solved this issue and got the expected behavior, but I think this sort of fix could break edge cases where there are multiple shipping options.
@rainerdema @RyanofWoods now that we moved the frontend to a separate repository, I'm not sure if we need to move this issue there or it's more an issue we should address in core (or both?). What do you think?