From f54124d5bed07f073877b09ce1023412a9f58f8b Mon Sep 17 00:00:00 2001 From: Arcadius Ahouansou Date: Thu, 25 Jun 2026 14:59:46 +0100 Subject: [PATCH] LPT-2323 coming from https://github.com/hmcts/cpp-context-listing-archived/commit/1e612197d5b7fa8da4a93b5f6855abecc70234b9 to support alphabetical list generation --- .../listing/query/api/HearingQueryApi.java | 41 ++++++++++-- .../query/api/HearingQueryApiTest.java | 66 +++++++++++++++++++ 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/listing-query/listing-query-api/src/main/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApi.java b/listing-query/listing-query-api/src/main/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApi.java index 82edd884f..af4fa7adb 100644 --- a/listing-query/listing-query-api/src/main/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApi.java +++ b/listing-query/listing-query-api/src/main/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApi.java @@ -9,6 +9,8 @@ import static uk.gov.justice.services.messaging.Envelope.metadataFrom; import static uk.gov.justice.services.messaging.JsonEnvelope.envelopeFrom; import static uk.gov.justice.services.messaging.JsonObjects.createObjectBuilderWithFilter; +import static uk.gov.moj.cpp.listing.domain.CourtListType.ALPHABETICAL; +import static uk.gov.moj.cpp.listing.domain.CourtListType.JUDGE; import static uk.gov.moj.cpp.listing.domain.CourtListType.ONLINE_PUBLIC; import static uk.gov.moj.cpp.listing.domain.CourtListType.PUBLIC; @@ -25,7 +27,9 @@ import uk.gov.moj.cpp.listing.common.xhibit.ReferenceDataLoader; import uk.gov.moj.cpp.listing.domain.CourtListType; import uk.gov.moj.cpp.listing.domain.referencedata.OrganisationUnit; +import uk.gov.moj.cpp.listing.query.api.service.AlphabeticalCourtListService; import uk.gov.moj.cpp.listing.query.api.service.ReferenceDataService; +import uk.gov.moj.cpp.listing.query.document.generator.JudgeListTemplateAssembler; import uk.gov.moj.cpp.listing.query.document.generator.StandardPublicCourtListTemplateAssembler; import uk.gov.moj.cpp.listing.query.view.HearingQueryView; import uk.gov.moj.cpp.listing.query.view.service.ProgressionService; @@ -63,6 +67,7 @@ public class HearingQueryApi { public static final String RESTRICTED = "restricted"; public static final String INCLUDE_APPLICATIONS = "includeApplications"; private static final String LIST_ID = "listId"; + private static final String START_DATE = "startDate"; private static final String OU_L2_CODE = "oucodeL2Code"; private static final String FIRST_NAME = "firstName"; private static final String LAST_NAME = "lastName"; @@ -86,6 +91,12 @@ public class HearingQueryApi { @Inject private StandardPublicCourtListTemplateAssembler standardPublicCourtListAssembler; + @Inject + private AlphabeticalCourtListService alphabeticalCourtListService; + + @Inject + private JudgeListTemplateAssembler judgeListTemplateAssembler; + @Inject private ReferenceDataService referenceDataService; @@ -165,18 +176,23 @@ public JsonEnvelope searchHearingsForCourtListPayload(final JsonEnvelope query) final String courtCentreId = query.payloadAsJsonObject().getString(COURT_CENTRE_ID, null); final String courtRoomId = query.payloadAsJsonObject().getString(COURT_ROOM_ID, null); + final String startDate = query.payloadAsJsonObject().getString(START_DATE, null); final String listId = query.payloadAsJsonObject().getString(LIST_ID); final boolean restricted = Optional.ofNullable(query.payloadAsJsonObject().get(RESTRICTED)).map(restrictedJson -> Boolean.valueOf(restrictedJson.toString())).orElse(false); final boolean includeApplications = Optional.ofNullable(query.payloadAsJsonObject().get(INCLUDE_APPLICATIONS)).map(includeApplicationsJson -> Boolean.valueOf(includeApplicationsJson.toString())).orElse(false); final Optional courtListType = CourtListType.valueFor(listId); if(courtListType.isPresent()) { - final JsonEnvelope queryResponse = hearingQueryView.getCourtListContent(query); - final Optional courtListData = standardPublicCourtListAssembler.assemble(queryResponse, courtCentreId, courtRoomId, courtListType.get(), restricted, includeApplications); + final CourtListType listType = courtListType.get(); + // JUDGE uses a different query (range search by judge); all other types use the standard court list content. + final JsonEnvelope queryResponse = JUDGE.equals(listType) + ? hearingQueryView.rangeSearchHearingsForJudge(query) + : hearingQueryView.getCourtListContent(query); + final Optional courtListData = buildCourtListData(queryResponse, courtCentreId, courtRoomId, listType, restricted, includeApplications, startDate); if (courtListData.isPresent()) { final JsonObject courtListPayload = courtListData.get(); final boolean isWelsh = referenceDataService.isHearingLanguageWelsh(queryResponse, courtCentreId).orElse(false); - final String templateName = getTemplateName(courtListType.get(), isWelsh); + final String templateName = getTemplateName(listType, isWelsh); final JsonObjectBuilder builder = JsonObjects.createObjectBuilder(); courtListPayload.forEach(builder::add); builder.add("templateName", templateName); @@ -290,8 +306,25 @@ private JsonEnvelope processGetCaseByDefendant(final JsonObject payload, final S return this.hearingQueryView.getCasesByDefendantAndHearingDate(caseIds, defendants, hearingDate, query); } + /** + * Builds the court list payload for the given type, routing ALPHABETICAL and JUDGE to their dedicated + * assemblers (mirroring the binary /courtlist endpoint). Without this, those types fall through to the + * standard assembler and yield an empty payload. + */ + private Optional buildCourtListData(final JsonEnvelope queryResponse, final String courtCentreId, final String courtRoomId, + final CourtListType courtListType, final boolean restricted, + final boolean includeApplications, final String startDate) { + if (ALPHABETICAL.equals(courtListType)) { + return alphabeticalCourtListService.buildAlphabeticalCourtListData(queryResponse, courtCentreId); + } + if (JUDGE.equals(courtListType)) { + return judgeListTemplateAssembler.assemble(queryResponse, courtCentreId, courtRoomId, courtListType, startDate); + } + return standardPublicCourtListAssembler.assemble(queryResponse, courtCentreId, courtRoomId, courtListType, restricted, includeApplications); + } + private String getTemplateName(final CourtListType courtListType, boolean welsh) { - if ((PUBLIC.equals(courtListType) || ONLINE_PUBLIC.equals(courtListType)) && welsh) { + if ((ALPHABETICAL.equals(courtListType) || PUBLIC.equals(courtListType) || ONLINE_PUBLIC.equals(courtListType)) && welsh) { return courtListType.getWelshTemplateName(); } return courtListType.getTemplateName(); diff --git a/listing-query/listing-query-api/src/test/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApiTest.java b/listing-query/listing-query-api/src/test/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApiTest.java index 3a550dfde..0e143182c 100644 --- a/listing-query/listing-query-api/src/test/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApiTest.java +++ b/listing-query/listing-query-api/src/test/java/uk/gov/moj/cpp/listing/query/api/HearingQueryApiTest.java @@ -19,8 +19,10 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static uk.gov.justice.services.messaging.JsonEnvelope.envelopeFrom; @@ -31,6 +33,8 @@ import static uk.gov.justice.services.test.utils.core.matchers.JsonEnvelopeMatcher.jsonEnvelope; import static uk.gov.justice.services.test.utils.core.matchers.JsonEnvelopeMetadataMatcher.metadata; import static uk.gov.justice.services.test.utils.core.matchers.JsonEnvelopePayloadMatcher.payloadIsJson; +import static uk.gov.moj.cpp.listing.domain.CourtListType.ALPHABETICAL; +import static uk.gov.moj.cpp.listing.domain.CourtListType.JUDGE; import static uk.gov.moj.cpp.listing.domain.CourtListType.ONLINE_PUBLIC; import static uk.gov.moj.cpp.listing.domain.CourtListType.PRISON; import static uk.gov.moj.cpp.listing.domain.CourtListType.PUBLIC; @@ -49,8 +53,10 @@ import uk.gov.moj.cpp.listing.common.xhibit.ReferenceDataLoader; import uk.gov.moj.cpp.listing.domain.CourtListType; import uk.gov.moj.cpp.listing.domain.referencedata.OrganisationUnit; +import uk.gov.moj.cpp.listing.query.api.service.AlphabeticalCourtListService; import uk.gov.moj.cpp.listing.query.api.service.ReferenceDataService; import uk.gov.moj.cpp.listing.query.api.util.FileUtil; +import uk.gov.moj.cpp.listing.query.document.generator.JudgeListTemplateAssembler; import uk.gov.moj.cpp.listing.query.document.generator.StandardPublicCourtListTemplateAssembler; import uk.gov.moj.cpp.listing.query.view.HearingQueryView; import uk.gov.moj.cpp.listing.query.view.service.ProgressionService; @@ -117,6 +123,12 @@ public class HearingQueryApiTest { @Mock private StandardPublicCourtListTemplateAssembler standardPublicCourtListAssembler; + @Mock + private AlphabeticalCourtListService alphabeticalCourtListService; + + @Mock + private JudgeListTemplateAssembler judgeListTemplateAssembler; + @Mock private ReferenceDataService referenceDataService; @@ -329,6 +341,60 @@ public void shouldReturnPayloadWithTemplateNameWhenUshersMagistrateList() { assertThat(returnedEnvelope.payloadAsJsonObject().getString("templateName"), is("UshersMagistrateList")); } + @Test + public void shouldRouteAlphabeticalToAlphabeticalServiceAndReturnCourtListTemplate() { + final JsonEnvelope query = envelopeFrom( + metadataBuilder() + .withId(fromString("6d4ced64-b058-4bd4-a652-98d8230b92a5")) + .withName("listing.search.court.list.payload"), + createObjectBuilder() + .add(COURT_CENTRE_ID, randomUUID().toString()) + .add(COURT_ROOM_ID, randomUUID().toString()) + .add(LIST_ID, ALPHABETICAL.toString()) + .build()); + + final JsonEnvelope courtListContent = mock(JsonEnvelope.class); + when(hearingQueryView.getCourtListContent(query)).thenReturn(courtListContent); + when(alphabeticalCourtListService.buildAlphabeticalCourtListData(any(JsonEnvelope.class), any(String.class))) + .thenReturn(Optional.of(createObjectBuilder().add("id", "id1").build())); + when(referenceDataService.isHearingLanguageWelsh(any(JsonEnvelope.class), any(String.class))).thenReturn(Optional.empty()); + + final JsonEnvelope returnedEnvelope = hearingQueryApi.searchHearingsForCourtListPayload(query); + + assertThat(returnedEnvelope.payloadAsJsonObject().getString("id"), is("id1")); + assertThat(returnedEnvelope.payloadAsJsonObject().getString("templateName"), is("CourtList")); + verify(alphabeticalCourtListService).buildAlphabeticalCourtListData(any(JsonEnvelope.class), any(String.class)); + verify(standardPublicCourtListAssembler, never()).assemble(any(), any(), any(), any(), anyBoolean(), anyBoolean()); + } + + @Test + public void shouldRouteJudgeToJudgeAssemblerUsingJudgeRangeSearchAndReturnJudgeListTemplate() { + final JsonEnvelope query = envelopeFrom( + metadataBuilder() + .withId(fromString("6d4ced64-b058-4bd4-a652-98d8230b92a5")) + .withName("listing.search.court.list.payload"), + createObjectBuilder() + .add(COURT_CENTRE_ID, randomUUID().toString()) + .add(COURT_ROOM_ID, randomUUID().toString()) + .add("startDate", "2026-06-03") + .add(LIST_ID, JUDGE.toString()) + .build()); + + final JsonEnvelope judgeContent = mock(JsonEnvelope.class); + when(hearingQueryView.rangeSearchHearingsForJudge(query)).thenReturn(judgeContent); + when(judgeListTemplateAssembler.assemble(any(JsonEnvelope.class), any(String.class), any(String.class), any(CourtListType.class), any(String.class))) + .thenReturn(Optional.of(createObjectBuilder().add("id", "id1").build())); + when(referenceDataService.isHearingLanguageWelsh(any(JsonEnvelope.class), any(String.class))).thenReturn(Optional.empty()); + + final JsonEnvelope returnedEnvelope = hearingQueryApi.searchHearingsForCourtListPayload(query); + + assertThat(returnedEnvelope.payloadAsJsonObject().getString("id"), is("id1")); + assertThat(returnedEnvelope.payloadAsJsonObject().getString("templateName"), is("JudgeList")); + verify(hearingQueryView).rangeSearchHearingsForJudge(query); + verify(hearingQueryView, never()).getCourtListContent(query); + verify(judgeListTemplateAssembler).assemble(any(JsonEnvelope.class), any(String.class), any(String.class), any(CourtListType.class), any(String.class)); + } + @Test public void shouldReturnPayloadWithTemplateNameWhenOnlinePublicCourtList() { final JsonEnvelope query = envelopeFrom(