SPRDT-1011: migrate listing courtscheduler calls to reshaped Phase-1 contract#13
Open
ozturkmenb wants to merge 13 commits into
Open
SPRDT-1011: migrate listing courtscheduler calls to reshaped Phase-1 contract#13ozturkmenb wants to merge 13 commits into
ozturkmenb wants to merge 13 commits into
Conversation
Update listing's courtscheduler client to the Phase-1 reshaped API:
- search-by-id: GET /courtschedule/search.court-schedules-by-id -> GET
/sessions; query param courtScheduleIds -> ids
- release slots: DELETE /hearingslots/{id} -> DELETE /sessions/{id};
action remove.hearing.slots -> release.sessions
- list hearings: PUT /list/hearingslots -> POST /hearings; action
list.hearings-in-court-sessions -> list.hearings-in-sessions
- extend multiday: POST /extendmultidayhearing/hearingslots -> PATCH
/hearings/{hearingId} (new HttpPatch helper)
- search-and-book (mags/crown/crown-fallback): GET query endpoints ->
POST /hearings/{hearingId} with typed JSON body, actions
mags.search.and.book / crown.search.and.book
Response parsing: mags searchAndBook now reads sessions[0] (was a
hearingSlots object); multiday reads sessions[] (was courtSchedules[]).
Crown-fallback parser unchanged - matched by the courtscheduler
single-day flat-field change. Other responses serialise identical
domain objects, so their parsing is unchanged.
- CourtSchedulerServiceStub (WireMock): retarget every stub to the new
endpoints/actions — GET /sessions, DELETE /sessions/{id}
(release.sessions), POST /hearings (list.hearings-in-sessions),
PATCH /hearings/{id} (extend.multiday.hearing), POST /hearings/{id}
(mags/crown.search.and.book). Multiday vs crown-fallback share the
crown.search.and.book endpoint and are disambiguated by a
durationInMinutes body matcher (>360 vs <=360). Response bodies
reshaped: mags now {hearingId,sessions[]}, multiday courtSchedules->
sessions, crown-fallback flat fields + empty sessions[].
- HearingSlotsServiceTest: expect new URLs/methods/headers; DELETE now
202 ACCEPTED; HttpPatch for extend; POST bodies for search-and-book.
- CourtScheduleEnrichmentServiceTest + 3 search-book fixtures: new
sessions[] response shape for mags/multiday.
- HearingSlotsService: guard extendMultiDayHearing against empty payload
(was NPE on getString(hearingId) before the validation guard).
Both changed modules green (listing-common 165, listing-command-api 295).
The list.hearings-in-sessions REQUEST body is {"hearingSlots":[...]} (only
the RESPONSE uses "hearings"). The stub retarget mistakenly changed the
WireMock request-body matcher to containing("hearings"), which is not a
substring of "hearingSlots", so the real stub stopped matching and the
empty catch-all responded {"hearings":[]}. Enrichment then threw
IllegalStateException(Missing courtScheduleIds) -> 500 on every
list-court-hearing, cascading to 103 IT failures via the shared
whenCaseIsSubmittedForListing setup step. Restore the matcher to
containing("hearingSlots").
…r-call migration S1192: add SESSION_START_TIME constant in CourtScheduleEnrichmentService (4 literal uses). S3776: reduce postSearchBook cognitive complexity by extracting buildTypedJsonBody helper. Duplication: unify post/patch/postSearchBook execute+response logic via executeAndBuildResponse. Coverage: add unit tests for patch success/error/IOException, postSearchBook typed body (durationInMinutes as number, isPolice as boolean, hearingId in path, crown content-type), buildTypedJsonBody edge cases, and searchAndBookSlots paths (empty sessions, non-OK, draft/isDraft fallback, judiciaries present/absent).
Two request-body shape bugs surfaced against the real courtscheduler on
ns-ste-ccm-22 (both masked by loosely-matching WireMock IT stubs):
1. list.hearings-in-sessions sent hearingSlots[].ids instead of
courtScheduleIds - the COURT_SCHEDULE_IDS constant was repurposed to
"ids" for the GET /sessions query param but also built the list body
key. Split into COURT_SCHEDULE_IDS ("courtScheduleIds", body key) and
IDS_PARAM ("ids", query param).
2. multiDaySearchAndBook omitted courtCentreId + hearingDate, which
crown.search.and.book requires (additionalProperties:false). Supply
them from the hearing context at both call sites; the engine ignores
them for the anchored path but schema validation requires them present.
Harden CourtSchedulerServiceStub to match on the required nested keys
(courtScheduleId for list; courtCentreId + hearingDate for multiday crown)
so a missing-required-key regression fails the ITs instead of silently
passing. Add unit tests for both body shapes.
…ale draft id on update mergeCourtScheduleIdsFromNonDefaultDays previously skipped hearingDays that already carried a courtScheduleId, so on a reschedule the old draft id was left in place. The downstream fetch then returned the draft session, isDraft=true propagated to the aggregate, canAllocateForCrown() was closed, and hearing-rescheduled was emitted with allocated:false. Fix: remove the early-return guard and allow the nonDefaultDays id to overwrite the stale draft id when they differ. The new (non-draft) id is then fetched, isDraft=false is propagated, canAllocateForCrown() opens, and hearing-allocated-for-listing-v2 + hearing-rescheduled(allocated:true) are both emitted correctly. CROWN-only path (mergeCourtScheduleIdsFromNonDefaultDays is only called from enrichCrownUpdateHearing); MAGS behaviour unchanged.
…day window The J05 fix commit (205 new lines) shrank SonarQube's NUMBER_OF_DAYS=1 new-code denominator, flipping new_maintainability_rating to D by surfacing pre-existing smells inside the new-code period. Clear all 20 counted smells; every change is behaviour-preserving: CourtScheduleEnrichmentService (production): - S3358: extract nested ternaries into locals (startTime fallback, anchor centre id, anchor hearing date, isDraft resolution via if/else) - S6201: use instanceof pattern variables for JsonObject casts - S1125: simplify the CROWN isPolice boolean expression Tests (CourtScheduleEnrichmentServiceTest, ListingCommandApiTest, HearingAggregateTest): - S5786: drop redundant public on JUnit5 test methods - S6204: Stream.toList() instead of collect(Collectors.toList()) - S1117: rename locals that shadowed fields - S1128: remove unused import Unit tests green: CourtScheduleEnrichmentServiceTest 140, ListingCommandApiTest 33, HearingAggregateTest 173, 0 failures.
… (J05) Adds CrownUpdateHearingSingleDayIT: a CROWN, originally-unallocated single-day hearing updated via update-hearing-for-listing with a non-draft courtScheduleId on nonDefaultDays must end ALLOCATED (polls listing.search.hearing for $.allocated==true and the new $.startDate). Locks the end-to-end single-day CROWN allocation outcome (the J05 scenario) at the integration layer. The update-hearing-for-listing schema is additionalProperties:false and does not expose hearingDays, so the exact stale-draft-id merge collision remains covered by the unit/aggregate tests (CourtScheduleEnrichmentServiceTest, HearingAggregateTest); this IT locks the e2e outcome. Stubs: stubSearchCourtSchedulesByIdSession(isDraft=false) + stubListHearingInCourtSessionsForCourtSchedule; dates via ItClock.plusWorkingDays. Passes in the full listing IT suite (Tests run: 1, 0 failures).
…troom from resolved final schedule update-hearing-for-listing with only a courtScheduleId on nonDefaultDays (no room fields) booked the session but never allocated: the handler resolved a null command-level courtroom, called removeCourtRoom, and canAllocateForCrown() stayed closed. Allocation only worked when the caller (UI) also supplied the room. Fix: inverse of stripRoomInfoIfAnyDraft (ADR-005) — when the command carries no courtroom and every enriched hearingDay resolved to a FINAL (isDraft=false) session in one distinct room, promote that room to the command level (and backfill a roomless selectedCourtCentre, which the handler prefers for CROWN). Draft sessions are roomless on every courtscheduler query path so they can never qualify; payload-supplied rooms are never overridden; multi-day spans across different rooms stay underived. Locked failing-first at both levels: CourtScheduleEnrichmentServiceTest (3 new derivation tests red->green + draft/parity/mixed-room pins, 146/146) and CrownUpdateHearingScheduleOnlyIT (schedule-only allocate + ADR-005 draft mirror, red 90s-timeout on allocated=false -> green 2/2).
…t be resolved When the CROWN update enrichment could not resolve or book the requested sessions (multi-day search or single-day fetch returning empty), it logged a WARN and returned the seeded hearingDays unchanged — carrying an unverified courtScheduleId and a payload room. The aggregate then allocated the hearing while courtscheduler's bookings were untouched, diverging the two services (observed live on ns-ste-ccm-34: multi-day allocate collapsed to a 1-day allocated hearing while all three draft bookings remained). Fix: markDaysDraftWhenSessionsUnresolved — on either empty-result path the enriched days are marked isDraft=true, so canAllocateForCrown() stays closed, stripRoomInfoIfAnyDraft (ADR-005) clears day rooms downstream, and the courtScheduleIds are preserved for traceability. Two failing-first unit tests lock the behaviour; the two tests pinning the old return-unchanged contract were retargeted. Full listing IT suite green (239 tests).
…k ignores the requested start date A crown.search.and.book response whose block starts on a different date than the command requested is no longer silently adopted: the days are re-marked draft (same fail-safe as unresolved sessions) so the hearing window cannot diverge from the caller's intent.
Author
…s block total + anchor - validate CROWN update payload shape (CrownNonDefaultDaysValidator, 400 on violation): at most one virtual=true nonDefaultDay; startDate must equal the virtual day's date; genuine (non-virtual) days must fall within startDate..endDate - multi-day booking uses the virtual day's duration as the block TOTAL and its courtScheduleId/date as the anchor sent to courtscheduler, instead of summing every day (a mixed proxy+genuine payload double-counted, e.g. 1440+360=1800, and over-booked a 5th session past the requested endDate) - after session extraction, hearingDays whose date matches a genuine nonDefaultDay take that day's startTime (list-response times previously always won)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

SPRDT-1011 — migrate listing's courtscheduler calls to the reshaped Phase-1 contract
Updates
cpp-context-listing's courtscheduler client to the resource-based contract from the courtscheduler Phase-1 reshape (SPRDT-1089). In-place migration — no additive endpoints.Calls migrated
GET /courtschedule/search.court-schedules-by-id, paramcourtScheduleIdsGET /sessions, paramidsDELETE /hearingslots/{id}·remove.hearing.slotsDELETE /sessions/{id}·release.sessionsPUT /list/hearingslots·list.hearings-in-court-sessionsPOST /hearings·list.hearings-in-sessionsPOST /extendmultidayhearing/hearingslotsPATCH /hearings/{id}GETquery endpointsPOST /hearings/{id}with JSON body ·mags.search.and.book/crown.search.and.bookUnchanged (not in Phase-1 scope):
get.hearing.slots,get.hearing.ids,validate-session-availability,provisionalBooking.Response handling
searchBookSlots(mags) now readssessions[0](was ahearingSlots{}object).multiDaySearchAndBookreadssessions[](wascourtSchedules[]).Dependency
Requires the courtscheduler Phase-1 change that makes single-day
crown.search.and.bookcarry the booked session detail (room/time/draft/overbooked) flat on the response — ondev/SPRDT-1089-phase1-engine(courtscheduler PR #845). The integrated environment needs both this PR and that change deployed together.Verification
mvn clean install— full reactor green (26 modules)../runIntegrationTests.sh— 236 passed, 0 failed, 3 skipped.Notes
extendMultiDayHearingreturned a 500 (NPE) on an empty payload instead of aDataValidationException.