namespace Big.Domain; /// /// The Registration aggregate root (CLAUDE.md §2.2): a zorgprofessional's submission to the BIG /// register. It owns its lifecycle invariants — it starts /// on submission, remembers the Flowable process that drives it, and records the zaak the ACL opens. /// public sealed class Registration { private Registration(RegistrationId id, string bsn) { Id = id; Bsn = bsn; Status = RegistrationStatus.Ingediend; } public RegistrationId Id { get; } /// The citizen-service number of the submitting zorgprofessional. Handed to the ACL /// as the domain payload; the domain never constructs ZGW concepts from it (§8.1). public string Bsn { get; } public RegistrationStatus Status { get; private set; } /// The Flowable process instance driving this registration, once started. public string? ProcessInstanceId { get; private set; } /// The zaak the ACL opened for this registration, once the external task has run. public Uri? ZaakUrl { get; private set; } /// Submit a new registration. It begins in . public static Registration Submit(string bsn) { ArgumentException.ThrowIfNullOrWhiteSpace(bsn); return new Registration(RegistrationId.New(), bsn); } /// Record that the registratie workflow process has been started for this registration. public void RecordProcessStarted(string processInstanceId) { ArgumentException.ThrowIfNullOrWhiteSpace(processInstanceId); ProcessInstanceId = processInstanceId; } /// /// Attach the zaak the ACL opened. The external-task worker may deliver the same job more than /// once (at-least-once), so re-attaching the identical URL is a no-op; a different URL signals a /// genuine conflict and is rejected. The status stays : /// opening the zaak does not advance the registration's lifecycle in this slice. /// public void AttachZaak(Uri zaakUrl) { ArgumentNullException.ThrowIfNull(zaakUrl); if (ZaakUrl is not null) { if (ZaakUrl != zaakUrl) throw new InvalidOperationException( $"Registration {Id} already has zaak {ZaakUrl}; cannot attach a different zaak {zaakUrl}."); // Stryker disable once Statement : equivalent — re-assigning the identical URL below is a // no-op, so removing this early return is behaviourally indistinguishable. return; } ZaakUrl = zaakUrl; } /// /// A behandelaar picks the registration up for beoordeling. Advances /// . /// Re-taking one already is a no-op (the same or /// another behandelaar re-opens it); a decided registration can no longer be taken into behandeling. /// public void TakeIntoBehandeling() { if (Status == RegistrationStatus.InBehandeling) return; if (Status != RegistrationStatus.Ingediend) throw new InvalidOperationException( $"Registration {Id} is {Status}; only an INGEDIEND registration can be taken into behandeling."); Status = RegistrationStatus.InBehandeling; } /// /// Approve the registration — the behandelaar's decision to enter it in the register. Advances a /// submitted or in-behandeling registration to . /// Requires an opened zaak (the approval sets that zaak's status via the ACL); a registration that /// has already been decided cannot be approved again. /// public void Approve() { if (ZaakUrl is null) throw new InvalidOperationException( $"Registration {Id} has no zaak yet; it cannot be approved before its zaak is opened."); RequireOpenForDecision(nameof(Approve)); Status = RegistrationStatus.Ingeschreven; } /// /// Reject the registration — the behandelaar's decision not to enter it in the register. Advances a /// submitted or in-behandeling registration to . Unlike /// approval this needs no zaak: a registration can be rejected before or after its zaak is opened. /// A registration that has already been decided cannot be rejected again. /// public void Reject() { RequireOpenForDecision(nameof(Reject)); Status = RegistrationStatus.Afgewezen; } // A decision is only valid while the registration is still open (INGEDIEND or IN_BEHANDELING). private void RequireOpenForDecision(string decision) { if (Status is not (RegistrationStatus.Ingediend or RegistrationStatus.InBehandeling)) throw new InvalidOperationException( $"Registration {Id} is {Status}; only an INGEDIEND or IN_BEHANDELING registration can be decided ({decision})."); } }