The status was derived in Contracts/Mappers.ToStatusDto, not the domain; Concept was a magic "Concept" string with no AanvraagStatusTag member; and the besluit endpoint re-derived its own guard by reading the status back out of the DTO and Enum.Parse-ing it. New Domain/Applications/AanvraagStatus.cs models the full status (Concept included, via a null Tag rather than a sixth enum member) as a closed type, constructible only through its factories. Aanvraag.StatusAt(now) carries the logic verbatim; Mappers.ToStatusDto and ZgwZaakMapper's two status producers become one-line projections onto the same wire DTO, so the wire shape is unchanged (gen:api shows zero diff beyond F1's). The one remaining Enum.Parse (the beoordeling GET, which crosses the IZaakSource wire boundary) is now non-throwing on an unrecognised tag. Also, WP-68 F2: the besluit transition-legality check now runs inside ApplicationStore.RecordBesluit's write lock instead of in the endpoint beforehand — two concurrent besluiten used to both pass the check before either wrote, letting the second silently overwrite a terminal decision. RecordBesluit returns an Ok/NotFound/Conflict outcome, mirroring DocumentStore.DeleteResult. Also, WP-68 F6: the "toelichting required" rule moves from an inline endpoint check into BeoordelingRules.RequiresToelichting, alongside CanDecide. The three tests naming this refactor's regression net (AanvraagStatusTag_covers_the_published_lifecycle, AutoApprovable_flips_to_goedgekeurd_after_the_window, ZgwZaakMapperTests) pass unmodified. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
63 lines
2.9 KiB
C#
63 lines
2.9 KiB
C#
namespace BigRegister.Domain.Applications;
|
|
|
|
/// <summary>
|
|
/// The post-submission aanvraag status lifecycle (ADR-0002, WP-63): Ingediend → In
|
|
/// behandeling → (Meer info gevraagd ⇄) → Goedgekeurd/Afgewezen. Concept (pre-submission,
|
|
/// the wizard draft) is deliberately NOT a member here — see <see cref="AanvraagStatus.Tag"/>,
|
|
/// which is null exactly when the aanvraag hasn't been submitted yet, instead of a sixth
|
|
/// "magic string" tag with no enum member to match it (WP-68 F3).
|
|
/// <see cref="Ingediend"/> is reserved: no endpoint sets it yet (there is no state between
|
|
/// "just submitted" and "in behandeling" in this POC) — kept because the FE's status union
|
|
/// and $localize catalogue already declare it, and removing it would ripple into both.
|
|
/// </summary>
|
|
public enum AanvraagStatusTag { Ingediend, InBehandeling, MeerInfoGevraagd, Goedgekeurd, Afgewezen }
|
|
|
|
/// <summary>
|
|
/// A behandelaar's recorded decision (WP-65b) — the three actions the beoordeling screen
|
|
/// offers, each advancing an aanvraag's <see cref="AanvraagStatus"/>.
|
|
/// </summary>
|
|
public enum Besluit { Goedkeuren, Afwijzen, MeerInfoOpvragen }
|
|
|
|
/// <summary>
|
|
/// The domain projection of an aanvraag's status at a point in time (WP-68 F3) — the type
|
|
/// <c>Aanvraag.StatusAt(now)</c> returns, replacing the logic that used to live directly in
|
|
/// <c>Contracts.Mappers.ToStatusDto</c>. Constructible only via the factories below, so a
|
|
/// caller can never build e.g. a Referentie-less Goedgekeurd. <see cref="Tag"/> is null only
|
|
/// for <see cref="Concept"/> — the one construction path that used to be a bare "Concept"
|
|
/// string with no corresponding <see cref="AanvraagStatusTag"/> member.
|
|
/// </summary>
|
|
public sealed class AanvraagStatus
|
|
{
|
|
public AanvraagStatusTag? Tag { get; }
|
|
public int? StepIndex { get; }
|
|
public int? StepCount { get; }
|
|
public string? Referentie { get; }
|
|
public bool? Manual { get; }
|
|
public string? Reden { get; }
|
|
|
|
private AanvraagStatus(AanvraagStatusTag? tag, int? stepIndex, int? stepCount, string? referentie, bool? manual, string? reden)
|
|
{
|
|
Tag = tag;
|
|
StepIndex = stepIndex;
|
|
StepCount = stepCount;
|
|
Referentie = referentie;
|
|
Manual = manual;
|
|
Reden = reden;
|
|
}
|
|
|
|
public static AanvraagStatus Concept(int stepIndex, int stepCount) =>
|
|
new(null, stepIndex, stepCount, null, null, null);
|
|
|
|
public static AanvraagStatus InBehandeling(string referentie, bool manual) =>
|
|
new(AanvraagStatusTag.InBehandeling, null, null, referentie, manual, null);
|
|
|
|
public static AanvraagStatus Goedgekeurd(string referentie) =>
|
|
new(AanvraagStatusTag.Goedgekeurd, null, null, referentie, null, null);
|
|
|
|
public static AanvraagStatus Afgewezen(string referentie, string? reden) =>
|
|
new(AanvraagStatusTag.Afgewezen, null, null, referentie, null, reden);
|
|
|
|
public static AanvraagStatus MeerInfoGevraagd(string referentie, string? reden) =>
|
|
new(AanvraagStatusTag.MeerInfoGevraagd, null, null, referentie, null, reden);
|
|
}
|