-
Mahmoud Aglan authored
Two things the desk could not previously be made to capture. A product now carries the details it cannot be sold without — a size, a colour, the name printed on the back. The admin declares them per product as either free text or a list of predefined answers; the registration wizard renders them inline on the cart row and refuses to move to payment while a required one is blank. None of this is a separate product, and none of it is reconstructable after the fact from an invoice line that says "قميص تدريب" — which is why the answers freeze onto invoice_items.metadata and into the line description at sale time. Renaming "لارج" to "L" next season must not rewrite what a player ordered last season, exactly as prices freeze. hotbuyCustomizations is browser-writable by necessity — it is what the receptionist is typing — so nothing downstream trusts it. Both the step guard and confirm() re-read the questions through Eloquent (Product carries BranchScope, so another branch's product resolves to nothing) and check every answer against ProductCustomization::accepts(). A select must match its own list: the dropdown is a convenience, not the check. Separately, a person entered into the system must now carry a four-part name. Egyptian records are keyed on it — national ID, birth certificate, federation card, school file — and a player registered as "محمد أحمد" matches none of them; two players sharing a first and father's name are common enough that parts three and four are what tell them apart. Applied where people are created at the desk and in the portal: the registration wizard (player and guardian), retroactive enrolment, the participant form, and portal sign-up. Four is a floor, not a target. FullName splits on Unicode whitespace explicitly. \s under /u still only means ASCII whitespace, and an Arabic keyboard produces U+00A0 — glued together, a perfectly valid four-part name would have been rejected. Deliberately left alone: - ParticipantImport is exempt. Enforcing the rule on a bulk import would block loading an existing roster, which is the one case where the short names are already a fact. - Records already in the database are untouched. This validates at entry. - The POS terminal, settlement wizard, group screen and essential- deliveries screen sell these same products and do not yet ask for the customizations. - Kits carry no customizations, only products. Migration is additive and guarded; CHECK constraint matches the enum character for character. 382 passed / 99 skipped on the restored Postgres tenant, 303 passed / 178 skipped on SQLite. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
d3113b08