Problem/Motivation

The rule from #3616316: Refuse a booking that orphans a place, alone between bookings or at the end of a row is all or nothing. Attached, the automatic seating avoids leaving a place available on its own and the hold refuses one; absent or switched off, neither happens. A venue can reasonably want the first without the second: let the engine seat parties tidily, and let a booker who is clicking a seat map take whatever seat they like, hole or no hole. A house that trusts its bookers, or one whose staff take bookings over the counter, does not want the map answering a click with a refusal.

Proposed resolution

One checkbox on the policy, off by default: Let a booker choose a place that leaves one on its own. With it on, check() skips any line whose place was chosen rather than assigned, and still judges the lines the engine placed. Nothing about the seating strategy changes: leaveAtLeast() keeps returning the configured minimum, so every rung goes on avoiding orphans.

The signal already exists per line and needs no new field. VenuePlacementProvider stamps place_chosen FALSE on the lines it places and PlaceSelectionController stamps it TRUE on a place clicked on the map, and a proposed policy line now carries the values a consumer attached to it, so the policy can tell them apart without asking anything.

Two consequences worth stating. The map path becomes free: with every proposed line chosen there is nothing to judge, so the policy never makes its availability read and the one extra query per hold disappears in that mode. And the engine-placed lines stay judged, which turns the rule into a guard against a strategy that proposed something it should not, rather than a wall in front of bookers.

The setting stays in yoyaku_placement rather than being offered by every constraint policy. It only means something for a rule about where a booking sits: on a quantity or per-booker cap it would let a booker exceed the cap by clicking the map instead of using the stepper, which is what those policies exist to prevent, and place_chosen is a placement value that yoyaku core has no business reading. When a second placement rule wants the same setting, it becomes a trait here, as LimitSettingTrait was extracted once three policies shared a number.

What this cannot express. place_chosen means the place was named rather than assigned; it does not say who named it. An operator typing a place at the counter looks exactly like a booker clicking the map, since both paths set it. A rule of the form "operators may, bookers may not" needs a different signal, a permission or the booking channel, and is a larger design than this checkbox.

Remaining tasks

  • The setting, its schema key and the guard in check().
  • A test each way: with the setting off a chosen place that would orphan another is refused; with it on the same click is accepted, the strategy still avoids orphans, and the availability read is not made.
  • The policy documentation and the French translation.

User interface changes

One checkbox in the policy's settings, off by default, so an existing attachment behaves exactly as it does now.

API changes

One settings key on a policy that has not been released. Nothing else.

Data model changes

None. The per-line signal it reads is already stored on the booking.

AI-Generated: Yes (Claude Code drafted this issue summary; the design was settled in conversation with the maintainer. No code is written yet.)

Issue fork yoyaku-3616344

Command icon 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

mably created an issue. See original summary.

mably’s picture

Issue summary: View changes

  • mably committed 2509d0fa on 1.x
    feat: #3616344 Let a venue apply the orphan rule to the automatic...
mably’s picture

Status: Active » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.