feat(workflow): diploma-eligibility DMN routes foreign diplomas via CBGV-advies (S-13, closes #14) #101

Open
not wants to merge 5 commits from feat/14-dmn-diploma-eligibility into main
3 changed files with 98 additions and 0 deletions
Showing only changes of commit 5e1975ae84 - Show all commits

View File

@@ -158,6 +158,49 @@ done
[ -n "$gone" ] || { echo "FAIL — Beoordelen task for $reg_id2 still active after withdrawal" >&2; docker logs "$dom" 2>&1 | tail -15 >&2; exit 1; } [ -n "$gone" ] || { echo "FAIL — Beoordelen task for $reg_id2 still active after withdrawal" >&2; docker logs "$dom" 2>&1 | tail -15 >&2; exit 1; }
echo "OK — withdrawal cancelled the Beoordelen task; the registratie process ended (ingetrokken)" echo "OK — withdrawal cancelled the Beoordelen task; the registratie process ended (ingetrokken)"
# ── S-13: diploma-eligibility routing. A registration with a FOREIGN diploma must route through the
# extra CBGVAdvies user task before Beoordelen (the DMN businessRuleTask sets route=CBGV_ADVIES and the
# gateway branches, ADR-0016). The domestic DIRECT path is already proven by the first registration
# above, which parked straight at Beoordelen. ──────────────────────────────────────────────────────
cbgv_query='{"processDefinitionKey":"registratie","taskDefinitionKey":"CBGVAdvies","includeProcessVariables":true}'
echo ">> submitting a registration with a foreign diploma"
locf="$(docker run --rm --network "$net" curlimages/curl:latest \
-fsS -D - -o /dev/null -X POST "http://$dom_ip:8080/registrations" \
-H 'Content-Type: application/json' -d '{"bsn":"123456782","diplomaOrigin":"Buitenlands"}' \
| sed -n 's/\r$//; s/^[Ll]ocation: //p' | head -1)"
[ -n "$locf" ] || { echo "FAIL — foreign POST /registrations returned no Location" >&2; exit 1; }
reg_idf="${locf##*/}"
echo ">> foreign registration $reg_idf"
echo ">> polling Flowable for its CBGV-advies task (foreign diplomas route here first)"
cbgv_task=""
for _ in $(seq 1 30); do
resp="$(flcurl -X POST "$fl_base/query/tasks" -H 'Content-Type: application/json' -d "$cbgv_query" 2>/dev/null || true)"
cbgv_task="$(printf '%s' "$resp" | task_for_reg "$reg_idf")"
[ -n "$cbgv_task" ] && break
sleep 2
done
[ -n "$cbgv_task" ] || { echo "FAIL — no CBGVAdvies task appeared for the foreign registration $reg_idf" >&2; docker logs "$dom" 2>&1 | tail -15 >&2; exit 1; }
echo ">> CBGVAdvies task $cbgv_task is waiting"
echo ">> asserting it has NOT reached Beoordelen yet (still awaiting CBGV-advies)"
resp="$(flcurl -X POST "$fl_base/query/tasks" -H 'Content-Type: application/json' -d "$query")"
early="$(printf '%s' "$resp" | task_for_reg "$reg_idf")"
[ -z "$early" ] || { echo "FAIL — foreign registration reached Beoordelen ($early) before CBGV-advies" >&2; exit 1; }
echo ">> completing the CBGV-advies task"
flcurl -X POST "$fl_base/runtime/tasks/$cbgv_task" -H 'Content-Type: application/json' -d '{"action":"complete"}' >/dev/null
echo ">> asserting it now advances to Beoordelen"
onward=""
for _ in $(seq 1 15); do
resp="$(flcurl -X POST "$fl_base/query/tasks" -H 'Content-Type: application/json' -d "$query" 2>/dev/null || true)"
[ -n "$(printf '%s' "$resp" | task_for_reg "$reg_idf")" ] && { onward=1; break; }
sleep 2
done
[ -n "$onward" ] || { echo "FAIL — foreign registration did not reach Beoordelen after CBGV-advies" >&2; exit 1; }
echo "OK — foreign diploma routed through CBGV-advies, then on to Beoordelen (DMN + gateway)"
# ── S-14: escalation. A third registration parks at Beoordelen. We fire its 14-day boundary timer # ── S-14: escalation. A third registration parks at Beoordelen. We fire its 14-day boundary timer
# early via Flowable's management API (the timer job is moved to executable and run), which routes a # early via Flowable's management API (the timer job is moved to executable and run), which routes a
# parallel token to the BeoordelingEscaleren external task. The domain's escalation worker acquires # parallel token to the BeoordelingEscaleren external task. The domain's escalation worker acquires

View File

@@ -0,0 +1,19 @@
# language: en
# Drives S-13 (#14). A registration's diploma origin decides its route: a domestic (Binnenlands)
# diploma goes straight to beoordeling, a foreign (Buitenlands) one is routed through an extra
# CBGV-advies step (PRD flow 4). The decision itself is a DMN evaluated inside the workflow
# (ADR-0016); the domain's part — verified here — is carrying the origin into the process so the DMN
# can route on it. The DMN evaluation and the CBGV routing are verified live (verify-domain).
Feature: Een diploma op herkomst routeren
Als register wil ik een aanvraag met een buitenlands diploma extra laten toetsen
zodat een CBGV-advies wordt ingewonnen voordat een behandelaar beoordeelt.
Scenario: Een binnenlands diploma start de registratie als binnenlands
Given a zorgprofessional with a "Binnenlands" diploma
When they submit their registration
Then the registratie process is started carrying a "Binnenlands" diploma
Scenario: Een buitenlands diploma start de registratie als buitenlands
Given a zorgprofessional with a "Buitenlands" diploma
When they submit their registration
Then the registratie process is started carrying a "Buitenlands" diploma

View File

@@ -0,0 +1,36 @@
using Acceptance.Support;
using Big.Application;
using Big.Domain;
using Reqnroll;
using Xunit;
namespace Acceptance.Steps;
/// <summary>Bindings for <c>EenDiplomaRouteren.feature</c> (S-13). Drives the submit use case against
/// in-memory ports and asserts the registratie process is started carrying the diploma origin — the
/// domain's contribution to flow 4. The DMN evaluation and the foreign→CBGV-advies routing it drives
/// are verified live (verify-domain); one instance per scenario.</summary>
[Binding]
[Scope(Feature = "Een diploma op herkomst routeren")]
public sealed class EenDiplomaRouterenSteps
{
private readonly InMemoryRegistrationStore _store = new();
private readonly InMemoryWorkflowClient _workflow = new();
private DiplomaOrigin _origin;
[Given("a zorgprofessional with a \"(.*)\" diploma")]
public void GivenAZorgprofessionalWithADiploma(string origin)
=> _origin = Enum.Parse<DiplomaOrigin>(origin, ignoreCase: true);
[When("they submit their registration")]
public async Task WhenTheySubmitTheirRegistration()
=> await new SubmitRegistration(_store, _workflow).HandleAsync(
new SubmitRegistrationCommand("123456782", _origin));
[Then("the registratie process is started carrying a \"(.*)\" diploma")]
public void ThenTheProcessIsStartedCarryingTheDiploma(string expected)
{
Assert.NotNull(_workflow.StartedFor);
Assert.Equal(Enum.Parse<DiplomaOrigin>(expected, ignoreCase: true), _workflow.StartedWithOrigin);
}
}