feat(#78): one citizen reference across self-service and the openbaar register #79

Merged
not merged 6 commits from feat/78-reference-correlation into main 2026-07-14 14:01:51 +00:00
7 changed files with 23 additions and 10 deletions
Showing only changes of commit 7b841d6e62 - Show all commits

View File

@@ -28,7 +28,7 @@ public sealed class OpenZaakWorker(IRegistrationStore store, IAclClient acl)
if (registration.ZaakUrl is not null)
return registration.ZaakUrl;
var zaakUrl = await acl.OpenZaakAsync(registration.Bsn, ct);
var zaakUrl = await acl.OpenZaakAsync(registration.Bsn, registration.Id.ToString(), ct);
registration.AttachZaak(zaakUrl);
await store.SaveAsync(registration, ct);
return zaakUrl;

View File

@@ -24,7 +24,10 @@ public interface IWorkflowClient
/// </summary>
public interface IAclClient
{
Task<Uri> OpenZaakAsync(string bsn, CancellationToken ct = default);
/// <summary>Open a zaak for the registration. <paramref name="reference"/> is the registration's
/// own reference (its id); the ACL records it as the zaak's identificatie so the openbaar register
/// can show the same reference the zorgprofessional was given (S-09b follow-up, adr-proposal #78).</summary>
Task<Uri> OpenZaakAsync(string bsn, string reference, CancellationToken ct = default);
/// <summary>
/// Record the approval on the given zaak. The ACL translates this to the ZGW concept — setting

View File

@@ -11,10 +11,10 @@ namespace Big.Infrastructure;
/// </summary>
public sealed class AclHttpClient(HttpClient http, AclOptions options) : IAclClient
{
public async Task<Uri> OpenZaakAsync(string bsn, CancellationToken ct = default)
public async Task<Uri> OpenZaakAsync(string bsn, string reference, CancellationToken ct = default)
{
using var response = await http.PostAsJsonAsync(
new Uri(options.BaseUrl, "zaken"), new OpenZaakRequest(bsn), ct);
new Uri(options.BaseUrl, "zaken"), new OpenZaakRequest(bsn, reference), ct);
response.EnsureSuccessStatusCode();
var opened = await response.Content.ReadFromJsonAsync<OpenZaakResponse>(ct)
@@ -31,7 +31,9 @@ public sealed class AclHttpClient(HttpClient http, AclOptions options) : IAclCli
response.EnsureSuccessStatusCode();
}
private sealed record OpenZaakRequest([property: JsonPropertyName("bsn")] string Bsn);
private sealed record OpenZaakRequest(
[property: JsonPropertyName("bsn")] string Bsn,
[property: JsonPropertyName("reference")] string Reference);
private sealed record OpenZaakResponse([property: JsonPropertyName("zaakUrl")] string ZaakUrl);

View File

@@ -15,12 +15,13 @@ public class AclHttpClientTests
var client = Client(capture.Responds(HttpStatusCode.OK,
"""{"zaakUrl":"http://openzaak/zaken/api/v1/zaken/abc"}"""));
var url = await client.OpenZaakAsync("123456782");
var url = await client.OpenZaakAsync("123456782", "reg-42");
Assert.Equal("http://openzaak/zaken/api/v1/zaken/abc", url.ToString());
Assert.Equal(HttpMethod.Post, capture.Seen!.Method);
Assert.Equal("http://acl/zaken", capture.Seen.RequestUri!.ToString());
Assert.Contains("\"bsn\":\"123456782\"", capture.Body);
Assert.Contains("\"reference\":\"reg-42\"", capture.Body);
}
[Fact]
@@ -29,7 +30,7 @@ public class AclHttpClientTests
var capture = new RequestCapture();
var client = Client(capture.Responds(HttpStatusCode.BadGateway));
await Assert.ThrowsAsync<HttpRequestException>(() => client.OpenZaakAsync("123456782"));
await Assert.ThrowsAsync<HttpRequestException>(() => client.OpenZaakAsync("123456782", "reg-1"));
}
[Fact]
@@ -38,7 +39,7 @@ public class AclHttpClientTests
var capture = new RequestCapture();
var client = Client(capture.Responds(HttpStatusCode.OK, "null"));
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => client.OpenZaakAsync("123456782"));
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => client.OpenZaakAsync("123456782", "reg-1"));
Assert.Contains("empty", ex.Message, StringComparison.OrdinalIgnoreCase);
}

View File

@@ -50,15 +50,17 @@ internal sealed class FakeAclClient(Uri? zaakUrl = null) : IAclClient
private readonly Uri _zaakUrl = zaakUrl ?? DefaultZaakUrl;
public string? OpenedForBsn { get; private set; }
public string? OpenedWithReference { get; private set; }
public int CallCount { get; private set; }
public Uri? ApprovedZaakUrl { get; private set; }
public int ApproveCallCount { get; private set; }
public Task<Uri> OpenZaakAsync(string bsn, CancellationToken ct = default)
public Task<Uri> OpenZaakAsync(string bsn, string reference, CancellationToken ct = default)
{
CallCount++;
OpenedForBsn = bsn;
OpenedWithReference = reference;
return Task.FromResult(_zaakUrl);
}

View File

@@ -25,6 +25,9 @@ public class OpenZaakWorkerTests
Assert.Equal(FakeAclClient.DefaultZaakUrl, zaakUrl);
Assert.Equal("123456782", acl.OpenedForBsn);
// The registration's own id is handed to the ACL as the zaak reference (identificatie),
// so the openbaar register can show the reference the zorgprofessional received (#78).
Assert.Equal(registration.Id.ToString(), acl.OpenedWithReference);
var saved = await store.GetAsync(registration.Id);
Assert.Equal(FakeAclClient.DefaultZaakUrl, saved!.ZaakUrl);
Assert.Equal(1, store.SaveCount);

View File

@@ -26,11 +26,13 @@ public sealed class InMemoryAclClient : IAclClient
public static readonly Uri OpenedZaakUrl = new("http://openzaak/zaken/api/v1/zaken/acc-zaak");
public string? OpenedForBsn { get; private set; }
public string? OpenedWithReference { get; private set; }
public Uri? ApprovedZaakUrl { get; private set; }
public Task<Uri> OpenZaakAsync(string bsn, CancellationToken ct = default)
public Task<Uri> OpenZaakAsync(string bsn, string reference, CancellationToken ct = default)
{
OpenedForBsn = bsn;
OpenedWithReference = reference;
return Task.FromResult(OpenedZaakUrl);
}