The wire said Application, the domain said Aanvraag — one aggregate with two names at every hop. Rename the backend DTOs and the /applications route to /aanvragen, regenerate the typed client, and rename the frontend adapter/store to match. Renamed: ApplicationSummaryDto/DetailDto, CreateApplicationRequest, SubmitApplicationRequest/Response → Aanvraag* equivalents; ApplicationsAdapter/Store → AanvragenAdapter/Store; applications.adapter.ts/applications.store.ts → aanvragen.*. Left untouched: the admin Case/Zaak vocabulary (/admin/cases, AdminCasesStore) — a separate read model, not part of this rename; the internal BigRegister.Domain.Applications namespace and the Applications EF table (renaming those needs a new EF migration, out of scope here). Part of the dashboard-readability refactor (see the approved plan). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
89 lines
4.5 KiB
C#
89 lines
4.5 KiB
C#
using System.Net.Http.Json;
|
|
using BigRegister.Api.Contracts;
|
|
using BigRegister.Api.Data;
|
|
using BigRegister.Domain.Applications;
|
|
using BigRegister.Domain.Authorization;
|
|
using Microsoft.AspNetCore.Mvc.Testing;
|
|
using Microsoft.AspNetCore.TestHost;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace BigRegister.Tests;
|
|
|
|
/// <summary>Wraps <see cref="LocalZaakSource"/> but returns a DIFFERENT case id than the
|
|
/// underlying Aanvraag.Id — reproduces exactly what <c>OpenZaakZaakSource</c> does in
|
|
/// production (the FE-facing case id from <c>ListCases</c> is the ZGW zaak's own uuid, not
|
|
/// <c>ApplicationStore</c>'s primary key) without needing a live OpenZaak, so the besluit
|
|
/// endpoint's Referentie-based resolution (the fix below) gets coverage on every push.</summary>
|
|
file sealed class IdMismatchZaakSource : IZaakSource
|
|
{
|
|
private readonly LocalZaakSource inner = new();
|
|
private static AanvraagSummaryDto Rekey(AanvraagSummaryDto dto) => dto with { Id = $"zaak-{dto.Id}" };
|
|
|
|
public IReadOnlyList<AanvraagSummaryDto> ListCases(DateTimeOffset now) =>
|
|
inner.ListCases(now).Select(Rekey).ToList();
|
|
|
|
public IReadOnlyList<AanvraagSummaryDto> ListMyCases(ZorgverlenerCaller caller, DateTimeOffset now) =>
|
|
inner.ListMyCases(caller, now).Select(Rekey).ToList();
|
|
|
|
public (string Referentie, AanvraagStatusDto Status, string? ZaakUrl) CreateZaak(
|
|
Aanvraag.Submitted aanvraag, DateTimeOffset now, CallerIdentity caller) => inner.CreateZaak(aanvraag, now, caller);
|
|
|
|
public void RecordBesluit(Aanvraag aanvraag, Besluit besluit, string? toelichting, DateTimeOffset now, CallerIdentity caller) =>
|
|
inner.RecordBesluit(aanvraag, besluit, toelichting, now, caller);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Regression for a real, live-repro'd bug: recording a besluit from the behandelportal always
|
|
/// 404'd against a real OpenZaak. Root cause — <c>POST /beoordeling/{id}/besluit</c> looked
|
|
/// <c>id</c> up directly in <c>ApplicationStore</c> (its own primary key), but <c>id</c> is
|
|
/// whatever <c>IZaakSource.ListCases</c> handed the FE; under <c>OpenZaakZaakSource</c> that's
|
|
/// the ZGW zaak's own uuid, a different value entirely. Fixed by resolving the case through
|
|
/// the same <c>ListCases</c> seak the GET sibling (<see cref="BeoordelingTests"/>) already uses,
|
|
/// then to the local <c>Aanvraag</c> via its Referentie (<c>ApplicationStore.GetByReferentie</c>)
|
|
/// — the one identifier stable across both sources. <see cref="IdMismatchZaakSource"/>
|
|
/// reproduces the id divergence without a live OpenZaak.
|
|
/// </summary>
|
|
public class BeoordelingIdMismatchTests
|
|
{
|
|
private static WebApplicationFactory<Program> Factory()
|
|
{
|
|
var dbPath = Path.Combine(Path.GetTempPath(), $"bigregister-id-mismatch-{Guid.NewGuid():N}.db");
|
|
return new WebApplicationFactory<Program>().WithWebHostBuilder(builder => builder
|
|
.UseSetting("ConnectionStrings:AppDb", $"Data Source={dbPath}")
|
|
.ConfigureTestServices(services => services.AddSingleton<IZaakSource, IdMismatchZaakSource>()));
|
|
}
|
|
|
|
private static HttpRequestMessage Behandelaar(HttpMethod method, string path, object? body = null)
|
|
{
|
|
var req = new HttpRequestMessage(method, path);
|
|
req.Headers.Add("X-Medewerker", "medewerker-1");
|
|
if (body is not null) req.Content = JsonContent.Create(body);
|
|
return req;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Besluit_resolves_by_referentie_when_the_case_id_differs_from_the_local_aanvraag_id()
|
|
{
|
|
using var factory = Factory();
|
|
using var client = factory.CreateClient();
|
|
|
|
var created = await client.PostAsJsonAsync("/api/v1/aanvragen", new { type = "registratie" });
|
|
var app = (await created.Content.ReadFromJsonAsync<AanvraagDetailDto>())!;
|
|
var submit = await client.PostAsJsonAsync($"/api/v1/aanvragen/{app.Id}/submit", new { diplomaHerkomst = "handmatig" });
|
|
submit.EnsureSuccessStatusCode();
|
|
|
|
var werkvoorraad = await client.SendAsync(Behandelaar(HttpMethod.Get, "/api/v1/werkvoorraad"));
|
|
var items = (await werkvoorraad.Content.ReadFromJsonAsync<List<AanvraagSummaryDto>>())!;
|
|
var caseId = Assert.Single(items).Id;
|
|
// Sanity: the id divergence this test exists for is real, not accidentally absent.
|
|
Assert.NotEqual(app.Id, caseId);
|
|
|
|
var res = await client.SendAsync(Behandelaar(HttpMethod.Post, $"/api/v1/beoordeling/{caseId}/besluit",
|
|
new { besluit = "Afwijzen", toelichting = "onvolledig" }));
|
|
|
|
res.EnsureSuccessStatusCode();
|
|
var body = (await res.Content.ReadFromJsonAsync<RecordBesluitResponse>())!;
|
|
Assert.Equal("Afgewezen", body.Status.Tag);
|
|
}
|
|
}
|