using Big.Domain; namespace Big.Application; /// A behandelaar's beoordeling outcome, in domain language. public enum BeoordelingsBesluit { /// Approve โ€” enter the registration in the register. Goedkeuren, /// Reject โ€” turn the registration down. Afwijzen, } /// A behandelaar's decision on a registration. public sealed record BeoordeelRegistratieCommand(RegistrationId RegistrationId, BeoordelingsBesluit Besluit); /// /// The beoordeling use case (S-12): apply a behandelaar's decision to a registration. /// sets the zaak's final status via the ACL (ยง8.1) and /// advances the aggregate to INGESCHREVEN; advances it to /// AFGEWEZEN in the domain (propagating a rejection to the zaak, so the openbaar projection reflects /// it, is a later sub-slice of S-12). Both decisions are idempotent โ€” a repeated or redelivered /// decision that matches the current terminal state is a no-op, so the ACL is not called twice. /// public sealed class BeoordeelRegistratie(IRegistrationStore store, IAclClient acl) { public async Task HandleAsync(BeoordeelRegistratieCommand command, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(command); var registration = await store.GetAsync(command.RegistrationId, ct) ?? throw new InvalidOperationException($"No registration {command.RegistrationId} to decide."); switch (command.Besluit) { case BeoordelingsBesluit.Goedkeuren: // A repeated approval is a no-op: don't set the zaak status a second time. if (registration.Status == RegistrationStatus.Ingeschreven) return; if (registration.ZaakUrl is null) throw new InvalidOperationException( $"Registration {command.RegistrationId} has no zaak yet; it cannot be approved."); await acl.ApproveZaakAsync(registration.ZaakUrl, ct); registration.Approve(); break; case BeoordelingsBesluit.Afwijzen: if (registration.Status == RegistrationStatus.Afgewezen) return; registration.Reject(); break; } await store.SaveAsync(registration, ct); } }