Nothing deletes a yoyaku_transaction in any state, so orders accumulate for the life of the site. The only cron sweeps are hold expiry, settlement, checkout reclaim and manager grants.
#3615440: Move the hold clock from the booking line to the order shipped the configuration for this and nothing else: order_retention, a state-keyed mapping on yoyaku.settings and yoyaku.tenant.* resolving tenant then site, deliberately not channel, because how long a booker's session lasts is a front's business while how long data is kept is the realm's. Nothing reads it yet. It also made empty orders routine, by ending a lapsed basket as empty rather than cancelling it, which is the right end state but leaves a contentless row behind every time.
The sweep is one cron query per configured state, state = X AND changed <= now - retention, ordered by changed, batch-limited and queued, the same bucketing sweptResourcesByGrace() already does for settlement. The ['state', 'changed'] composite it needs is already on BookingTransactionStorageSchema. An absent key means never delete, the reading a policy's enabled already carries, and the active states (pending, locked, placed, confirmed) are never eligible whatever is configured.
The part that needs designing is the guards, and it is why the sweep was left out of #3615440: Move the hold clock from the booking line to the order rather than shipped half-formed. An order must not be deleted while something still points at it, and only one of the three things that might is visible to the core module: whether it still has a line. The other two are a running Orchestra instance referencing it, which only yoyaku_orchestra can answer, and a payment row against it, which only yoyaku_payment can. Core cannot ask either without depending on it, so this needs a seam: a tagged OrderDeletionGuardInterface with any veto stopping the deletion, or an event the submodules may veto. The tagged service is the more predictable of the two and matches how availability bounds are already collected.
Two buckets are easy and go first. An empty order is definitionally contentless, and a cancelled one is the record of a booking that did not happen, so the accounting stakes are low; the payment guard is what does the real work there, since a cancellation that involved a refund is a record and must be left alone. P7D and P30D are the proposed defaults.
The settled states are the hard half, and the reason this is a plan rather than a task. Deleting a completed order destroys the record that a booking happened, and cascades into its lines, its payments, its tickets and any fee retained against it, all of which have accounting lives of their own. The reason to want a policy there is usually personal data rather than volume: the booker's name and address sit on the order. That argues for anonymizing a settled order rather than deleting it, keeping the booking and dropping the person. Which of the two, and whether the choice is made per state, is the decision this issue exists to make.
Remaining tasks: pick and build the guard seam, with a guard in each of yoyaku_orchestra and yoyaku_payment; the cron query and its queue worker; the order_retention fields on the tenant and site settings forms, which the configuration shipped without; decide delete against anonymize for the settled states and build whichever wins; tests, the one that matters most being that a guarded order survives a sweep it is otherwise eligible for; and the documentation. The deletion cascade itself is already covered by TransactionDeleteCascadeTest.
Issue fork yoyaku-3615441
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mably commentedComment #4
mably commentedComment #5
mably commentedComment #7
mably commented