solidus icon indicating copy to clipboard operation
solidus copied to clipboard

<Checkout>Redirected to address step with a free order in the cart

Open rainerdema opened this issue 4 years ago • 2 comments

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

  1. Create a promotion with these two rules to get a free order (Order with Flat Rate 100% + Shipment free)
  2. Set a tax rate to 0
  3. Make sure the pre-selected shipping method doesn't cost 0
  4. 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

rainerdema avatar Feb 26 '21 15:02 rainerdema

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:

  1. order's state is address, and its total is 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's checkout_steps are ["address", "delivery", "confirm", "complete"]
  2. User clicks 'save and continue'
  3. The order's state becomes delivery by the #transition_forward -> @order.next https://github.com/solidusio/solidus/blob/63501e77bbc66d7a55b7b34650c44659041842fc/frontend/app/controllers/spree/checkout_controller.rb#L34
  4. Now a shipment has been added to the order and the total becomes higher than 0. The order's checkout_steps changes to: ["address", "delivery", "payment", "confirm", "complete"]
  5. User clicks 'save and continue'
  6. Ordergoes into #transition_forward
  7. #apply_shipping_promotions occurs and total becomes 0 https://github.com/solidusio/solidus/blob/cff5fc0e67592ee87d85e4ae1dc8710c65bcbd18/core/lib/spree/core/state_machines/order.rb#L105
  8. Order's state becomes payment
  9. order's checkout_state becomes ["address", "delivery", "confirm", "complete"]
  10. GET request occurs for '/payment'
  11. CheckoutController invalidates 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.

RyanofWoods avatar Jun 22 '21 08:06 RyanofWoods

@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?

kennyadsl avatar Sep 06 '22 08:09 kennyadsl