using Big.Domain; namespace Big.Application; /// A zorgprofessional's request to withdraw their own registration ("trek aanvraag in"). public sealed record WithdrawRegistrationCommand(RegistrationId RegistrationId); /// /// The withdrawal use case (S-11): a zorgprofessional pulls a still-open registration back. It /// advances the aggregate to INGETROKKEN, persists it, then cancels the running registratie process /// by delivering the withdrawal message to its open Beoordelen task (ADR-0014), so the case /// leaves the behandelaar's werkbak. Idempotent — a repeated or redelivered withdrawal of an /// already-withdrawn registration is a no-op (not persisted or cancelled again). Cancelling is /// best-effort: if no Beoordelen task is open (the process has not parked there yet, or has /// already ended) the withdrawal still stands — mirroring . /// public sealed class WithdrawRegistration(IRegistrationStore store, IUserTaskClient tasks) { public async Task HandleAsync(WithdrawRegistrationCommand command, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(command); var registration = await store.GetAsync(command.RegistrationId, ct) ?? throw new InvalidOperationException($"No registration {command.RegistrationId} to withdraw."); // A repeated withdrawal is a no-op: don't persist or cancel the already-withdrawn one again. if (registration.Status == RegistrationStatus.Ingetrokken) return; registration.Withdraw(); await store.SaveAsync(registration, ct); await CancelWorkflowTaskAsync(command.RegistrationId, ct); } // Cancel the workflow: deliver the withdrawal message to the open Beoordelen task's execution so // the process's boundary event ends it. If none is open the withdrawal still stands. private async Task CancelWorkflowTaskAsync(RegistrationId registrationId, CancellationToken ct) { var open = await tasks.GetOpenBeoordelingenAsync(ct); var task = open.FirstOrDefault(t => t.RegistrationId == registrationId); if (task is not null) await tasks.WithdrawBeoordelingAsync(task.ExecutionId, ct); } }