Add a per-booker limit that sums units across everything it reaches

Adds the per-booker limit this issue asks for, as axes on the existing policy rather than new plugins.

The limit

slot_per_booker_limit becomes booker_quantity_limit. Two settings decide what its number means, and both count units, so the number on the form means the same thing however they are set.

count_across — how wide the sum is:

on a resource on a resource type
slot (default) each of its slots on its own each slot of every resource of the kind, on its own
resource all its slots added up that allowance granted separately to each resource of the kind
reach all its slots added up every resource of the kind pooled into one allowance

The middle width exists because a type attachment could otherwise only be the narrowest reading or the widest. "Ten per person per concert, the same rule for every concert" is the one most operators want, and it could previously only be said by attaching to each concert by hand.

count_from — how far back the counting goes, which is a separate question:

Counts
upcoming (default) only slots that are not over yet
date everything from a day the operator names, slots already over included
all every booking, however old

Neither of the first two is a default for the other. "One refuge at a time" needs upcoming, since a stay that is over has to release its allowance. "Ten concerts for the season" needs date, since a concert attended in September must keep counting in October, or the allowance quietly resets every night.

The cutoff is judged on when a slot ends, not when it starts: a refuge the booker is in tonight began this afternoon and has to keep counting, or a second one could be taken mid-stay. A named day is read in the site's own timezone, because it is the operator's day and not UTC.

Why the cutoff is not left to the booking states

A booking leaves held or confirmed only when something completes it or marks it unused, and the worker that does so after an event is never enqueued for a resource on manual settlement. Without a cutoff an allowance is spent for good on those resources, and a booker who came last season can never book again.

That applies to cross_resource_limit too, so count_from lives in BookerPolicyBase alongside the count-by dimensions both policies already share, and both inherit the setting, its form, its validation and the query condition. It is what makes that policy "at a time" rather than "for all time". transaction_quantity_limit is deliberately untouched: it counts within one transaction, so every line it sees is in the request in front of it and there is nothing older to cut off.

The reach is the host, not the request

A season allowance counts the dates the booker is not touching in this click as much as the one they are. Reading it from the lines would turn it into a per-basket limit, which transaction_quantity_limit already is. Nothing wider than the attachment's own lines is needed, so this does not reach for evaluationLines().

On the open question in the issue

The ids are migrated as data rather than kept. slot_per_booker_limit named one of the readings the policy now offers, so keeping it would make the id lie for the others. scripts/migrate-policy-names.php is generalized from one rename chain to a list and applies both renames it knows about. No new setting is written by the migration: the defaults are the old behavior, so an attachment carrying nothing keeps working as it did.

Tests

Nine new cases in OrderConstraintTest, each run against a deliberately broken build and seen to fail before being kept: the axis routed to a neighbouring width, the cutoff removed, and a named day treated as now. Controls accompany each, so that forgetting what is over did not become forgetting everything. Every case names the booker before the click it is about, the discipline [#3614839] established.

Wording

Stops calling the generic booked quantity a "place" in the files this touches, including the names [#3614839] shipped. A place is one specific bookable among many, provided by the dedicated yoyaku_placement module. Separately, the hosts table glossed a resource as "one hall", which contradicts the venue entity: the hall is the venue, and each concert running in it is a resource. Examples now say concert. The rest of that sweep, and letting a resource name the unit it sells through a plugin custom modules can extend, is [#3614854].

Docs and fr.po updated in the same commits throughout.

Edited by Frank Mably

Merge request reports

Loading
Loading