Issue #3614426: A line can be taken out of an order the checkout owns, so the lock is advisory

Locking an order for checkout freezes it: the amount the visitor is paying was computed from the lines the order had.

What was and was not guarded

Adding was already refused. holdGroup() takes a new line into an order only while it is empty or pending (BookingManager.php:180-193), with a comment covering "a request racing a payment". The issue summary claimed otherwise; that half is wrong and the MR leaves that code alone. A test now pins it so the rule keeps holding.

Removing was not refused at all. release() checked only that the line was held, cancel() only that it was confirmed. Neither looked at the owning order, so the admin per-line operations, the bulk release and cancel actions, the API client, the seat map's re-seating and the quantity stepper could each take a line out from under a payment in flight.

The guard

One private assertNotInCheckout() in the booking manager, called from release() and cancel(). No edit surface was touched: all six inherit it. Its rule is deliberately narrower than the one for adding, because removal is also a legitimate later operation — cancelling one ticket of a confirmed order is ordinary operator work, and cancel() only accepts a confirmed line, which lives in a settled order by definition. So only the window the checkout owns is closed.

Settlement still has to let go of a frozen order's lines, and now says so by name: releaseForSettlement() and cancelForSettlement() skip the guard. Four callers use them — the order-wide release and cancellation, the failed-payment subscriber, and the workflow-termination releaser — and each says in a comment why it is exempt.

Also adds BookingTransactionInterface::isInCheckout() and CHECKOUT_STATES (locked, placed), which TransactionManager's state machine now shares instead of repeating the pair inline.

Testing

CheckoutFreezeTest covers both halves of the freeze, the settlement exemption, the order-wide release of a frozen order, and that an editable basket still adds and removes. Verified by disabling only the guard calls: the release test then reports no exception thrown, and the add test reported the pre-existing message — which is how the wrong half of the issue summary was caught.

104/104 kernel classes green across the project (the release path has six consumers, so the sweep ran unfiltered). phpcs and phpstan clean, no new warnings.

Docs updated in both places the freeze is described (docs/payment.md order lock, docs/cart.md removals). No translation change: the refusals are developer-facing exceptions, and the diff adds no t(), TranslatableMarkup or Drupal.t() call.

Merge request reports

Loading
Loading