Problem
Every resource form carries every field the engine and its submodules can offer, whether or not the site does that thing. A house that never charges a no-show fee still sees No-show fee on every resource, on every tariff, and on every cell of every tariff preset. A site with no calendar, or one whose events are always single days, still answers questions about both. The operator is left deciding a field that has only one right answer here, over and over.
Manage form display hides a field, but it hides it and nothing more: a value stored behind it still resolves, so "we do not do this" and "you cannot see what we do" are the same setting. There is also no way to say "the answer is this, everywhere" without typing it on every resource.
Proposed resolution
Per field a rule may reach, two things, set at the site, the tenant or the resource type:
- a display choice: show, hide, or read-only;
- an enforced default: the value that applies where the field is not answered locally.
Turning a feature off is then not a separate concept: it is hidden with a default of empty. Enforcing a house rule is read-only with the value. Today's behavior is show with no default. One mechanism covers all three, and an operator stops being asked about anything their site has already decided.
What this must get right
The default is enforced on read, not on the form. Where a level rules a field, the value comes from that level, whatever sits in the row underneath. Hiding alone would leave a value typed before the rule was made still winning, invisibly: the worst of both, since nothing on screen explains what applies. Skipping the lower levels rather than deleting their data also means relaxing the rule restores what was there.
Read-only shows the value and where it came from, for example "12.00, set on the resource type", rather than an empty grayed box. It teaches the chain instead of hiding it, and the source is stated in text rather than conveyed by color alone.
A module declares the fields a rule may reach. The fields worth a rule belong to the engine, to placement, to payment, to ticketing and to the calendar, so the settings form cannot enumerate them itself. Each module declares which of its fields a rule may reach, with a machine name and a label. A hard-coded list would go stale exactly as the four hand-written "- None -" relabels did before #3614386 replaced them with one helper.
A hidden field must be answerable without the form. Hiding a required field with no enforced default gives a form that cannot be submitted and no visible reason. So a field with a rule is either optional, or the level that hides it supplies the value.
A tariff preset is reached by the site and the tenant only. A preset belongs to the tenant and may be applied to a production of any type, so it has no resource type to inherit from. A rule made for one resource type cannot touch a preset's cells.
What this generalizes
The module already does this in one-off ways: tariffs_enabled decides whether the tariff UI exists at all, #states hides a cancellation deadline when cancellation is off, and several fields say "leave empty to inherit the resource type" and are relabeled per form. Those become instances of one rule rather than four unrelated mechanisms.
The inherit labels collapse with it. "Inherit from type", "Inherit from the resource" and "Inherit from the site" exist only because each field has exactly one possible source today; with a real chain they are all simply "Inherit".
Remaining tasks
- The chain and its storage, alongside the existing "leave empty to inherit the resource type" fields.
- The declaration each module makes of the fields a rule may reach.
- The resolver honoring an enforced default, so a stored value the rule overrides is never what applies.
- The form work: hiding, and rendering read-only with its source named.
- Kernel coverage: each level overriding its parent; a stored value the rule overrides resolving to the enforced one; a preset reached by the tenant answer and untouched by a resource type one; a hidden required field refused at configuration time rather than at save time.
- Docs, and a French translation, in the same commit.
User interface changes
A settings screen per level listing the fields a rule may reach, each with its display choice and its default. On the forms themselves: a field a rule decides is absent, or shown read-only with the value and the level that set it.
AI-Generated: Yes (Claude Code was used to help draft this issue summary and to write the code and tests on the merge request. I reviewed and ran the work myself before posting it.)
Issue fork yoyaku-3615142
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 commentedComment #9
mably commented