Two related defects in booking cancellation:
- Cancelling from the registration form or checkout (abandoning the booking) released the order holds and left it in the reusable empty state instead of cancelled. The emptied order could then be reused, starting a second workflow instance on the same order.
- An order could be cancelled while its workflow instance kept running (for example an operator cancel that transitioned no line), so the cancelled order could not be deleted and the workflow was never torn down.
Root cause: cancellation had several overlapping paths, and cancelling an order did not reliably terminate its workflow instance.
Fix, a single order-driven cancel path:
- A new order-cancellation bridge terminates an order running workflow instance when the order enters the cancelled state, from any surface (operator, cart, expiry), covering the case a booking-event-driven reconcile misses. It stands down when the workflow itself drives the cancel, so it never tears down the instance mid-step.
- The example booking workflow abandon path now cancels the order rather than emptying it, so a cancelled booking is cancelled, not reusable.
- Operator cancellation now requires a dedicated cancel booking permission on top of managing the order, since cancelling frees capacity and can trigger refunds. The customer self-cancel (signed link) is unchanged.
- The delete guard message is explicit about a cancelled order whose instance is still running, and the bulk operations form surfaces the guard reason instead of a generic skip.
Covered by kernel tests: an external cancel terminates an orphaned instance, a workflow-driven cancel does not self-terminate, cancellation requires the capability, and a foreign-tenant append to an order is rejected.
Comments
Comment #3
mably commentedOpened MR !65 against 1.x (mergeable, no conflicts). CI is running. Setting to Needs review.
Comment #5
mably commented