From 3f9b13cd4ae610f04474d95411df4ebe65975204 Mon Sep 17 00:00:00 2001 From: Ragubalan Durairaj Date: Thu, 21 May 2026 11:12:25 +0100 Subject: [PATCH 1/3] SPRDT-874: Adjournment CROWN journey updates --- ...nscheduledCourtHearingListTransformer.java | 18 +++-- ...eduledCourtHearingListTransformerTest.java | 58 +++++++++++++++ ...gToHearingListingNeedsTransformerTest.java | 72 +++++++++++++++++++ 3 files changed, 142 insertions(+), 6 deletions(-) diff --git a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformer.java b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformer.java index 8c50a85094..889b33e019 100644 --- a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformer.java +++ b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformer.java @@ -101,8 +101,10 @@ private Optional transformCourtApplication(final // judicialResult.nextHearing.estimatedMinutes — not on the parent Hearing. final Integer estimatedMinutes = judicialResultWithNextHearing.get().getNextHearing().getEstimatedMinutes(); + final UUID bookingReference = judicialResultWithNextHearing.get().getNextHearing().getBookingReference(); + final HearingUnscheduledListingNeeds hearingListingNeeds = createHearingListingNeeds(hearing, typeOfList, jurisdictionType, hearing.getProsecutionCases(), - Arrays.asList(createCourtApplication(courtApplication, judicialResultWithNextHearing.get())), hearingType, courtCentre, estimatedMinutes); + Arrays.asList(createCourtApplication(courtApplication, judicialResultWithNextHearing.get())), hearingType, courtCentre, estimatedMinutes, bookingReference); LOGGER.info("Unscheduled listing (nextHearing) New HearingId: {} created with typeOfList {} , jurisdictionType {} ," + "hearingType {} , courtCentre {} from court application {} in HearingId: {}.", @@ -124,7 +126,7 @@ private Optional transformCourtApplication(final // No next hearing → no duration to forward; null lets the listing-side fallback into action // (HearingDurationDefaults) substitute a sane default. final HearingUnscheduledListingNeeds hearingListingNeeds = createHearingListingNeeds(hearing, typeOfList, jurisdictionType, hearing.getProsecutionCases(), - Arrays.asList(createCourtApplication(courtApplication, judicialResultWithUnscheduledFlag.get())), hearingType, hearing.getCourtCentre(), null); + Arrays.asList(createCourtApplication(courtApplication, judicialResultWithUnscheduledFlag.get())), hearingType, hearing.getCourtCentre(), null, null); LOGGER.info("Unscheduled listing (result) New HearingId: {} created with typeOfList {} , jurisdictionType {} ," + "hearingType {} , courtCentre {} from court application {} in HearingId: {}.", @@ -210,7 +212,7 @@ private Optional mergeListingNeedsWithSameTypeOf if (unscheduledListingNeeds.isPresent()) { return Optional.of(createHearingListingNeeds(originalHearing, unscheduledListingNeeds.get().getTypeOfList(), unscheduledListingNeeds.get().getJurisdictionType(), Arrays.asList(pc), null, unscheduledListingNeeds.get().getType(), unscheduledListingNeeds.get().getCourtCentre(), - unscheduledListingNeeds.get().getEstimatedMinutes())); + unscheduledListingNeeds.get().getEstimatedMinutes(), unscheduledListingNeeds.get().getBookingReference())); } return Optional.empty(); } @@ -232,8 +234,10 @@ private Optional transformDefendantOffence(final // judicialResult.nextHearing.estimatedMinutes — not on the parent Hearing. final Integer estimatedMinutes = judicialResultWithNextHearing.get().getNextHearing().getEstimatedMinutes(); + final UUID bookingReference = judicialResultWithNextHearing.get().getNextHearing().getBookingReference(); + final HearingUnscheduledListingNeeds hearingUnscheduledListingNeeds = createHearingListingNeeds(originalHearing, typeOfList, jurisdictionType, - Arrays.asList(pc), null, hearingType, courtCentre, estimatedMinutes); + Arrays.asList(pc), null, hearingType, courtCentre, estimatedMinutes, bookingReference); LOGGER.info("Unscheduled listing (nextHearing) New HearingId: {} created with typeOfList {} , jurisdictionType {} ," + "hearingType {} , courtCentre {} from court application {} in HearingId: {}.", @@ -253,7 +257,7 @@ private Optional transformDefendantOffence(final final HearingType hearingType = HearingType.hearingType().withId(HEARING_TYPE_HRG_ID).withDescription(HEARING_TYPE_HRG_DESC).build(); final HearingUnscheduledListingNeeds hearingUnscheduledListingNeeds = createHearingListingNeeds(originalHearing, typeOfList, jurisdictionType, - Arrays.asList(pc), null, hearingType, originalHearing.getCourtCentre(), null); + Arrays.asList(pc), null, hearingType, originalHearing.getCourtCentre(), null, null); LOGGER.info("Unscheduled listing (result) New HearingId: {} created with typeOfList {} , jurisdictionType {} ," + "hearingType {} , courtCentre {} from court application {} in HearingId: {}.", @@ -338,7 +342,8 @@ private HearingUnscheduledListingNeeds createHearingListingNeeds(final Hearing h final JurisdictionType jurisdictionType, final List prosecutionCases, final List courtApplications, final HearingType hearingType, final CourtCentre courtCentre, - final Integer estimatedMinutes) { + final Integer estimatedMinutes, + final UUID bookingReference) { // SPRDT-831: forward the user-typed estimatedMinutes Integer sourced from // judicialResult.nextHearing.estimatedMinutes. Mirrors the allocated-listings pattern in @@ -348,6 +353,7 @@ private HearingUnscheduledListingNeeds createHearingListingNeeds(final Hearing h // the SPRDT-806/807 "never 0 / never null" guarantee. return HearingUnscheduledListingNeeds.hearingUnscheduledListingNeeds() .withId(UUID.randomUUID()) + .withBookingReference(bookingReference) .withTypeOfList(typeOfList) .withReportingRestrictionReason(hearing.getReportingRestrictionReason()) .withProsecutionCases(prosecutionCases) diff --git a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformerTest.java b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformerTest.java index 5d4d7bad5a..f00fd1577f 100644 --- a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformerTest.java +++ b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/helper/UnscheduledCourtHearingListTransformerTest.java @@ -645,5 +645,63 @@ private JudicialResult resultWithNextHearingDateTobeFixed() { .build(); } + private JudicialResult resultWithNextHearingDateTobeFixedAndBookingReference(final UUID bookingReference) { + return JudicialResult.judicialResult() + .withIsUnscheduled(false) + .withJudicialResultTypeId(UnscheduledCourtHearingListTransformer.RESULT_DEFINITION_NHCCS) + .withNextHearing(NextHearing.nextHearing() + .withDateToBeFixed(true) + .withBookingReference(bookingReference) + .withType(HearingType.hearingType().withId(randomUUID()).withDescription("desc").build()) + .withCourtCentre(CourtCentre.courtCentre().withId(randomUUID()).build()) + .build()) + .withLabel(NHCCS_LABEL) + .build(); + } + + @Test + public void shouldPropagateBookingReferenceFromNextHearingOnOffencePath() { + final UUID bookingReference = randomUUID(); + final JudicialResult result = resultWithNextHearingDateTobeFixedAndBookingReference(bookingReference); + final Offence offence = createOffenceWithJR(asList(result)); + final Hearing hearing = createHearingWithOffences(asList(offence)); + + final List unscheduledListingNeedsList = unscheduledCourtHearingListTransformer.transformHearing(hearing); + + assertThat(unscheduledListingNeedsList.size(), is(1)); + assertThat(unscheduledListingNeedsList.get(0).getBookingReference(), is(bookingReference)); + } + + @Test + public void shouldPropagateBookingReferenceFromNextHearingOnApplicationPath() { + final UUID bookingReference = randomUUID(); + final JudicialResult result = resultWithNextHearingDateTobeFixedAndBookingReference(bookingReference); + + final CourtApplication courtApplication = CourtApplication.courtApplication() + .withId(randomUUID()) + .withJudicialResults(asList(result)) + .build(); + final Hearing hearing = Hearing.hearing() + .withJurisdictionType(JurisdictionType.MAGISTRATES) + .withCourtApplications(asList(courtApplication)) + .build(); + + final List unscheduledListingNeedsList = unscheduledCourtHearingListTransformer.transformHearing(hearing); + + assertThat(unscheduledListingNeedsList.size(), is(1)); + assertThat(unscheduledListingNeedsList.get(0).getBookingReference(), is(bookingReference)); + } + + @Test + public void shouldNotSetBookingReferenceWhenJudicialResultHasUnscheduledFlagOnly() { + final Offence offence = createOffenceWithJR(asList(wofnResult())); + final Hearing hearing = createHearingWithOffences(asList(offence)); + + final List unscheduledListingNeedsList = unscheduledCourtHearingListTransformer.transformHearing(hearing); + + assertThat(unscheduledListingNeedsList.size(), is(1)); + assertThat(unscheduledListingNeedsList.get(0).getBookingReference(), is(nullValue())); + } + } \ No newline at end of file diff --git a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java index d1d8e361a8..58c46af578 100644 --- a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java +++ b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java @@ -11,6 +11,8 @@ import static org.hamcrest.Matchers.nullValue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static uk.gov.moj.cpp.progression.helper.TestHelper.buildNextHearing; import static uk.gov.moj.cpp.progression.helper.TestHelper.buildNextHearingForApplication; @@ -18,11 +20,14 @@ import static uk.gov.moj.cpp.progression.test.FileUtil.getPayload; import uk.gov.justice.core.courts.CommittingCourt; +import uk.gov.justice.core.courts.CourtCentre; import uk.gov.justice.core.courts.Defendant; import uk.gov.justice.core.courts.Hearing; import uk.gov.justice.core.courts.HearingListingNeeds; +import uk.gov.justice.core.courts.HearingType; import uk.gov.justice.core.courts.JudicialResult; import uk.gov.justice.core.courts.JurisdictionType; +import uk.gov.justice.core.courts.NextHearing; import uk.gov.justice.core.courts.NextHearingsRequested; import uk.gov.justice.core.courts.Offence; import uk.gov.justice.core.courts.ProsecutionCase; @@ -863,6 +868,73 @@ public void shouldReturnTwoHearingNeedsWhenTwoHearingTypeNotMatchWithBookingRefe assertThat(defendant2.getOffences().get(0).getId(), equalTo(OFFENCE_ID_2)); } + @Test + public void shouldCarryBookingReferenceAndGroupOffencesWhenNhccNextHearingHasBookingReference() { + final Map> slotsMap = new HashMap<>(); + slotsMap.put(BOOKING_REFERENCE_1, new HashSet<>(Arrays.asList(COURT_SCHEDULE_ID_1))); + + when(provisionalBookingServiceAdapter.getSlots(anyList())).thenReturn(slotsMap); + when(offenceToCommittingCourtConverter.convert(any(), any(), any())).thenReturn(Optional.empty()); + + final Hearing hearing = TestHelper.buildHearing(Arrays.asList( + buildProsecutionCase(CASE_ID_1, DEFENDANT_ID_1, OFFENCE_ID_1, + buildNextHearing(HEARING_TYPE_1, BOOKING_REFERENCE_1, COURT_LOCATION, null, LISTED_START_DATETIME_1)), + buildProsecutionCase(CASE_ID_2, DEFENDANT_ID_2, OFFENCE_ID_2, + buildNextHearing(HEARING_TYPE_1, BOOKING_REFERENCE_1, COURT_LOCATION, null, LISTED_START_DATETIME_1)) + )); + + final List result = transformer.transform(hearing); + + assertThat(result.size(), is(1)); + final HearingListingNeeds needs = result.get(0); + assertThat(needs.getBookingReference(), equalTo(BOOKING_REFERENCE_1)); + assertThat(needs.getProsecutionCases().size(), is(2)); + + final Optional case1 = needs.getProsecutionCases().stream().filter(pc -> pc.getId().equals(CASE_ID_1)).findFirst(); + final Optional case2 = needs.getProsecutionCases().stream().filter(pc -> pc.getId().equals(CASE_ID_2)).findFirst(); + assertThat(case1.isPresent(), is(true)); + assertThat(case2.isPresent(), is(true)); + assertThat(case1.get().getDefendants().get(0).getOffences().get(0).getId(), equalTo(OFFENCE_ID_1)); + assertThat(case2.get().getDefendants().get(0).getOffences().get(0).getId(), equalTo(OFFENCE_ID_2)); + } + + @Test + public void shouldWarnAndSkipWhenNhccNextHearingBookingReferenceNotFoundInSlots() { + when(provisionalBookingServiceAdapter.getSlots(anyList())).thenReturn(new HashMap<>()); + + final Hearing hearing = TestHelper.buildHearing(Arrays.asList( + buildProsecutionCase(CASE_ID_1, DEFENDANT_ID_1, OFFENCE_ID_1, + buildNextHearing(HEARING_TYPE_1, BOOKING_REFERENCE_1, COURT_LOCATION, null, LISTED_START_DATETIME_1)) + )); + + final List result = transformer.transform(hearing); + + assertThat(result.size(), is(0)); + verify(logger).warn(any(String.class), eq(BOOKING_REFERENCE_1), eq(CASE_ID_1)); + } + + @Test + public void shouldSkipNhccsJudicialResultWithDateToBeFixedEvenWhenBookingReferenceIsPresent() { + final Map> slotsMap = new HashMap<>(); + slotsMap.put(BOOKING_REFERENCE_1, new HashSet<>(Arrays.asList(COURT_SCHEDULE_ID_1))); + when(provisionalBookingServiceAdapter.getSlots(anyList())).thenReturn(slotsMap); + + final NextHearing nhccsNextHearing = NextHearing.nextHearing() + .withDateToBeFixed(true) + .withBookingReference(BOOKING_REFERENCE_1) + .withType(HearingType.hearingType().withId(HEARING_TYPE_1).withDescription("desc").build()) + .withCourtCentre(CourtCentre.courtCentre().withCourtHearingLocation(COURT_LOCATION).build()) + .build(); + + final Hearing hearing = TestHelper.buildHearing(Arrays.asList( + buildProsecutionCase(CASE_ID_1, DEFENDANT_ID_1, OFFENCE_ID_1, nhccsNextHearing) + )); + + final List result = transformer.transform(hearing); + + assertThat(result.size(), is(0)); + } + private JsonObject getHearing(final String path) { return stringToJsonObjectConverter.convert(getPayload(path)); } From 65cce486f2a08cca88a6058518a88c5aeb2e25b3 Mon Sep 17 00:00:00 2001 From: Ragubalan Durairaj Date: Thu, 21 May 2026 11:29:59 +0100 Subject: [PATCH 2/3] SPRDT-874: pom version updated --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c3d2d7cf32..5dcdafb088 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ 6.4.1 17.103.131 17.103.163 - 17.0.149 + 17.104.168 17.104.49 17.0.85 17.103.42 From 7b865184d073ce4da5e8112893c9204a5ad5e987 Mon Sep 17 00:00:00 2001 From: Baris Ozturkmen Date: Sun, 14 Jun 2026 02:08:57 +0100 Subject: [PATCH 3/3] SPRDT-874: correct Crown next-hearing tests to match bookingReference-as-courtScheduleId behaviour Crown next hearings with a bookingReference absent from the provisional booking slots map use the bookingReference itself as the courtScheduleId rather than warning and skipping. Update the NHCC test to assert that behaviour and add a separate NHMC (Magistrates) test confirming the warn-and-skip path is unchanged for non-Crown jurisdictions. --- ...gToHearingListingNeedsTransformerTest.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java index 58c46af578..a257d33308 100644 --- a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java +++ b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/transformer/HearingToHearingListingNeedsTransformerTest.java @@ -899,8 +899,12 @@ public void shouldCarryBookingReferenceAndGroupOffencesWhenNhccNextHearingHasBoo } @Test - public void shouldWarnAndSkipWhenNhccNextHearingBookingReferenceNotFoundInSlots() { + public void shouldUseBookingReferenceAsCourtScheduleIdWhenNhccNextHearingBookingReferenceNotFoundInSlots() { + // Crown has no provisional booking concept: when the bookingReference is not present in the + // slots map, the transformer uses the bookingReference itself as the courtScheduleId rather + // than warning and skipping (see HearingToHearingListingNeedsTransformer#isCrownNextHearing). when(provisionalBookingServiceAdapter.getSlots(anyList())).thenReturn(new HashMap<>()); + when(offenceToCommittingCourtConverter.convert(any(), any(), any())).thenReturn(Optional.empty()); final Hearing hearing = TestHelper.buildHearing(Arrays.asList( buildProsecutionCase(CASE_ID_1, DEFENDANT_ID_1, OFFENCE_ID_1, @@ -909,6 +913,27 @@ public void shouldWarnAndSkipWhenNhccNextHearingBookingReferenceNotFoundInSlots( final List result = transformer.transform(hearing); + assertThat(result.size(), is(1)); + assertThat(result.get(0).getBookingReference(), equalTo(BOOKING_REFERENCE_1)); + } + + @Test + public void shouldWarnAndSkipWhenNhmcNextHearingBookingReferenceNotFoundInSlots() { + // Non-Crown (Magistrates) next hearings still warn and skip when the bookingReference has no + // matching provisional booking slot. + when(provisionalBookingServiceAdapter.getSlots(anyList())).thenReturn(new HashMap<>()); + + final NextHearing magsNextHearing = NextHearing.nextHearing() + .withValuesFrom(buildNextHearing(HEARING_TYPE_1, BOOKING_REFERENCE_1, COURT_LOCATION, null, LISTED_START_DATETIME_1)) + .withJurisdictionType(JurisdictionType.MAGISTRATES) + .build(); + + final Hearing hearing = TestHelper.buildHearing(Arrays.asList( + buildProsecutionCase(CASE_ID_1, DEFENDANT_ID_1, OFFENCE_ID_1, magsNextHearing) + )); + + final List result = transformer.transform(hearing); + assertThat(result.size(), is(0)); verify(logger).warn(any(String.class), eq(BOOKING_REFERENCE_1), eq(CASE_ID_1)); }