namespace BigRegister.Domain.Intake; /// /// Config value (ADR-0001's "config value" shape). Below this many NL work-hours the /// scholing question is required. The frontend receives this value /// (GET /intake/policy) and applies it for instant UX feedback /// (intake.machine.ts's lageUren); is the /// backend re-validating it as the authority on submit (WP-69) — /// POST /aanvragen/{id}/submit (intake-typed aanvragen only) calls it before /// writing anything, and a violation 400s (ProblemDetails), never silently accepts /// an incomplete answer. /// public static class IntakePolicy { public const int ScholingThreshold = 1000; /// /// Completeness rule for the scholing question (WP-69) — not merit: below /// an answer must be present, but "nee" is a legal answer /// that still submits (turning "few uren + no scholing" into a rejection is out of scope, /// see the WP). Three-valued, so two parameters (uren, punten) couldn't express it: /// /// below threshold and no answer at all ⇒ incomplete; /// answered true (scholing gevolgd) ⇒ punten required and non-negative /// (mirrors parseUren); /// answered anything but true ⇒ punten must be absent (a stale answer left /// behind by raising uren is not a legal payload). /// /// Returns the Dutch detail message for a 400 ProblemDetails, or null when complete. /// Boundary is <, not <= — mirrors lageUren. /// public static string? RejectIncompleteScholing(int uren, bool? aanvullendeScholing, int? scholingPunten) { if (uren < ScholingThreshold && aanvullendeScholing is null) return $"Beantwoord de vraag over aanvullende scholing: bij minder dan {ScholingThreshold} gewerkte uren is dit verplicht."; if (aanvullendeScholing == true && (scholingPunten is null || scholingPunten < 0)) return "Vul het aantal behaalde nascholingspunten in."; if (aanvullendeScholing != true && scholingPunten is not null) return "Nascholingspunten horen alleen bij een gevolgde aanvullende scholing."; return null; } }