Compare commits
7 Commits
main
...
feat/13-be
| Author | SHA1 | Date | |
|---|---|---|---|
| 7693a4a85a | |||
| ddebfd371a | |||
| d700659957 | |||
| 63699c3f55 | |||
| 5c05879cde | |||
| 09000d8e64 | |||
| 23125ef492 |
@@ -24,6 +24,7 @@ builder.Services.AddHttpClient<IAclClient, AclHttpClient>();
|
|||||||
|
|
||||||
builder.Services.AddScoped<SubmitRegistration>();
|
builder.Services.AddScoped<SubmitRegistration>();
|
||||||
builder.Services.AddScoped<ApproveRegistration>();
|
builder.Services.AddScoped<ApproveRegistration>();
|
||||||
|
builder.Services.AddScoped<BeoordeelRegistratie>();
|
||||||
builder.Services.AddScoped<OpenZaakWorker>();
|
builder.Services.AddScoped<OpenZaakWorker>();
|
||||||
builder.Services.AddScoped<OpenZaakJobProcessor>();
|
builder.Services.AddScoped<OpenZaakJobProcessor>();
|
||||||
|
|
||||||
@@ -55,6 +56,22 @@ app.MapPost("/registrations/{id}/approve", async (string id, ApproveRegistration
|
|||||||
return Results.NoContent();
|
return Results.NoContent();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The behandelaar's beoordeling (S-12): decide a registration goedkeuren (→ INGESCHREVEN, sets the
|
||||||
|
// zaak's final status via the ACL) or afwijzen (→ AFGEWEZEN). Idempotent. This is the domain contract
|
||||||
|
// the behandel-portal's decision reaches through the BFF; it supersedes the temporary /approve above,
|
||||||
|
// which is retired once the portal lands.
|
||||||
|
app.MapPost("/registrations/{id}/decide", async (string id, DecideRequest body, BeoordeelRegistratie beoordeel, CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
if (!Guid.TryParse(id, out var guid))
|
||||||
|
return Results.NotFound();
|
||||||
|
|
||||||
|
if (!Enum.TryParse<BeoordelingsBesluit>(body.Besluit, ignoreCase: true, out var besluit))
|
||||||
|
return Results.BadRequest(new { error = $"Unknown besluit '{body.Besluit}'. Expected 'goedkeuren' or 'afwijzen'." });
|
||||||
|
|
||||||
|
await beoordeel.HandleAsync(new BeoordeelRegistratieCommand(new RegistrationId(guid), besluit), ct);
|
||||||
|
return Results.NoContent();
|
||||||
|
});
|
||||||
|
|
||||||
// Read a registration. Its zaak URL appears once the worker has opened the zaak (eventually).
|
// Read a registration. Its zaak URL appears once the worker has opened the zaak (eventually).
|
||||||
app.MapGet("/registrations/{id}", async (string id, IRegistrationStore store, CancellationToken ct) =>
|
app.MapGet("/registrations/{id}", async (string id, IRegistrationStore store, CancellationToken ct) =>
|
||||||
{
|
{
|
||||||
@@ -72,6 +89,8 @@ await app.RunAsync();
|
|||||||
|
|
||||||
public sealed record SubmitRegistrationRequest(string Bsn);
|
public sealed record SubmitRegistrationRequest(string Bsn);
|
||||||
|
|
||||||
|
public sealed record DecideRequest(string Besluit);
|
||||||
|
|
||||||
public sealed record RegistrationResponse(string RegistrationId, string Status, string? ZaakUrl);
|
public sealed record RegistrationResponse(string RegistrationId, string Status, string? ZaakUrl);
|
||||||
|
|
||||||
public partial class Program;
|
public partial class Program;
|
||||||
|
|||||||
57
services/domain/Big.Application/BeoordeelRegistratie.cs
Normal file
57
services/domain/Big.Application/BeoordeelRegistratie.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using Big.Domain;
|
||||||
|
|
||||||
|
namespace Big.Application;
|
||||||
|
|
||||||
|
/// <summary>A behandelaar's beoordeling outcome, in domain language.</summary>
|
||||||
|
public enum BeoordelingsBesluit
|
||||||
|
{
|
||||||
|
/// <summary>Approve — enter the registration in the register.</summary>
|
||||||
|
Goedkeuren,
|
||||||
|
|
||||||
|
/// <summary>Reject — turn the registration down.</summary>
|
||||||
|
Afwijzen,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>A behandelaar's decision on a registration.</summary>
|
||||||
|
public sealed record BeoordeelRegistratieCommand(RegistrationId RegistrationId, BeoordelingsBesluit Besluit);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The beoordeling use case (S-12): apply a behandelaar's decision to a registration.
|
||||||
|
/// <see cref="BeoordelingsBesluit.Goedkeuren"/> sets the zaak's final status via the ACL (§8.1) and
|
||||||
|
/// advances the aggregate to INGESCHREVEN; <see cref="BeoordelingsBesluit.Afwijzen"/> 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.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,10 +66,28 @@ public sealed class Registration
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Approve the registration — the behandelaar's decision to enter it in the register. Advances
|
/// A behandelaar picks the registration up for beoordeling. Advances
|
||||||
/// <see cref="RegistrationStatus.Ingediend"/> → <see cref="RegistrationStatus.Ingeschreven"/>.
|
/// <see cref="RegistrationStatus.Ingediend"/> → <see cref="RegistrationStatus.InBehandeling"/>.
|
||||||
/// Requires an opened zaak (the approval sets that zaak's status via the ACL), and only a
|
/// Re-taking one already <see cref="RegistrationStatus.InBehandeling"/> is a no-op (the same or
|
||||||
/// submitted registration can be approved: re-approving is rejected as an invalid transition.
|
/// another behandelaar re-opens it); a decided registration can no longer be taken into behandeling.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Approve the registration — the behandelaar's decision to enter it in the register. Advances a
|
||||||
|
/// submitted or in-behandeling registration to <see cref="RegistrationStatus.Ingeschreven"/>.
|
||||||
|
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Approve()
|
public void Approve()
|
||||||
{
|
{
|
||||||
@@ -77,10 +95,27 @@ public sealed class Registration
|
|||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"Registration {Id} has no zaak yet; it cannot be approved before its zaak is opened.");
|
$"Registration {Id} has no zaak yet; it cannot be approved before its zaak is opened.");
|
||||||
|
|
||||||
if (Status != RegistrationStatus.Ingediend)
|
RequireOpenForDecision(nameof(Approve));
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"Registration {Id} is {Status}; only an INGEDIEND registration can be approved.");
|
|
||||||
|
|
||||||
Status = RegistrationStatus.Ingeschreven;
|
Status = RegistrationStatus.Ingeschreven;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reject the registration — the behandelaar's decision not to enter it in the register. Advances a
|
||||||
|
/// submitted or in-behandeling registration to <see cref="RegistrationStatus.Afgewezen"/>. 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.
|
||||||
|
/// </summary>
|
||||||
|
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}).");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
namespace Big.Domain;
|
namespace Big.Domain;
|
||||||
|
|
||||||
/// <summary>The lifecycle states a <see cref="Registration"/> moves through. The walking
|
/// <summary>The lifecycle states a <see cref="Registration"/> moves through. Submission starts in
|
||||||
/// skeleton knows <see cref="Ingediend"/> and the terminal <see cref="Ingeschreven"/>; withdrawal,
|
/// <see cref="Ingediend"/>; a behandelaar takes it <see cref="InBehandeling"/> and decides it into one
|
||||||
/// beoordeling and herregistratie states arrive in their own slices (Iteration 2+).</summary>
|
/// of the terminal states <see cref="Ingeschreven"/> (approved) or <see cref="Afgewezen"/> (rejected).
|
||||||
|
/// Withdrawal and herregistratie states arrive in their own slices (S-11+).</summary>
|
||||||
public enum RegistrationStatus
|
public enum RegistrationStatus
|
||||||
{
|
{
|
||||||
/// <summary>Submitted by the zorgprofessional; the registratie process has been started.</summary>
|
/// <summary>Submitted by the zorgprofessional; the registratie process has been started.</summary>
|
||||||
Ingediend,
|
Ingediend,
|
||||||
|
|
||||||
/// <summary>Approved: entered in the register. Terminal in the walking skeleton (S-09b).</summary>
|
/// <summary>Picked up by a behandelaar for beoordeling (S-12).</summary>
|
||||||
|
InBehandeling,
|
||||||
|
|
||||||
|
/// <summary>Approved: entered in the register. Terminal.</summary>
|
||||||
Ingeschreven,
|
Ingeschreven,
|
||||||
|
|
||||||
|
/// <summary>Rejected by the behandelaar. Terminal.</summary>
|
||||||
|
Afgewezen,
|
||||||
}
|
}
|
||||||
|
|||||||
142
services/domain/Big.Tests/BeoordeelRegistratieTests.cs
Normal file
142
services/domain/Big.Tests/BeoordeelRegistratieTests.cs
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
using Big.Application;
|
||||||
|
using Big.Domain;
|
||||||
|
|
||||||
|
namespace Big.Tests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The beoordeling use case (S-12): a behandelaar's decision on a registration. Goedkeuren sets the
|
||||||
|
/// zaak's final status via the ACL (§8.1) and marks the aggregate INGESCHREVEN; Afwijzen marks it
|
||||||
|
/// AFGEWEZEN in the domain (propagating a rejection to the zaak is a later sub-slice). Both are
|
||||||
|
/// idempotent so a repeated or redelivered decision is a no-op.
|
||||||
|
/// </summary>
|
||||||
|
public class BeoordeelRegistratieTests
|
||||||
|
{
|
||||||
|
private static Registration WithZaak(string bsn = "123456782")
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit(bsn);
|
||||||
|
registration.AttachZaak(FakeAclClient.DefaultZaakUrl);
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Goedkeuren_sets_the_zaak_status_via_the_acl_and_marks_the_registration_ingeschreven()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var registration = WithZaak();
|
||||||
|
store.Seed(registration);
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
await handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Goedkeuren));
|
||||||
|
|
||||||
|
var saved = await store.GetAsync(registration.Id);
|
||||||
|
Assert.Equal(RegistrationStatus.Ingeschreven, saved!.Status);
|
||||||
|
Assert.Equal(FakeAclClient.DefaultZaakUrl, acl.ApprovedZaakUrl);
|
||||||
|
Assert.Equal(1, acl.ApproveCallCount);
|
||||||
|
Assert.Equal(1, store.SaveCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Afwijzen_marks_the_registration_afgewezen_without_calling_the_acl()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var registration = WithZaak();
|
||||||
|
store.Seed(registration);
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
await handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Afwijzen));
|
||||||
|
|
||||||
|
var saved = await store.GetAsync(registration.Id);
|
||||||
|
Assert.Equal(RegistrationStatus.Afgewezen, saved!.Status);
|
||||||
|
Assert.Equal(0, acl.ApproveCallCount);
|
||||||
|
Assert.Equal(1, store.SaveCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Goedkeuren_an_in_behandeling_registration_marks_it_ingeschreven()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var registration = WithZaak();
|
||||||
|
registration.TakeIntoBehandeling();
|
||||||
|
store.Seed(registration);
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
await handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Goedkeuren));
|
||||||
|
|
||||||
|
Assert.Equal(RegistrationStatus.Ingeschreven, (await store.GetAsync(registration.Id))!.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Rejects_a_null_command_without_touching_the_store_or_acl()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<ArgumentNullException>(() => handler.HandleAsync(null!));
|
||||||
|
Assert.Equal(0, acl.ApproveCallCount);
|
||||||
|
Assert.Equal(0, store.SaveCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Deciding_an_unknown_registration_throws_and_does_not_call_the_acl()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||||
|
handler.HandleAsync(new BeoordeelRegistratieCommand(RegistrationId.New(), BeoordelingsBesluit.Goedkeuren)));
|
||||||
|
Assert.Contains("No registration", ex.Message);
|
||||||
|
Assert.Equal(0, acl.ApproveCallCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Goedkeuren_before_the_zaak_is_opened_throws_without_calling_the_acl()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var registration = Registration.Submit("123456782"); // no zaak yet
|
||||||
|
store.Seed(registration);
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||||
|
handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Goedkeuren)));
|
||||||
|
Assert.Contains("no zaak", ex.Message);
|
||||||
|
Assert.Equal(0, acl.ApproveCallCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Re_goedkeuren_an_already_ingeschreven_registration_is_idempotent()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var registration = WithZaak();
|
||||||
|
store.Seed(registration);
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
await handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Goedkeuren));
|
||||||
|
await handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Goedkeuren));
|
||||||
|
|
||||||
|
Assert.Equal(1, acl.ApproveCallCount);
|
||||||
|
Assert.Equal(RegistrationStatus.Ingeschreven, (await store.GetAsync(registration.Id))!.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Re_afwijzen_an_already_afgewezen_registration_is_idempotent()
|
||||||
|
{
|
||||||
|
var store = new FakeRegistrationStore();
|
||||||
|
var acl = new FakeAclClient();
|
||||||
|
var registration = WithZaak();
|
||||||
|
store.Seed(registration);
|
||||||
|
var handler = new BeoordeelRegistratie(store, acl);
|
||||||
|
|
||||||
|
await handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Afwijzen));
|
||||||
|
await handler.HandleAsync(new BeoordeelRegistratieCommand(registration.Id, BeoordelingsBesluit.Afwijzen));
|
||||||
|
|
||||||
|
Assert.Equal(1, store.SaveCount);
|
||||||
|
Assert.Equal(RegistrationStatus.Afgewezen, (await store.GetAsync(registration.Id))!.Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -121,4 +121,100 @@ public class RegistrationTests
|
|||||||
Assert.Contains("only an INGEDIEND", ex.Message);
|
Assert.Contains("only an INGEDIEND", ex.Message);
|
||||||
Assert.Equal(RegistrationStatus.Ingeschreven, registration.Status);
|
Assert.Equal(RegistrationStatus.Ingeschreven, registration.Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Taking_a_registration_into_behandeling_moves_it_to_in_behandeling()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
|
||||||
|
registration.TakeIntoBehandeling();
|
||||||
|
|
||||||
|
Assert.Equal(RegistrationStatus.InBehandeling, registration.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Re_taking_an_in_behandeling_registration_is_idempotent()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
registration.TakeIntoBehandeling();
|
||||||
|
|
||||||
|
registration.TakeIntoBehandeling();
|
||||||
|
|
||||||
|
Assert.Equal(RegistrationStatus.InBehandeling, registration.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Taking_a_decided_registration_into_behandeling_is_rejected()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
registration.AttachZaak(new Uri("http://openzaak/zaken/api/v1/zaken/abc"));
|
||||||
|
registration.Approve();
|
||||||
|
|
||||||
|
var ex = Assert.Throws<InvalidOperationException>(() => registration.TakeIntoBehandeling());
|
||||||
|
Assert.Contains("only an INGEDIEND", ex.Message);
|
||||||
|
Assert.Equal(RegistrationStatus.Ingeschreven, registration.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Approving_an_in_behandeling_registration_with_a_zaak_sets_it_ingeschreven()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
registration.AttachZaak(new Uri("http://openzaak/zaken/api/v1/zaken/abc"));
|
||||||
|
registration.TakeIntoBehandeling();
|
||||||
|
|
||||||
|
registration.Approve();
|
||||||
|
|
||||||
|
Assert.Equal(RegistrationStatus.Ingeschreven, registration.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Rejecting_a_registration_sets_it_afgewezen()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
|
||||||
|
registration.Reject();
|
||||||
|
|
||||||
|
Assert.Equal(RegistrationStatus.Afgewezen, registration.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Rejecting_needs_no_zaak()
|
||||||
|
{
|
||||||
|
// A registration can be turned down before its zaak is ever opened, so Reject must not require one.
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
|
||||||
|
registration.Reject();
|
||||||
|
|
||||||
|
Assert.Equal(RegistrationStatus.Afgewezen, registration.Status);
|
||||||
|
Assert.Null(registration.ZaakUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Rejecting_an_in_behandeling_registration_sets_it_afgewezen()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
registration.TakeIntoBehandeling();
|
||||||
|
|
||||||
|
registration.Reject();
|
||||||
|
|
||||||
|
Assert.Equal(RegistrationStatus.Afgewezen, registration.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Deciding_an_already_decided_registration_is_rejected()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
registration.Reject();
|
||||||
|
|
||||||
|
var approveEx = Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
{
|
||||||
|
registration.AttachZaak(new Uri("http://openzaak/zaken/api/v1/zaken/abc"));
|
||||||
|
registration.Approve();
|
||||||
|
});
|
||||||
|
Assert.Contains("IN_BEHANDELING", approveEx.Message);
|
||||||
|
|
||||||
|
var rejectEx = Assert.Throws<InvalidOperationException>(() => registration.Reject());
|
||||||
|
Assert.Contains("Afgewezen", rejectEx.Message);
|
||||||
|
Assert.Equal(RegistrationStatus.Afgewezen, registration.Status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
tests/acceptance/Features/EenRegistratieBeoordelen.feature
Normal file
24
tests/acceptance/Features/EenRegistratieBeoordelen.feature
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# language: en
|
||||||
|
# Drives S-12 (#13). A behandelaar picks up a submitted registration for beoordeling and decides it:
|
||||||
|
# goedkeuren enters it in the register (INGESCHREVEN, the zaak's final status set via the ACL, §8.1),
|
||||||
|
# afwijzen turns it down (AFGEWEZEN). This scenario exercises the use cases against in-memory
|
||||||
|
# stand-ins for the ACL and the store; real Flowable user-task claim/complete arrives in a later
|
||||||
|
# sub-slice and is verified live.
|
||||||
|
Feature: Een registratie beoordelen
|
||||||
|
Als behandelaar wil ik een ingediende registratie beoordelen
|
||||||
|
zodat deze wordt ingeschreven of afgewezen.
|
||||||
|
|
||||||
|
Scenario: Goedkeuren schrijft de registratie in via de ACL
|
||||||
|
Given a submitted registration with an opened zaak
|
||||||
|
When the behandelaar takes it into behandeling
|
||||||
|
Then the registration has status "INBEHANDELING"
|
||||||
|
When the behandelaar decides "goedkeuren"
|
||||||
|
Then the registration has status "INGESCHREVEN"
|
||||||
|
And the zaak's final status is set via the ACL
|
||||||
|
|
||||||
|
Scenario: Afwijzen wijst de registratie af zonder de ACL
|
||||||
|
Given a submitted registration with an opened zaak
|
||||||
|
When the behandelaar takes it into behandeling
|
||||||
|
And the behandelaar decides "afwijzen"
|
||||||
|
Then the registration has status "AFGEWEZEN"
|
||||||
|
And the ACL is not asked to set the zaak status
|
||||||
58
tests/acceptance/Steps/EenRegistratieBeoordelenSteps.cs
Normal file
58
tests/acceptance/Steps/EenRegistratieBeoordelenSteps.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using Acceptance.Support;
|
||||||
|
using Big.Application;
|
||||||
|
using Big.Domain;
|
||||||
|
using Reqnroll;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Acceptance.Steps;
|
||||||
|
|
||||||
|
/// <summary>Bindings for <c>EenRegistratieBeoordelen.feature</c> (S-12). Drives the TakeIntoBehandeling
|
||||||
|
/// transition and the BeoordeelRegistratie use case against in-memory ports; one instance per scenario.
|
||||||
|
/// Scoped to this feature so its "the registration has status" step does not clash with the identically
|
||||||
|
/// phrased (but differently-asserting) step in <see cref="RegistratieIndienenSteps"/>.</summary>
|
||||||
|
[Binding]
|
||||||
|
[Scope(Feature = "Een registratie beoordelen")]
|
||||||
|
public sealed class EenRegistratieBeoordelenSteps
|
||||||
|
{
|
||||||
|
private readonly InMemoryAclClient _acl = new();
|
||||||
|
private readonly InMemoryRegistrationStore _store = new();
|
||||||
|
private RegistrationId _id;
|
||||||
|
|
||||||
|
[Given("a submitted registration with an opened zaak")]
|
||||||
|
public async Task GivenASubmittedRegistrationWithAnOpenedZaak()
|
||||||
|
{
|
||||||
|
var registration = Registration.Submit("123456782");
|
||||||
|
registration.AttachZaak(InMemoryAclClient.OpenedZaakUrl);
|
||||||
|
await _store.SaveAsync(registration);
|
||||||
|
_id = registration.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
[When("the behandelaar takes it into behandeling")]
|
||||||
|
public async Task WhenTheBehandelaarTakesItIntoBehandeling()
|
||||||
|
{
|
||||||
|
var registration = await _store.GetAsync(_id);
|
||||||
|
registration!.TakeIntoBehandeling();
|
||||||
|
await _store.SaveAsync(registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[When("the behandelaar decides \"(.*)\"")]
|
||||||
|
public async Task WhenTheBehandelaarDecides(string besluit)
|
||||||
|
=> await new BeoordeelRegistratie(_store, _acl).HandleAsync(
|
||||||
|
new BeoordeelRegistratieCommand(_id, Enum.Parse<BeoordelingsBesluit>(besluit, ignoreCase: true)));
|
||||||
|
|
||||||
|
[Then("the registration has status \"(.*)\"")]
|
||||||
|
public async Task ThenTheRegistrationHasStatus(string expected)
|
||||||
|
{
|
||||||
|
var registration = await _store.GetAsync(_id);
|
||||||
|
Assert.NotNull(registration);
|
||||||
|
Assert.Equal(expected, registration.Status.ToString().ToUpperInvariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then("the zaak's final status is set via the ACL")]
|
||||||
|
public void ThenTheZaakFinalStatusIsSetViaTheAcl()
|
||||||
|
=> Assert.Equal(InMemoryAclClient.OpenedZaakUrl, _acl.ApprovedZaakUrl);
|
||||||
|
|
||||||
|
[Then("the ACL is not asked to set the zaak status")]
|
||||||
|
public void ThenTheAclIsNotAskedToSetTheZaakStatus()
|
||||||
|
=> Assert.Null(_acl.ApprovedZaakUrl);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user