From e5e5d82b0df7caaf4514f09f19a1455d699754c6 Mon Sep 17 00:00:00 2001 From: SachinNaik Date: Tue, 31 Mar 2026 14:27:38 +0100 Subject: [PATCH 001/108] HPDI-4063 Adding caseManagementCategory as top level field --- .../uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java | 7 +++++++ .../pcs/ccd/view/globalsearch/CaseFieldsView.java | 8 ++++++++ src/main/resources/application.yaml | 5 ++++- .../ccd/view/globalsearch/CaseFieldsViewTest.java | 12 ++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index 51e0ef2d04..18098acf74 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -532,4 +532,11 @@ public class PCSCase { ) private String caseManagementLocationFormatted; + @CCD( + label = "CaseManagementCategory", + access = {GlobalSearchAccess.class} + ) + private String caseManagementCategory; + + } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java index 57736f2ab2..d221a348ec 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java @@ -7,11 +7,14 @@ import java.util.List; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class CaseFieldsView { + @Value("${globalsearch.caseManagementCategory}") + private String caseManagementCategory; /** * Sets case fields for the pcsCase. @@ -20,6 +23,7 @@ public class CaseFieldsView { public void setCaseFields(final PCSCase pcsCase) { setCaseNameHmctsField(pcsCase); setCaseManagementLocationField(pcsCase); + setCaseManagementCategory(pcsCase); } /** @@ -55,6 +59,10 @@ private void setCaseManagementLocationField(final PCSCase pcsCase) { } } + private void setCaseManagementCategory(PCSCase pcsCase) { + pcsCase.setCaseManagementCategory(caseManagementCategory); + } + private String getFormattedClaimantName(final List> claimants) { String formattedClaimantName = null; if (claimants != null && !claimants.isEmpty()) { diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index f2bdbaa71a..f52537ae5a 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -19,6 +19,9 @@ management: elasticsearch: enabled: false +globalsearch: + caseManagementCategory: Property Possession Claims + hmcts: hmctsOrgId: AAA3 @@ -196,4 +199,4 @@ payments: core_case_data: api: - url: ${CCD_DATA_STORE_URL:localhost:4452} \ No newline at end of file + url: ${CCD_DATA_STORE_URL:localhost:4452} diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java index 921c66ba94..17810cb7f5 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.params.provider.CsvSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; @ExtendWith(MockitoExtension.class) class CaseFieldsViewTest { @@ -47,6 +48,7 @@ class CaseFieldsViewTest { @BeforeEach void setUp() { underTest = new CaseFieldsView(); + ReflectionTestUtils.setField(underTest, "caseManagementCategory", "Property Possession Claims"); } @@ -161,4 +163,14 @@ void shouldNotCallSetCaseManagementLocationFormattedWhenEitherIdIsNull(Integer e // Then verify(pcsCase, never()).setCaseManagementLocationFormatted(anyString()); } + + @Test + void shouldSetCaseManagementCategory() { + + //When + underTest.setCaseFields(pcsCase); + + // Then + verify(pcsCase).setCaseManagementCategory("Property Possession Claims"); + } } From 90cf6e15cfe984a6ee01fb0e2a47008b136e69ed Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 1 Apr 2026 14:14:01 +0100 Subject: [PATCH 002/108] HDPI-4063 Change caseManagementCategory to Dynamic List --- .../hmcts/reform/pcs/ccd/domain/PCSCase.java | 3 +-- .../ccd/view/globalsearch/CaseFieldsView.java | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index 18098acf74..084dac7a11 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -536,7 +536,6 @@ public class PCSCase { label = "CaseManagementCategory", access = {GlobalSearchAccess.class} ) - private String caseManagementCategory; - + private DynamicList caseManagementCategory; } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java index d221a348ec..7a3a90ed44 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java @@ -1,11 +1,15 @@ package uk.gov.hmcts.reform.pcs.ccd.view.globalsearch; +import uk.gov.hmcts.ccd.sdk.type.DynamicList; +import uk.gov.hmcts.ccd.sdk.type.DynamicListElement; import uk.gov.hmcts.ccd.sdk.type.ListValue; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; +import java.util.ArrayList; import java.util.List; +import java.util.UUID; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -60,7 +64,18 @@ private void setCaseManagementLocationField(final PCSCase pcsCase) { } private void setCaseManagementCategory(PCSCase pcsCase) { - pcsCase.setCaseManagementCategory(caseManagementCategory); + final UUID uuid = UUID.randomUUID(); + final DynamicListElement listElement = DynamicListElement.builder() + .code(uuid) + .label(caseManagementCategory) + .build(); + final List caseManagementCategoryList = new ArrayList<>(); + caseManagementCategoryList.add(listElement); + + pcsCase.setCaseManagementCategory(DynamicList.builder() + .value(listElement) + .listItems(caseManagementCategoryList) + .build()); } private String getFormattedClaimantName(final List> claimants) { From c7109b93246db30660c7705b66470f502851c697 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 1 Apr 2026 16:26:37 +0100 Subject: [PATCH 003/108] HDPI-4063 Change caseManagementLocation to CaseLocation type --- .../gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 6 +++--- .../hmcts/reform/pcs/ccd/domain/PCSCase.java | 5 +++-- .../ccd/view/globalsearch/CaseFieldsView.java | 18 +++++++--------- .../view/globalsearch/CaseFieldsViewTest.java | 21 ++++++++++++------- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index 67c12b6cea..33cacfd8e6 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -83,10 +83,10 @@ public PCSCase getCase(CaseViewRequest request) { boolean hasUnsubmittedCaseData = caseHasUnsubmittedData(caseReference, state); - caseFieldsView.setCaseFields(pcsCase); - setMarkdownFields(pcsCase, hasUnsubmittedCaseData); + caseFieldsView.setCaseFields(pcsCase); + //allows indexing for Global Search pcsCase.setSearchCriteria(new SearchCriteria()); @@ -109,7 +109,7 @@ private PCSCase getSubmittedCase(long caseReference) { PCSCase pcsCase = PCSCase.builder() .propertyAddress(convertAddress(pcsCaseEntity.getPropertyAddress())) .legislativeCountry(pcsCaseEntity.getLegislativeCountry()) - .caseManagementLocation(pcsCaseEntity.getCaseManagementLocation()) + .caseManagementLocationNumber(pcsCaseEntity.getCaseManagementLocation()) .allClaimants(partyMap.get(PartyRole.CLAIMANT)) .allDefendants(partyMap.get(PartyRole.DEFENDANT)) .allUnderlesseeOrMortgagees(partyMap.get(PartyRole.UNDERLESSEE_OR_MORTGAGEE)) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index 084dac7a11..1b980122c7 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -7,6 +7,7 @@ import uk.gov.hmcts.ccd.sdk.External; import uk.gov.hmcts.ccd.sdk.api.CCD; import uk.gov.hmcts.ccd.sdk.type.AddressUK; +import uk.gov.hmcts.ccd.sdk.type.CaseLocation; import uk.gov.hmcts.ccd.sdk.type.Document; import uk.gov.hmcts.ccd.sdk.type.DynamicList; import uk.gov.hmcts.ccd.sdk.type.FieldType; @@ -126,7 +127,7 @@ public class PCSCase { @CCD( label = "Case management location" ) - private Integer caseManagementLocation; + private Integer caseManagementLocationNumber; @CCD( label = "Region Id" @@ -530,7 +531,7 @@ public class PCSCase { label = "CaseManagementLocation", access = {GlobalSearchAccess.class} ) - private String caseManagementLocationFormatted; + private CaseLocation caseManagementLocation; @CCD( label = "CaseManagementCategory", diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java index 7a3a90ed44..b9a3a275c2 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java @@ -1,5 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.view.globalsearch; +import uk.gov.hmcts.ccd.sdk.type.CaseLocation; import uk.gov.hmcts.ccd.sdk.type.DynamicList; import uk.gov.hmcts.ccd.sdk.type.DynamicListElement; import uk.gov.hmcts.ccd.sdk.type.ListValue; @@ -49,17 +50,16 @@ private void setCaseNameHmctsField(final PCSCase pcsCase) { pcsCase.setCaseNamePublic(formattedCaseName); } - /** - * Builds a formatted string for the case management location field based on epimsId and regionId. - * - * @param pcsCase The current case data - */ + private void setCaseManagementLocationField(final PCSCase pcsCase) { - Integer epimsId = pcsCase.getCaseManagementLocation(); + Integer epimsId = pcsCase.getCaseManagementLocationNumber(); Integer region = pcsCase.getRegionId(); if (epimsId != null && region != null) { - pcsCase.setCaseManagementLocationFormatted(getFormattedValue(region, epimsId)); + pcsCase.setCaseManagementLocation(CaseLocation.builder() + .baseLocation(String.valueOf(epimsId)) + .region(String.valueOf(region)) + .build()); } } @@ -105,8 +105,4 @@ private String getFormattedDefendantName(final List> defendants private boolean isDefendantNameKnown(final List> defendants) { return defendants.getFirst().getValue().getNameKnown() == VerticalYesNo.YES; } - - private String getFormattedValue(int region, int epimsId) { - return "{region:%s,baseLocation:%s}".formatted(region, epimsId); - } } diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java index 17810cb7f5..3b5b94ffd8 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java @@ -1,12 +1,14 @@ package uk.gov.hmcts.reform.pcs.ccd.view.globalsearch; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo.NO; import static uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo.YES; +import uk.gov.hmcts.ccd.sdk.type.CaseLocation; +import uk.gov.hmcts.ccd.sdk.type.DynamicList; import uk.gov.hmcts.ccd.sdk.type.ListValue; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; @@ -132,17 +134,20 @@ void shouldSetCaseNameWhenClaimantIsCitizenAndDefendantUnkown() { } @Test - void shouldSetCaseManagementLocationFormatted() { + void shouldSetCaseManagementLocation() { //Given - when(pcsCase.getCaseManagementLocation()).thenReturn(29096); + when(pcsCase.getCaseManagementLocationNumber()).thenReturn(29096); when(pcsCase.getRegionId()).thenReturn(1); //When underTest.setCaseFields(pcsCase); // Then - verify(pcsCase).setCaseManagementLocationFormatted("{region:1,baseLocation:29096}"); + verify(pcsCase).setCaseManagementLocation(CaseLocation.builder() + .baseLocation("29096") + .region("1") + .build()); } @ParameterizedTest @@ -151,17 +156,17 @@ void shouldSetCaseManagementLocationFormatted() { "null,1", "null,null" }, nullValues = {"null"}) - void shouldNotCallSetCaseManagementLocationFormattedWhenEitherIdIsNull(Integer epimsId, Integer regionId) { + void shouldNotCallSetCaseManagementLocationWhenEitherIdIsNull(Integer epimsId, Integer regionId) { //Given - when(pcsCase.getCaseManagementLocation()).thenReturn(epimsId); + when(pcsCase.getCaseManagementLocationNumber()).thenReturn(epimsId); when(pcsCase.getRegionId()).thenReturn(regionId); //When underTest.setCaseFields(pcsCase); // Then - verify(pcsCase, never()).setCaseManagementLocationFormatted(anyString()); + verify(pcsCase, never()).setCaseManagementLocation(any(CaseLocation.class)); } @Test @@ -171,6 +176,6 @@ void shouldSetCaseManagementCategory() { underTest.setCaseFields(pcsCase); // Then - verify(pcsCase).setCaseManagementCategory("Property Possession Claims"); + verify(pcsCase).setCaseManagementCategory(any(DynamicList.class)); } } From c8ffc492612edd7d126f2a979db312687d22d541 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 7 Apr 2026 14:05:37 +0100 Subject: [PATCH 004/108] HDPI-4063 Styling and tests --- .../pcs/ccd/view/globalsearch/CaseFieldsView.java | 8 +++----- .../pcs/ccd/view/globalsearch/CaseFieldsViewTest.java | 10 +++++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java index b9a3a275c2..b9d1bb1789 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java @@ -64,13 +64,11 @@ private void setCaseManagementLocationField(final PCSCase pcsCase) { } private void setCaseManagementCategory(PCSCase pcsCase) { - final UUID uuid = UUID.randomUUID(); - final DynamicListElement listElement = DynamicListElement.builder() - .code(uuid) + DynamicListElement listElement = DynamicListElement.builder() + .code(UUID.randomUUID()) .label(caseManagementCategory) .build(); - final List caseManagementCategoryList = new ArrayList<>(); - caseManagementCategoryList.add(listElement); + List caseManagementCategoryList = List.of(listElement); pcsCase.setCaseManagementCategory(DynamicList.builder() .value(listElement) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java index 3b5b94ffd8..d4cb3fc112 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java @@ -1,5 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.view.globalsearch; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -15,6 +16,8 @@ import java.util.List; +import org.mockito.ArgumentCaptor; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -171,11 +174,16 @@ void shouldNotCallSetCaseManagementLocationWhenEitherIdIsNull(Integer epimsId, I @Test void shouldSetCaseManagementCategory() { + ArgumentCaptor captor = ArgumentCaptor.forClass(DynamicList.class); //When underTest.setCaseFields(pcsCase); // Then - verify(pcsCase).setCaseManagementCategory(any(DynamicList.class)); + verify(pcsCase).setCaseManagementCategory(captor.capture()); + DynamicList result = captor.getValue(); + assertThat(result.getValue().getLabel()).isEqualTo("Property Possession Claims"); + assertThat(result.getListItems()).hasSize(1); + assertThat(result.getListItems().getFirst().getLabel()).isEqualTo("Property Possession Claims"); } } From a2ae320bdda35c37108ea4844323c322730198ec Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 7 Apr 2026 14:23:31 +0100 Subject: [PATCH 005/108] HDPI-4063 Styling and tests --- .../hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java index b9d1bb1789..8afb177804 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsView.java @@ -8,7 +8,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; -import java.util.ArrayList; import java.util.List; import java.util.UUID; From c69133d9ba96977b45ccba49a082c13ae7a89fae Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 8 Apr 2026 15:53:24 +0100 Subject: [PATCH 006/108] HDPI-4063 Set case location in test to final field --- .../reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java index d4cb3fc112..e083d1766b 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/CaseFieldsViewTest.java @@ -33,6 +33,7 @@ class CaseFieldsViewTest { private static final String CLAIMANT_NAME = "Freeman"; private static final String DEFENDANT_LAST_NAME = "Jackson"; private static final String CLAIMANT_ORGANISATION_NAME = "Treetops Housing"; + private static final int CASE_MANAGEMENT_LOCATION_NUMBER = 29096; @Mock private PCSCase pcsCase; @@ -140,7 +141,7 @@ void shouldSetCaseNameWhenClaimantIsCitizenAndDefendantUnkown() { void shouldSetCaseManagementLocation() { //Given - when(pcsCase.getCaseManagementLocationNumber()).thenReturn(29096); + when(pcsCase.getCaseManagementLocationNumber()).thenReturn(CASE_MANAGEMENT_LOCATION_NUMBER); when(pcsCase.getRegionId()).thenReturn(1); //When @@ -148,7 +149,7 @@ void shouldSetCaseManagementLocation() { // Then verify(pcsCase).setCaseManagementLocation(CaseLocation.builder() - .baseLocation("29096") + .baseLocation(String.valueOf(CASE_MANAGEMENT_LOCATION_NUMBER)) .region("1") .build()); } From 9823795129310f8eb121e456d7aee7cd720233e5 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 10 Apr 2026 11:44:44 +0100 Subject: [PATCH 007/108] HDPI-4161 Create and grant GS roles. --- .../pcs/ccd/accesscontrol/GlobalSearchAccess.java | 11 ++--------- .../hmcts/reform/pcs/ccd/accesscontrol/UserRole.java | 3 ++- .../pcs/ccd/accesscontrol/GlobalSearchAccessTest.java | 7 +++++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index b09cf101da..fc5ed29302 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,7 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_CASE_WORKER; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_SOLICITOR; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.GS_PROFILE; import uk.gov.hmcts.ccd.sdk.api.HasAccessControl; import uk.gov.hmcts.ccd.sdk.api.HasRole; @@ -14,13 +13,7 @@ public class GlobalSearchAccess implements HasAccessControl { @Override public SetMultimap getGrants() { SetMultimap grants = HashMultimap.create(); - grants.putAll(PCS_CASE_WORKER, Permission.CRUD); - - /*** - * Remove before release - */ - - grants.putAll(PCS_SOLICITOR, Permission.CRUD); + grants.put(GS_PROFILE, Permission.R); return grants; } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index 1a10265e20..55cca0824b 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -23,7 +23,8 @@ public enum UserRole implements HasRole { CREATOR("[CREATOR]", Permission.CRU, RAS), DEFENDANT("[DEFENDANT]", Permission.CRU, RAS), PCS_CASE_WORKER("caseworker-pcs", Set.of(R), IDAM), - PCS_SOLICITOR("caseworker-pcs-solicitor", Permission.CRU, IDAM); + PCS_SOLICITOR("caseworker-pcs-solicitor", Permission.CRU, IDAM), + GS_PROFILE("GS_profile", Set.of(R), IDAM); @JsonValue private final String role; diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java index 7c9f0963bf..c0efcdb744 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java @@ -3,7 +3,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_CASE_WORKER; +import static uk.gov.hmcts.ccd.sdk.api.Permission.R; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.GS_PROFILE; import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; @@ -12,6 +13,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Set; + class GlobalSearchAccessTest { private GlobalSearchAccess underTest; @@ -24,7 +27,7 @@ void setUp() { @Test void shouldGrantGlobalSearchAccess() { SetMultimap grants = underTest.getGrants(); - assertThat(grants.asMap()).contains(entry(PCS_CASE_WORKER, Permission.CRUD)); + assertThat(grants.asMap()).contains(entry(GS_PROFILE, Set.of(R))); } } From 76610f700869f13b2e3dd68d81c7e0049dfbcfcf Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 10 Apr 2026 16:51:27 +0100 Subject: [PATCH 008/108] HDPI-4161 adjust so role assignments to allow for internal and external role names to differ --- .../pcs/ccd/accesscontrol/ExternalUserRole.java | 5 ++++- .../ccd/accesscontrol/GlobalSearchAccess.java | 4 ++-- .../reform/pcs/ccd/accesscontrol/UserRole.java | 17 ++++++++++++++--- .../accesscontrol/GlobalSearchAccessTest.java | 4 ++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java index e902062679..47643a072e 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java @@ -16,8 +16,11 @@ public static ExternalUserRole forCcdRole(UserRole ccdRole) { @Override public String getRole() { + String name = ccdUserRole.getExternalRoleName() != null + ? ccdUserRole.getExternalRoleName() + : ccdUserRole.getRole(); String rolePrefix = (ccdUserRole.getRoleType() == RoleType.IDAM) ? "idam:" : ""; - return rolePrefix + ccdUserRole.getRole(); + return rolePrefix + name; } @Override diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index fc5ed29302..c59b5fee79 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,6 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.GS_PROFILE; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; import uk.gov.hmcts.ccd.sdk.api.HasAccessControl; import uk.gov.hmcts.ccd.sdk.api.HasRole; @@ -13,7 +13,7 @@ public class GlobalSearchAccess implements HasAccessControl { @Override public SetMultimap getGrants() { SetMultimap grants = HashMultimap.create(); - grants.put(GS_PROFILE, Permission.R); + grants.put(HMCTS_STAFF, Permission.R); return grants; } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index 55cca0824b..e7a0c09ae0 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -1,7 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; import com.fasterxml.jackson.annotation.JsonValue; -import lombok.AllArgsConstructor; import lombok.Getter; import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; @@ -15,7 +14,6 @@ /** * All the different roles for a PCS case. */ -@AllArgsConstructor @Getter public enum UserRole implements HasRole { @@ -24,12 +22,25 @@ public enum UserRole implements HasRole { DEFENDANT("[DEFENDANT]", Permission.CRU, RAS), PCS_CASE_WORKER("caseworker-pcs", Set.of(R), IDAM), PCS_SOLICITOR("caseworker-pcs-solicitor", Permission.CRU, IDAM), - GS_PROFILE("GS_profile", Set.of(R), IDAM); + HMCTS_STAFF("GS_profile", Set.of(R), RAS, "hmcts-staff"), + HMCTS_JUDICIARY("GS_profile", Set.of(R), RAS, "hmcts-judiciary"); @JsonValue private final String role; private final Set caseTypePermissions; private final RoleType roleType; + private final String externalRoleName; + + UserRole(String role, Set permissions, RoleType roleType) { + this(role, permissions, roleType, null); + } + + UserRole(String role, Set permissions, RoleType roleType, String externalRoleName) { + this.role = role; + this.caseTypePermissions = permissions; + this.roleType = roleType; + this.externalRoleName = externalRoleName; + } public String getCaseTypePermissions() { return Permission.toString(caseTypePermissions); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java index c0efcdb744..e5204d72f3 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.GS_PROFILE; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; @@ -27,7 +27,7 @@ void setUp() { @Test void shouldGrantGlobalSearchAccess() { SetMultimap grants = underTest.getGrants(); - assertThat(grants.asMap()).contains(entry(GS_PROFILE, Set.of(R))); + assertThat(grants.asMap()).contains(entry(HMCTS_STAFF, Set.of(R))); } } From 30fcc913fe3f484f64fbe060fd1842523e6320cf Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Mon, 13 Apr 2026 10:10:57 +0100 Subject: [PATCH 009/108] try overriding env vars --- charts/pcs-api/values.ccd.preview.template.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index fd85fd55a5..caf70a73d6 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -194,6 +194,9 @@ xui-webapp: SERVICES_TERMS_AND_CONDITIONS: http://xui-terms-and-conditions-aat.service.core-compute-aat.internal SERVICES_HEARINGS_COMPONENT_API: http://jurisdiction-hearings-api-aat.service.core-compute-aat.internal JURISDICTIONS: PCS,CIVIL + GLOBAL_SEARCH_SERVICES: PCS,CIVIL + WA_SUPPORTED_JURISDICTIONS: PCS,CIVIL + STAFF_SUPPORTED_JURISDICTIONS: PCS FEATURE_REDIS_ENABLED: false REDISCLOUD_URL: http://dummyrediscloudurl FEATURE_APP_INSIGHTS_ENABLED: false From c00584d2dd8af2ba0212c7e1f4554da4fc873933 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Mon, 13 Apr 2026 15:40:21 +0100 Subject: [PATCH 010/108] try --- .../gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 4 - .../controllers/RefDataStubController.java | 105 ++++++++++++++++++ .../pcs/globalsearch/SearchCriteria.java | 7 +- 3 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index fa05a0bc2c..daabb76f2d 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -8,7 +8,6 @@ import uk.gov.hmcts.ccd.sdk.type.AddressUK; import uk.gov.hmcts.ccd.sdk.type.Document; import uk.gov.hmcts.ccd.sdk.type.ListValue; -import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; import uk.gov.hmcts.ccd.sdk.type.YesOrNo; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; @@ -89,9 +88,6 @@ public PCSCase getCase(CaseViewRequest request) { caseFieldsView.setCaseFields(pcsCase); - //allows indexing for Global Search - pcsCase.setSearchCriteria(new SearchCriteria()); - return pcsCase; } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java b/src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java new file mode 100644 index 0000000000..f883a36187 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java @@ -0,0 +1,105 @@ +package uk.gov.hmcts.reform.pcs.controllers; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +import static java.util.Map.entry; + +@RestController +public class RefDataStubController { + + private static final String SERVICE = "PCS"; + private static final String SERVICE_NAME = "Possessions"; + private static final String LOCATION_ID = "336559"; + private static final String LOCATION_NAME = "Central London County Court"; + private static final String REGION_ID = "1"; + + @GetMapping(value = "/refdata/internal/staff/usersByServiceName", produces = MediaType.APPLICATION_JSON_VALUE) + public List> usersByServiceName(@RequestParam("ccd_service_names") String ccdServiceNames) { + return List.of( + staffUser("74e702fa-e20f-3a40-bc1d-d915f0874d00", "caseworker@pcs.com", "Case", "Worker"), + staffUser("749ce9f7-535a-3cf5-ba07-f66e6d55c5fa", "judge@pcs.com", "Judge", "PCS") + ); + } + + @GetMapping(value = "/refdata/location/court-venues/services", produces = MediaType.APPLICATION_JSON_VALUE) + public Map courtVenuesByService(@RequestParam("service_code") String serviceCode) { + return Map.of("court_venues", buildCourtVenueList()); + } + + @GetMapping(value = "/refdata/location/court-venues", produces = MediaType.APPLICATION_JSON_VALUE) + public List> courtVenuesById(@RequestParam("epimms_id") String epimmsId) { + return buildCourtVenueList(); + } + + @GetMapping(value = "/refdata/location/orgServices", produces = MediaType.APPLICATION_JSON_VALUE) + public Map orgServices() { + return Map.of( + "service_area", List.of(Map.ofEntries( + entry("service_code", SERVICE), + entry("ccd_service_name", SERVICE), + entry("service_name", SERVICE_NAME), + entry("service_short_description", SERVICE_NAME), + entry("service_description", SERVICE_NAME), + entry("jurisdiction", SERVICE), + entry("order", 1) + )) + ); + } + + private Map staffUser(String userId, String email, String firstName, String lastName) { + Map staffProfile = Map.ofEntries( + entry("id", userId), + entry("first_name", firstName), + entry("last_name", lastName), + entry("region_id", REGION_ID), + entry("user_type", "Caseworker"), + entry("idam_roles", "caseworker-pcs"), + entry("suspended", "N"), + entry("case_allocator", "N"), + entry("task_supervisor", "N"), + entry("staff_admin", "N"), + entry("created_time", "2024-01-01T00:00:00Z"), + entry("last_updated_time", "2024-01-01T00:00:00Z"), + entry("email_id", email), + entry("region", "London"), + entry("base_location", List.of(Map.of( + "location_id", LOCATION_ID, + "location", LOCATION_NAME, + "is_primary", true, + "services", List.of( + Map.of( + "service_code", SERVICE, + "ccd_service_name", SERVICE, + "service_name", SERVICE_NAME + ) + ) + ))), + entry("user_type_id", "1"), + entry("role", List.of()), + entry("skills", List.of()), + entry("work_area", List.of()) + ); + + return Map.of( + "ccd_service_name", SERVICE, + "staff_profile", staffProfile + ); + } + + private List> buildCourtVenueList() { + return List.of(Map.of( + "epimms_id", LOCATION_ID, + "site_name", LOCATION_NAME, + "is_case_management_location", "Y", + "region_id", REGION_ID, + "court_type", SERVICE_NAME, + "service_code", SERVICE + )); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java index e3e78a98e5..054f4313f9 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java @@ -10,16 +10,19 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; -import java.util.Collections; import java.util.List; +import static java.util.List.of; @Slf4j @Component @AllArgsConstructor public class SearchCriteria implements CCDConfig { - private static final List SEARCH_CRITERIA_LIST = Collections.emptyList(); + private static final List SEARCH_CRITERIA_LIST = of( + SearchCriteriaField.builder().otherCaseReference("caseNameHmctsInternal").build(), + SearchCriteriaField.builder().otherCaseReference("caseNamePublic").build() + ); @Override public void configureDecentralised(DecentralisedConfigBuilder configBuilder) { From 7eacfa91bc79d4b63b62ed30f40e1f37e5c87d92 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Mon, 13 Apr 2026 15:58:42 +0100 Subject: [PATCH 011/108] add tests --- .../reform/pcs/globalsearch/SearchCriteriaTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java index 44458e6ba6..4732e2b7ec 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java @@ -7,8 +7,9 @@ import uk.gov.hmcts.ccd.sdk.api.DecentralisedConfigBuilder; import uk.gov.hmcts.ccd.sdk.api.SearchCriteria.SearchCriteriaBuilder; +import uk.gov.hmcts.ccd.sdk.api.SearchCriteriaField; -import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,6 +28,10 @@ void setUp() { void shouldConfigureSearchCriteria() { var configBuilder = mock(DecentralisedConfigBuilder.class); var searchCriteriaBuilder = mock(SearchCriteriaBuilder.class); + var expectedFields = List.of( + SearchCriteriaField.builder().otherCaseReference("caseNameHmctsInternal").build(), + SearchCriteriaField.builder().otherCaseReference("caseNamePublic").build() + ); when(configBuilder.searchCriteria()).thenReturn(searchCriteriaBuilder); when(searchCriteriaBuilder.fields(anyList())).thenReturn(searchCriteriaBuilder); @@ -34,6 +39,6 @@ void shouldConfigureSearchCriteria() { underTest.configureDecentralised(configBuilder); verify(configBuilder).searchCriteria(); - verify(searchCriteriaBuilder).fields(Collections.emptyList()); + verify(searchCriteriaBuilder).fields(expectedFields); } } From db7ef83e101084a5670fafb06b9628c47d1c72d4 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Mon, 13 Apr 2026 16:48:40 +0100 Subject: [PATCH 012/108] fix --- .../reform/pcs/globalsearch/SearchCriteriaTest.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java index 4732e2b7ec..1d841f6282 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java @@ -1,18 +1,15 @@ package uk.gov.hmcts.reform.pcs.globalsearch; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import uk.gov.hmcts.ccd.sdk.api.DecentralisedConfigBuilder; import uk.gov.hmcts.ccd.sdk.api.SearchCriteria.SearchCriteriaBuilder; import uk.gov.hmcts.ccd.sdk.api.SearchCriteriaField; import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.*; class SearchCriteriaTest { From 196268a49fb533794ad19d458efed3f2b2a7ade4 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Mon, 13 Apr 2026 17:23:39 +0100 Subject: [PATCH 013/108] fix --- .../controllers/RefDataStubController.java | 105 ------------------ .../pcs/globalsearch/SearchCriteriaTest.java | 6 +- 2 files changed, 4 insertions(+), 107 deletions(-) delete mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java b/src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java deleted file mode 100644 index f883a36187..0000000000 --- a/src/main/java/uk/gov/hmcts/reform/pcs/controllers/RefDataStubController.java +++ /dev/null @@ -1,105 +0,0 @@ -package uk.gov.hmcts.reform.pcs.controllers; - -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; -import java.util.Map; - -import static java.util.Map.entry; - -@RestController -public class RefDataStubController { - - private static final String SERVICE = "PCS"; - private static final String SERVICE_NAME = "Possessions"; - private static final String LOCATION_ID = "336559"; - private static final String LOCATION_NAME = "Central London County Court"; - private static final String REGION_ID = "1"; - - @GetMapping(value = "/refdata/internal/staff/usersByServiceName", produces = MediaType.APPLICATION_JSON_VALUE) - public List> usersByServiceName(@RequestParam("ccd_service_names") String ccdServiceNames) { - return List.of( - staffUser("74e702fa-e20f-3a40-bc1d-d915f0874d00", "caseworker@pcs.com", "Case", "Worker"), - staffUser("749ce9f7-535a-3cf5-ba07-f66e6d55c5fa", "judge@pcs.com", "Judge", "PCS") - ); - } - - @GetMapping(value = "/refdata/location/court-venues/services", produces = MediaType.APPLICATION_JSON_VALUE) - public Map courtVenuesByService(@RequestParam("service_code") String serviceCode) { - return Map.of("court_venues", buildCourtVenueList()); - } - - @GetMapping(value = "/refdata/location/court-venues", produces = MediaType.APPLICATION_JSON_VALUE) - public List> courtVenuesById(@RequestParam("epimms_id") String epimmsId) { - return buildCourtVenueList(); - } - - @GetMapping(value = "/refdata/location/orgServices", produces = MediaType.APPLICATION_JSON_VALUE) - public Map orgServices() { - return Map.of( - "service_area", List.of(Map.ofEntries( - entry("service_code", SERVICE), - entry("ccd_service_name", SERVICE), - entry("service_name", SERVICE_NAME), - entry("service_short_description", SERVICE_NAME), - entry("service_description", SERVICE_NAME), - entry("jurisdiction", SERVICE), - entry("order", 1) - )) - ); - } - - private Map staffUser(String userId, String email, String firstName, String lastName) { - Map staffProfile = Map.ofEntries( - entry("id", userId), - entry("first_name", firstName), - entry("last_name", lastName), - entry("region_id", REGION_ID), - entry("user_type", "Caseworker"), - entry("idam_roles", "caseworker-pcs"), - entry("suspended", "N"), - entry("case_allocator", "N"), - entry("task_supervisor", "N"), - entry("staff_admin", "N"), - entry("created_time", "2024-01-01T00:00:00Z"), - entry("last_updated_time", "2024-01-01T00:00:00Z"), - entry("email_id", email), - entry("region", "London"), - entry("base_location", List.of(Map.of( - "location_id", LOCATION_ID, - "location", LOCATION_NAME, - "is_primary", true, - "services", List.of( - Map.of( - "service_code", SERVICE, - "ccd_service_name", SERVICE, - "service_name", SERVICE_NAME - ) - ) - ))), - entry("user_type_id", "1"), - entry("role", List.of()), - entry("skills", List.of()), - entry("work_area", List.of()) - ); - - return Map.of( - "ccd_service_name", SERVICE, - "staff_profile", staffProfile - ); - } - - private List> buildCourtVenueList() { - return List.of(Map.of( - "epimms_id", LOCATION_ID, - "site_name", LOCATION_NAME, - "is_case_management_location", "Y", - "region_id", REGION_ID, - "court_type", SERVICE_NAME, - "service_code", SERVICE - )); - } -} diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java index 1d841f6282..3a4153cbfe 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java @@ -9,7 +9,9 @@ import java.util.List; import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class SearchCriteriaTest { @@ -25,7 +27,7 @@ void setUp() { void shouldConfigureSearchCriteria() { var configBuilder = mock(DecentralisedConfigBuilder.class); var searchCriteriaBuilder = mock(SearchCriteriaBuilder.class); - var expectedFields = List.of( + final var expectedFields = List.of( SearchCriteriaField.builder().otherCaseReference("caseNameHmctsInternal").build(), SearchCriteriaField.builder().otherCaseReference("caseNamePublic").build() ); From 1971be3c62aafb2a823e419162932e17642b679b Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Mon, 13 Apr 2026 18:19:35 +0100 Subject: [PATCH 014/108] revert --- .../hmcts/reform/pcs/globalsearch/SearchCriteria.java | 8 ++------ .../reform/pcs/globalsearch/SearchCriteriaTest.java | 10 +--------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java index 054f4313f9..1adb1fbaa2 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java @@ -10,19 +10,15 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; +import java.util.Collections; import java.util.List; -import static java.util.List.of; - @Slf4j @Component @AllArgsConstructor public class SearchCriteria implements CCDConfig { - private static final List SEARCH_CRITERIA_LIST = of( - SearchCriteriaField.builder().otherCaseReference("caseNameHmctsInternal").build(), - SearchCriteriaField.builder().otherCaseReference("caseNamePublic").build() - ); + private static final List SEARCH_CRITERIA_LIST = Collections.emptyList(); @Override public void configureDecentralised(DecentralisedConfigBuilder configBuilder) { diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java index 3a4153cbfe..bb995a948f 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java @@ -4,10 +4,6 @@ import org.junit.jupiter.api.Test; import uk.gov.hmcts.ccd.sdk.api.DecentralisedConfigBuilder; import uk.gov.hmcts.ccd.sdk.api.SearchCriteria.SearchCriteriaBuilder; -import uk.gov.hmcts.ccd.sdk.api.SearchCriteriaField; - -import java.util.List; - import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -27,10 +23,6 @@ void setUp() { void shouldConfigureSearchCriteria() { var configBuilder = mock(DecentralisedConfigBuilder.class); var searchCriteriaBuilder = mock(SearchCriteriaBuilder.class); - final var expectedFields = List.of( - SearchCriteriaField.builder().otherCaseReference("caseNameHmctsInternal").build(), - SearchCriteriaField.builder().otherCaseReference("caseNamePublic").build() - ); when(configBuilder.searchCriteria()).thenReturn(searchCriteriaBuilder); when(searchCriteriaBuilder.fields(anyList())).thenReturn(searchCriteriaBuilder); @@ -38,6 +30,6 @@ void shouldConfigureSearchCriteria() { underTest.configureDecentralised(configBuilder); verify(configBuilder).searchCriteria(); - verify(searchCriteriaBuilder).fields(expectedFields); + verify(searchCriteriaBuilder).fields(java.util.Collections.emptyList()); } } From 25250caf6c05ca4f886638d15d3a7c35c41009c0 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Tue, 14 Apr 2026 09:26:42 +0100 Subject: [PATCH 015/108] try --- .../java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index daabb76f2d..af2119e6b9 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -8,6 +8,7 @@ import uk.gov.hmcts.ccd.sdk.type.AddressUK; import uk.gov.hmcts.ccd.sdk.type.Document; import uk.gov.hmcts.ccd.sdk.type.ListValue; +import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; import uk.gov.hmcts.ccd.sdk.type.YesOrNo; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; @@ -87,6 +88,13 @@ public PCSCase getCase(CaseViewRequest request) { setMarkdownFields(pcsCase, hasUnsubmittedCaseData); caseFieldsView.setCaseFields(pcsCase); + pcsCase.setSearchCriteria(SearchCriteria.builder() + .otherCaseReferences(List.of( + ListValue.builder() + .id(UUID.randomUUID().toString()) + .value(caseReference + "-search") + .build())) + .build()); return pcsCase; } From df0a43cd34ee8c9501cfab993e59581329d651d5 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Tue, 14 Apr 2026 10:04:33 +0100 Subject: [PATCH 016/108] try with pcs --- charts/pcs-api/values.ccd.preview.template.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index caf70a73d6..2a802f9e84 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -193,10 +193,10 @@ xui-webapp: SERVICES_CCD_DATA_STORE_API: http://${SERVICE_NAME}-ccd-data-store-api SERVICES_TERMS_AND_CONDITIONS: http://xui-terms-and-conditions-aat.service.core-compute-aat.internal SERVICES_HEARINGS_COMPONENT_API: http://jurisdiction-hearings-api-aat.service.core-compute-aat.internal - JURISDICTIONS: PCS,CIVIL - GLOBAL_SEARCH_SERVICES: PCS,CIVIL - WA_SUPPORTED_JURISDICTIONS: PCS,CIVIL - STAFF_SUPPORTED_JURISDICTIONS: PCS + JURISDICTIONS: "pcs-${CHANGE_ID}",CIVIL + GLOBAL_SEARCH_SERVICES: "pcs-${CHANGE_ID}",CIVIL + WA_SUPPORTED_JURISDICTIONS: "pcs-${CHANGE_ID}",CIVIL + STAFF_SUPPORTED_JURISDICTIONS: "pcs-${CHANGE_ID}" FEATURE_REDIS_ENABLED: false REDISCLOUD_URL: http://dummyrediscloudurl FEATURE_APP_INSIGHTS_ENABLED: false From 4f231af436ac1bc36cdd07cc5b15ff67e88216ac Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Tue, 14 Apr 2026 10:26:20 +0100 Subject: [PATCH 017/108] revert --- charts/pcs-api/values.ccd.preview.template.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index 2a802f9e84..caf70a73d6 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -193,10 +193,10 @@ xui-webapp: SERVICES_CCD_DATA_STORE_API: http://${SERVICE_NAME}-ccd-data-store-api SERVICES_TERMS_AND_CONDITIONS: http://xui-terms-and-conditions-aat.service.core-compute-aat.internal SERVICES_HEARINGS_COMPONENT_API: http://jurisdiction-hearings-api-aat.service.core-compute-aat.internal - JURISDICTIONS: "pcs-${CHANGE_ID}",CIVIL - GLOBAL_SEARCH_SERVICES: "pcs-${CHANGE_ID}",CIVIL - WA_SUPPORTED_JURISDICTIONS: "pcs-${CHANGE_ID}",CIVIL - STAFF_SUPPORTED_JURISDICTIONS: "pcs-${CHANGE_ID}" + JURISDICTIONS: PCS,CIVIL + GLOBAL_SEARCH_SERVICES: PCS,CIVIL + WA_SUPPORTED_JURISDICTIONS: PCS,CIVIL + STAFF_SUPPORTED_JURISDICTIONS: PCS FEATURE_REDIS_ENABLED: false REDISCLOUD_URL: http://dummyrediscloudurl FEATURE_APP_INSIGHTS_ENABLED: false From c3be642f45df4455ae9594f37d95f8869b1fbdb9 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Tue, 14 Apr 2026 12:28:12 +0100 Subject: [PATCH 018/108] fix try --- Jenkinsfile_CNP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 9fc8a49bcb..6dbfadb98c 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -53,7 +53,7 @@ withPipeline(type, product, component) { setPreviewEnvVars() if (githubApi.getLabelsbyPattern(env.BRANCH_NAME, "pr-values:ccd").size() > 0) { env.CCD_ENABLED = "true" - env.CASE_TYPE_SUFFIX="${CHANGE_ID}" + //env.CASE_TYPE_SUFFIX="${CHANGE_ID}" enableHighLevelDataSetup() } else { env.CCD_ENABLED = "false" From a9587164220441de6a1b5e9ef8979f838e6e4099 Mon Sep 17 00:00:00 2001 From: adusumillipraveen Date: Tue, 14 Apr 2026 12:34:22 +0100 Subject: [PATCH 019/108] fix --- charts/pcs-api/values.ccd.preview.template.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index caf70a73d6..cd57b21293 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -14,7 +14,6 @@ global: java: environment: - CASE_TYPE_SUFFIX: ${CHANGE_ID} PCS_DB_NAME: "{{ .Values.global.databaseNamePrefix }}pcs" PCS_DB_HOST: '{{ tpl .Values.global.postgresHostname $}}' PCS_DB_USER_NAME: "{{ .Values.global.postgresUsername}}" From 10c4367b7e50dccadbbfc097f1d17cbbb077b8ce Mon Sep 17 00:00:00 2001 From: toby-plunkett Date: Tue, 21 Apr 2026 12:42:56 +0100 Subject: [PATCH 020/108] testing --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53ebefd17e..55c9fc8f81 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Building and deploying the application ### Building the application - + The project uses [Gradle](https://gradle.org) as a build tool. It already contains `./gradlew` wrapper script, so there's no need to install gradle. From 15755424faeecb6f436437897eeba20387215c7b Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 22 Apr 2026 17:07:41 +0100 Subject: [PATCH 021/108] HDPI-6150 Whitelist pcs-api --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index 83b3e64ea2..dcefc4717e 100644 --- a/build.gradle +++ b/build.gradle @@ -537,6 +537,8 @@ tasks.withType(CftlibExec).configureEach { environment 'XUI_DOCUMENTS_API_V2', 'http://ccd-case-document-am-api-aat.service.core-compute-aat.internal' environment 'DATA_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,pcs_frontend,pcs_api' environment 'CCD_S2S-AUTHORISED_SERVICES_CASE_USER_ROLES', 'aac_manage_case_assignment,pcs_api' + environment 'DEFINITION_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,ccd_admin,jui_webapp,pui_webapp,' + + 'aac_manage_case_assignment,xui_webapp,am_org_role_mapping_service' } tasks.register('highLevelDataSetup', JavaExec) { From ba03bb699f7dfcc7d3a8e9a5c5eebcc2056e983b Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 22 Apr 2026 17:08:40 +0100 Subject: [PATCH 022/108] HDPI-6150 Whitelist pcs-api --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dcefc4717e..2bc65e052d 100644 --- a/build.gradle +++ b/build.gradle @@ -538,7 +538,7 @@ tasks.withType(CftlibExec).configureEach { environment 'DATA_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,pcs_frontend,pcs_api' environment 'CCD_S2S-AUTHORISED_SERVICES_CASE_USER_ROLES', 'aac_manage_case_assignment,pcs_api' environment 'DEFINITION_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,ccd_admin,jui_webapp,pui_webapp,' + - 'aac_manage_case_assignment,xui_webapp,am_org_role_mapping_service' + 'aac_manage_case_assignment,xui_webapp,am_org_role_mapping_service, pcs_api' } tasks.register('highLevelDataSetup', JavaExec) { From eb1f171ca758d0c4a59ac66b15fd7c610759983b Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 09:35:21 +0100 Subject: [PATCH 023/108] HDPI-6150 Whitelist pcs-api typo --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2bc65e052d..e7169c6929 100644 --- a/build.gradle +++ b/build.gradle @@ -538,7 +538,7 @@ tasks.withType(CftlibExec).configureEach { environment 'DATA_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,pcs_frontend,pcs_api' environment 'CCD_S2S-AUTHORISED_SERVICES_CASE_USER_ROLES', 'aac_manage_case_assignment,pcs_api' environment 'DEFINITION_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,ccd_admin,jui_webapp,pui_webapp,' + - 'aac_manage_case_assignment,xui_webapp,am_org_role_mapping_service, pcs_api' + 'aac_manage_case_assignment,xui_webapp,am_org_role_mapping_service,pcs_api' } tasks.register('highLevelDataSetup', JavaExec) { From 664ea4585e8735f8277d1dfd27c24c4b2eed7fc2 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 11:03:15 +0100 Subject: [PATCH 024/108] HDPI-6150 Adjust Helm chart to whitelist pcs --- charts/pcs-api/values.ccd.preview.template.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index fd85fd55a5..183e4c56d8 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -79,6 +79,7 @@ ccd: DEFINITION_STORE_DB_OPTIONS: "" ELASTIC_SEARCH_INDEX_SHARDS: 1 ELASTIC_SEARCH_INDEX_SHARDS_REPLICAS: 0 + DEFINITION_STORE_S2S_AUTHORISED_SERVICES: "ccd_data,ccd_gw,ccd_admin,jui_webapp,pui_webapp,aac_manage_case_assignment,xui_webapp,am_org_role_mapping_service,pcs_api" ingressHost: ccd-definition-store-${SERVICE_FQDN} keyVaults: ccd: From 503ea8e2da06e2cb6730bee187f735ac74ba736d Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 11:20:57 +0100 Subject: [PATCH 025/108] HDPI-6150 remove autoindex --- charts/pcs-api/values.ccd.preview.template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index 183e4c56d8..1598917911 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -165,7 +165,7 @@ ccd: - name: cluster.initial_master_nodes value: "" - name: action.auto_create_index - value: .security*,.watches,.triggered_watches,.watcher-history-*,.logstash_dead_letter,.ml*,global_search + value: .security*,.watches,.triggered_watches,.watcher-history-*,.logstash_dead_letter,.ml* persistence: enabled: false ingress: From 0936ad1f94ef8ef61fd87a7f7a14fd4e584c57fc Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 15:03:48 +0100 Subject: [PATCH 026/108] HDPI-6150 update pipeline to make the api call --- Jenkinsfile_CNP | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 9fc8a49bcb..2e54d8161d 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -115,6 +115,10 @@ withPipeline(type, product, component) { generateDefinitions(builder) } + afterSuccess('highleveldatasetup') { + triggerGlobalSearchIndex() + } + before('smoketest:aat') { env.CASE_TYPE_SUFFIX="staging" env.CCD_ENABLED = "true" @@ -167,6 +171,43 @@ def setPerftestEnvVars() { env.ENVIRONMENT= "perftest" } +def triggerGlobalSearchIndex() { + echo "Triggering global search index on ${env.DEFINITION_STORE_URL_BASE}" + + def s2sToken = sh( + script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ + -H 'Content-Type: application/json' \ + -d '{"microservice": "pcs_api"}'""", + returnStdout: true + ).trim() + + def idamToken = sh( + script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=password' \ + --data-urlencode 'username=${env.IDAM_SYSTEM_USERNAME}' \ + --data-urlencode 'password=${env.IDAM_SYSTEM_USER_PASSWORD}' \ + --data-urlencode 'client_id=pcs_api' \ + --data-urlencode 'client_secret=${env.PCS_API_IDAM_SECRET}' \ + --data-urlencode 'scope=openid profile roles' \ + | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, + returnStdout: true + ).trim() + + def status = sh( + script: """curl -s -o /dev/null -w "%{http_code}" -X POST ${env.DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index \ + -H "Authorization: Bearer ${idamToken}" \ + -H "ServiceAuthorization: Bearer ${s2sToken}" """, + returnStdout: true + ).trim() + + if (status == "201") { + echo "Global search index created successfully" + } else { + error "Global search index returned status ${status}" + } +} + def generateDefinitions(builder) { builder.gradle('--rerun-tasks generateCCDConfig') sh "./bin/create-xlsx.sh ${env.ENVIRONMENT}" From 4c0b41d9883d64e0895b4b47644a44046eecadb8 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 15:54:20 +0100 Subject: [PATCH 027/108] HDPI-6150 check env vars are set --- Jenkinsfile_CNP | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 2e54d8161d..144e4d5932 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -173,6 +173,11 @@ def setPerftestEnvVars() { def triggerGlobalSearchIndex() { echo "Triggering global search index on ${env.DEFINITION_STORE_URL_BASE}" + sh """ + echo "IDAM_SYSTEM_USERNAME set: \$([ -n "\${IDAM_SYSTEM_USERNAME}" ] && echo yes || echo no)" + echo "IDAM_SYSTEM_USER_PASSWORD set: \$([ -n "\${IDAM_SYSTEM_USER_PASSWORD}" ] && echo yes || echo no)" + echo "PCS_API_IDAM_SECRET set: \$([ -n "\${PCS_API_IDAM_SECRET}" ] && echo yes || echo no)" + """ def s2sToken = sh( script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ @@ -185,10 +190,10 @@ def triggerGlobalSearchIndex() { script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=password' \ - --data-urlencode 'username=${env.IDAM_SYSTEM_USERNAME}' \ - --data-urlencode 'password=${env.IDAM_SYSTEM_USER_PASSWORD}' \ + --data-urlencode "username=\${IDAM_SYSTEM_USERNAME}" \ + --data-urlencode "password=\${IDAM_SYSTEM_USER_PASSWORD}" \ --data-urlencode 'client_id=pcs_api' \ - --data-urlencode 'client_secret=${env.PCS_API_IDAM_SECRET}' \ + --data-urlencode "client_secret=\${PCS_API_IDAM_SECRET}" \ --data-urlencode 'scope=openid profile roles' \ | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, returnStdout: true From 3efafd2ec1273e4d18a987a135c8a9bc1ee538af Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 16:18:29 +0100 Subject: [PATCH 028/108] HDPI-6150 check env vars are set --- Jenkinsfile_CNP | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 144e4d5932..ef8597d540 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -173,11 +173,9 @@ def setPerftestEnvVars() { def triggerGlobalSearchIndex() { echo "Triggering global search index on ${env.DEFINITION_STORE_URL_BASE}" - sh """ - echo "IDAM_SYSTEM_USERNAME set: \$([ -n "\${IDAM_SYSTEM_USERNAME}" ] && echo yes || echo no)" - echo "IDAM_SYSTEM_USER_PASSWORD set: \$([ -n "\${IDAM_SYSTEM_USER_PASSWORD}" ] && echo yes || echo no)" - echo "PCS_API_IDAM_SECRET set: \$([ -n "\${PCS_API_IDAM_SECRET}" ] && echo yes || echo no)" - """ + echo "IDAM_SYSTEM_USERNAME length: ${env.IDAM_SYSTEM_USERNAME?.length()}" + echo "IDAM_SYSTEM_USER_PASSWORD length: ${env.IDAM_SYSTEM_USER_PASSWORD?.length()}" + echo "PCS_API_IDAM_SECRET length: ${env.PCS_API_IDAM_SECRET?.length()}" def s2sToken = sh( script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ @@ -186,18 +184,24 @@ def triggerGlobalSearchIndex() { returnStdout: true ).trim() - def idamToken = sh( - script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - --data-urlencode 'grant_type=password' \ - --data-urlencode "username=\${IDAM_SYSTEM_USERNAME}" \ - --data-urlencode "password=\${IDAM_SYSTEM_USER_PASSWORD}" \ - --data-urlencode 'client_id=pcs_api' \ - --data-urlencode "client_secret=\${PCS_API_IDAM_SECRET}" \ - --data-urlencode 'scope=openid profile roles' \ - | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, - returnStdout: true - ).trim() + def idamToken = withEnv([ + "IDAM_SYSTEM_USERNAME=${env.IDAM_SYSTEM_USERNAME}", + "IDAM_SYSTEM_USER_PASSWORD=${env.IDAM_SYSTEM_USER_PASSWORD}", + "PCS_API_IDAM_SECRET=${env.PCS_API_IDAM_SECRET}" + ]) { + sh( + script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=password' \ + --data-urlencode "username=\${IDAM_SYSTEM_USERNAME}" \ + --data-urlencode "password=\${IDAM_SYSTEM_USER_PASSWORD}" \ + --data-urlencode 'client_id=pcs_api' \ + --data-urlencode "client_secret=\${PCS_API_IDAM_SECRET}" \ + --data-urlencode 'scope=openid profile roles' \ + | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, + returnStdout: true + ).trim() + } def status = sh( script: """curl -s -o /dev/null -w "%{http_code}" -X POST ${env.DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index \ From 7c45241e79a70933861e9cf4a4d6f9b2338be53b Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 16:43:17 +0100 Subject: [PATCH 029/108] HDPI-6150 pull in vars from keyvault --- Jenkinsfile_CNP | 56 ++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index ef8597d540..ab8c039d9f 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -173,47 +173,47 @@ def setPerftestEnvVars() { def triggerGlobalSearchIndex() { echo "Triggering global search index on ${env.DEFINITION_STORE_URL_BASE}" - echo "IDAM_SYSTEM_USERNAME length: ${env.IDAM_SYSTEM_USERNAME?.length()}" - echo "IDAM_SYSTEM_USER_PASSWORD length: ${env.IDAM_SYSTEM_USER_PASSWORD?.length()}" - echo "PCS_API_IDAM_SECRET length: ${env.PCS_API_IDAM_SECRET?.length()}" - - def s2sToken = sh( - script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ - -H 'Content-Type: application/json' \ - -d '{"microservice": "pcs_api"}'""", - returnStdout: true - ).trim() - def idamToken = withEnv([ - "IDAM_SYSTEM_USERNAME=${env.IDAM_SYSTEM_USERNAME}", - "IDAM_SYSTEM_USER_PASSWORD=${env.IDAM_SYSTEM_USER_PASSWORD}", - "PCS_API_IDAM_SECRET=${env.PCS_API_IDAM_SECRET}" - ]) { - sh( + withAzureKeyvault( + azureKeyVaultSecrets: [ + [$class: 'AzureKeyVaultSecret', secretType: 'Secret', name: 'idam-system-user-name', version: '', envVariable: 'IDAM_SYSTEM_USERNAME'], + [$class: 'AzureKeyVaultSecret', secretType: 'Secret', name: 'idam-system-user-password', version: '', envVariable: 'IDAM_SYSTEM_USER_PASSWORD'], + [$class: 'AzureKeyVaultSecret', secretType: 'Secret', name: 'pcs-api-idam-secret', version: '', envVariable: 'PCS_API_IDAM_SECRET'] + ], + keyVaultURLOverride: "https://pcs-aat.vault.azure.net/" + ) { + def s2sToken = sh( + script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ + -H 'Content-Type: application/json' \ + -d '{"microservice": "pcs_api"}'""", + returnStdout: true + ).trim() + + def idamToken = sh( script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=password' \ --data-urlencode "username=\${IDAM_SYSTEM_USERNAME}" \ --data-urlencode "password=\${IDAM_SYSTEM_USER_PASSWORD}" \ - --data-urlencode 'client_id=pcs_api' \ + --data-urlencode 'client_id=pcs-api' \ --data-urlencode "client_secret=\${PCS_API_IDAM_SECRET}" \ --data-urlencode 'scope=openid profile roles' \ | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, returnStdout: true ).trim() - } - def status = sh( - script: """curl -s -o /dev/null -w "%{http_code}" -X POST ${env.DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index \ - -H "Authorization: Bearer ${idamToken}" \ - -H "ServiceAuthorization: Bearer ${s2sToken}" """, - returnStdout: true - ).trim() + def status = sh( + script: """curl -s -o /dev/null -w "%{http_code}" -X POST ${env.DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index \ + -H "Authorization: Bearer ${idamToken}" \ + -H "ServiceAuthorization: Bearer ${s2sToken}" """, + returnStdout: true + ).trim() - if (status == "201") { - echo "Global search index created successfully" - } else { - error "Global search index returned status ${status}" + if (status == "201") { + echo "Global search index created successfully" + } else { + error "Global search index returned status ${status}" + } } } From 8c4a32a00271d0aeef47f34a2455bdfac04c705f Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 23 Apr 2026 17:23:53 +0100 Subject: [PATCH 030/108] HDPI-6150 remove ccd definition store var from local --- build.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.gradle b/build.gradle index e7169c6929..83b3e64ea2 100644 --- a/build.gradle +++ b/build.gradle @@ -537,8 +537,6 @@ tasks.withType(CftlibExec).configureEach { environment 'XUI_DOCUMENTS_API_V2', 'http://ccd-case-document-am-api-aat.service.core-compute-aat.internal' environment 'DATA_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,pcs_frontend,pcs_api' environment 'CCD_S2S-AUTHORISED_SERVICES_CASE_USER_ROLES', 'aac_manage_case_assignment,pcs_api' - environment 'DEFINITION_STORE_S2S_AUTHORISED_SERVICES', 'ccd_data,ccd_gw,ccd_admin,jui_webapp,pui_webapp,' + - 'aac_manage_case_assignment,xui_webapp,am_org_role_mapping_service,pcs_api' } tasks.register('highLevelDataSetup', JavaExec) { From 48996734c3d74f733745e56cfd93ab5913cc577f Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 09:25:45 +0100 Subject: [PATCH 031/108] HDPI-6150 remove whitespace --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55c9fc8f81..53ebefd17e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Building and deploying the application ### Building the application - + The project uses [Gradle](https://gradle.org) as a build tool. It already contains `./gradlew` wrapper script, so there's no need to install gradle. From 58ce009be7cebfdf79fe83da4ba637c299215c25 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 11:20:46 +0100 Subject: [PATCH 032/108] HDPI-6150 only trigger GS indexing on PR --- Jenkinsfile_CNP | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index ab8c039d9f..7a4a19cfa8 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -116,7 +116,9 @@ withPipeline(type, product, component) { } afterSuccess('highleveldatasetup') { - triggerGlobalSearchIndex() + onPR { + triggerGlobalSearchIndex() + } } before('smoketest:aat') { From f074b27db407a02c66ac4ad16159b082e76ee8b8 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 14:00:20 +0100 Subject: [PATCH 033/108] HDPI-6150 Move ES Index to before smoke tests to access secrets --- Jenkinsfile_CNP | 75 ++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 7a4a19cfa8..0a9cf5c716 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -115,8 +115,8 @@ withPipeline(type, product, component) { generateDefinitions(builder) } - afterSuccess('highleveldatasetup') { - onPR { + before('smoketest:preview') { + if (githubApi.getLabelsbyPattern(env.BRANCH_NAME, "pr-values:ccd").size() > 0) { triggerGlobalSearchIndex() } } @@ -176,46 +176,37 @@ def setPerftestEnvVars() { def triggerGlobalSearchIndex() { echo "Triggering global search index on ${env.DEFINITION_STORE_URL_BASE}" - withAzureKeyvault( - azureKeyVaultSecrets: [ - [$class: 'AzureKeyVaultSecret', secretType: 'Secret', name: 'idam-system-user-name', version: '', envVariable: 'IDAM_SYSTEM_USERNAME'], - [$class: 'AzureKeyVaultSecret', secretType: 'Secret', name: 'idam-system-user-password', version: '', envVariable: 'IDAM_SYSTEM_USER_PASSWORD'], - [$class: 'AzureKeyVaultSecret', secretType: 'Secret', name: 'pcs-api-idam-secret', version: '', envVariable: 'PCS_API_IDAM_SECRET'] - ], - keyVaultURLOverride: "https://pcs-aat.vault.azure.net/" - ) { - def s2sToken = sh( - script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ - -H 'Content-Type: application/json' \ - -d '{"microservice": "pcs_api"}'""", - returnStdout: true - ).trim() - - def idamToken = sh( - script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - --data-urlencode 'grant_type=password' \ - --data-urlencode "username=\${IDAM_SYSTEM_USERNAME}" \ - --data-urlencode "password=\${IDAM_SYSTEM_USER_PASSWORD}" \ - --data-urlencode 'client_id=pcs-api' \ - --data-urlencode "client_secret=\${PCS_API_IDAM_SECRET}" \ - --data-urlencode 'scope=openid profile roles' \ - | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, - returnStdout: true - ).trim() - - def status = sh( - script: """curl -s -o /dev/null -w "%{http_code}" -X POST ${env.DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index \ - -H "Authorization: Bearer ${idamToken}" \ - -H "ServiceAuthorization: Bearer ${s2sToken}" """, - returnStdout: true - ).trim() - - if (status == "201") { - echo "Global search index created successfully" - } else { - error "Global search index returned status ${status}" - } + def s2sToken = sh( + script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ + -H 'Content-Type: application/json' \ + -d '{"microservice": "pcs_api"}'""", + returnStdout: true + ).trim() + + def idamToken = sh( + script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=password' \ + --data-urlencode "username=\${IDAM_SYSTEM_USERNAME}" \ + --data-urlencode "password=\${IDAM_SYSTEM_USER_PASSWORD}" \ + --data-urlencode 'client_id=pcs-api' \ + --data-urlencode "client_secret=\${PCS_API_IDAM_SECRET}" \ + --data-urlencode 'scope=openid profile roles' \ + | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, + returnStdout: true + ).trim() + + def status = sh( + script: """curl -s -o /dev/null -w "%{http_code}" -X POST ${env.DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index \ + -H "Authorization: Bearer ${idamToken}" \ + -H "ServiceAuthorization: Bearer ${s2sToken}" """, + returnStdout: true + ).trim() + + if (status == "201") { + echo "Global search index created successfully" + } else { + error "Global search index returned status ${status}" } } From 17fa2fe45e2e06f87f709057ab16848d4ed967fb Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 14:39:12 +0100 Subject: [PATCH 034/108] HDPI-6150 Move ES Index to it's own script --- Jenkinsfile_CNP | 39 +----------------------------- bin/trigger-global-search-index.sh | 27 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 38 deletions(-) create mode 100644 bin/trigger-global-search-index.sh diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 0a9cf5c716..2b92aacd49 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -117,7 +117,7 @@ withPipeline(type, product, component) { before('smoketest:preview') { if (githubApi.getLabelsbyPattern(env.BRANCH_NAME, "pr-values:ccd").size() > 0) { - triggerGlobalSearchIndex() + sh "./bin/trigger-global-search-index.sh" } } @@ -173,43 +173,6 @@ def setPerftestEnvVars() { env.ENVIRONMENT= "perftest" } -def triggerGlobalSearchIndex() { - echo "Triggering global search index on ${env.DEFINITION_STORE_URL_BASE}" - - def s2sToken = sh( - script: """curl -s -X POST ${env.IDAM_S2S_AUTH_URL}/testing-support/lease \ - -H 'Content-Type: application/json' \ - -d '{"microservice": "pcs_api"}'""", - returnStdout: true - ).trim() - - def idamToken = sh( - script: """curl -s -X POST '${env.IDAM_API_URL}/o/token' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - --data-urlencode 'grant_type=password' \ - --data-urlencode "username=\${IDAM_SYSTEM_USERNAME}" \ - --data-urlencode "password=\${IDAM_SYSTEM_USER_PASSWORD}" \ - --data-urlencode 'client_id=pcs-api' \ - --data-urlencode "client_secret=\${PCS_API_IDAM_SECRET}" \ - --data-urlencode 'scope=openid profile roles' \ - | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\" """, - returnStdout: true - ).trim() - - def status = sh( - script: """curl -s -o /dev/null -w "%{http_code}" -X POST ${env.DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index \ - -H "Authorization: Bearer ${idamToken}" \ - -H "ServiceAuthorization: Bearer ${s2sToken}" """, - returnStdout: true - ).trim() - - if (status == "201") { - echo "Global search index created successfully" - } else { - error "Global search index returned status ${status}" - } -} - def generateDefinitions(builder) { builder.gradle('--rerun-tasks generateCCDConfig') sh "./bin/create-xlsx.sh ${env.ENVIRONMENT}" diff --git a/bin/trigger-global-search-index.sh b/bin/trigger-global-search-index.sh new file mode 100644 index 0000000000..cb61eccf88 --- /dev/null +++ b/bin/trigger-global-search-index.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -ex + +S2S_TOKEN=$(curl -s -X POST "${IDAM_S2S_AUTH_URL}/testing-support/lease" \ + -H 'Content-Type: application/json' \ + -d '{"microservice": "pcs_api"}') + +IDAM_TOKEN=$(curl -s -X POST "${IDAM_API_URL}/o/token" \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=password' \ + --data-urlencode "username=${IDAM_SYSTEM_USERNAME}" \ + --data-urlencode "password=${IDAM_SYSTEM_USER_PASSWORD}" \ + --data-urlencode 'client_id=pcs-api' \ + --data-urlencode "client_secret=${PCS_API_IDAM_SECRET}" \ + --data-urlencode 'scope=openid profile roles' \ + | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") + +STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST "${DEFINITION_STORE_URL_BASE}/elastic-support/global-search/index" \ + -H "Authorization: Bearer ${IDAM_TOKEN}" \ + -H "ServiceAuthorization: Bearer ${S2S_TOKEN}") + +if [ "$STATUS" != "201" ]; then + echo "ERROR: Global search index returned status ${STATUS}" + exit 1 +fi + +echo "Global search index created successfully" From d9438278741454bd8265fc7800a14b3774bc856c Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 14:58:41 +0100 Subject: [PATCH 035/108] HDPI-6150 Make script executable --- bin/trigger-global-search-index.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/trigger-global-search-index.sh diff --git a/bin/trigger-global-search-index.sh b/bin/trigger-global-search-index.sh old mode 100644 new mode 100755 From ed7adb0f0f6d7f317929ad1d0e18d05801cbc849 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 15:58:06 +0100 Subject: [PATCH 036/108] HDPI-6150 Fix merge conflict --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index daa97e662a..a0c1783ec5 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -88,8 +88,6 @@ public PCSCase getCase(CaseViewRequest request) { setMarkdownFields(pcsCase, hasUnsubmittedCaseData); enforcementOrderMediator.handleEnforcementRequirements(caseReference, pcsCase); - caseFieldsView.setCaseFields(pcsCase); - caseFieldsView.setCaseFields(pcsCase); pcsCase.setSearchCriteria(SearchCriteria.builder() .otherCaseReferences(List.of( From f27b9fa0aa4680cfa046eeb993d62c7f8afec680 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 16:30:23 +0100 Subject: [PATCH 037/108] HDPI-6150 Reverting SearchCritera change to see if GS still works --- .../java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index a0c1783ec5..5e1f003669 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -89,13 +89,9 @@ public PCSCase getCase(CaseViewRequest request) { enforcementOrderMediator.handleEnforcementRequirements(caseReference, pcsCase); caseFieldsView.setCaseFields(pcsCase); - pcsCase.setSearchCriteria(SearchCriteria.builder() - .otherCaseReferences(List.of( - ListValue.builder() - .id(UUID.randomUUID().toString()) - .value(caseReference + "-search") - .build())) - .build()); + + //allows indexing for Global Search + pcsCase.setSearchCriteria(new SearchCriteria()); return pcsCase; } From e8c35b5002110b3b31b50bdab59dcb1b84379575 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 17:13:28 +0100 Subject: [PATCH 038/108] HDPI-6150 Reverting Uneeded changes --- Jenkinsfile_CNP | 1 - .../gov/hmcts/reform/pcs/ccd/domain/PCSCase.java | 1 - .../reform/pcs/globalsearch/SearchCriteria.java | 1 + .../pcs/globalsearch/SearchCriteriaTest.java | 14 +++++++++----- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index ac36408d9f..75f4487276 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -53,7 +53,6 @@ withPipeline(type, product, component) { setPreviewEnvVars() if (githubApi.getLabelsbyPattern(env.BRANCH_NAME, "pr-values:ccd").size() > 0) { env.CCD_ENABLED = "true" - //env.CASE_TYPE_SUFFIX="${CHANGE_ID}" enableHighLevelDataSetup() } else { env.CCD_ENABLED = "false" diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index cdc37f6603..73b1da8b85 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -10,7 +10,6 @@ import uk.gov.hmcts.ccd.sdk.type.CaseLocation; import uk.gov.hmcts.ccd.sdk.type.CaseLink; import uk.gov.hmcts.ccd.sdk.type.ComponentLauncher; -import uk.gov.hmcts.ccd.sdk.type.CaseLocation; import uk.gov.hmcts.ccd.sdk.type.Document; import uk.gov.hmcts.ccd.sdk.type.DynamicList; import uk.gov.hmcts.ccd.sdk.type.FieldType; diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java index 1adb1fbaa2..e3e78a98e5 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.List; + @Slf4j @Component @AllArgsConstructor diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java index bb995a948f..44458e6ba6 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteriaTest.java @@ -1,14 +1,18 @@ package uk.gov.hmcts.reform.pcs.globalsearch; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import uk.gov.hmcts.ccd.sdk.api.DecentralisedConfigBuilder; -import uk.gov.hmcts.ccd.sdk.api.SearchCriteria.SearchCriteriaBuilder; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import uk.gov.hmcts.ccd.sdk.api.DecentralisedConfigBuilder; +import uk.gov.hmcts.ccd.sdk.api.SearchCriteria.SearchCriteriaBuilder; + +import java.util.Collections; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + class SearchCriteriaTest { private SearchCriteria underTest; @@ -30,6 +34,6 @@ void shouldConfigureSearchCriteria() { underTest.configureDecentralised(configBuilder); verify(configBuilder).searchCriteria(); - verify(searchCriteriaBuilder).fields(java.util.Collections.emptyList()); + verify(searchCriteriaBuilder).fields(Collections.emptyList()); } } From 56dd3f7bdc0485a99eb7719848edc90e82b80c76 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 17:14:34 +0100 Subject: [PATCH 039/108] HDPI-6150 Reverting Uneeded changes --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index 73b1da8b85..e51fb4f5e0 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -7,9 +7,9 @@ import uk.gov.hmcts.ccd.sdk.External; import uk.gov.hmcts.ccd.sdk.api.CCD; import uk.gov.hmcts.ccd.sdk.type.AddressUK; -import uk.gov.hmcts.ccd.sdk.type.CaseLocation; import uk.gov.hmcts.ccd.sdk.type.CaseLink; import uk.gov.hmcts.ccd.sdk.type.ComponentLauncher; +import uk.gov.hmcts.ccd.sdk.type.CaseLocation; import uk.gov.hmcts.ccd.sdk.type.Document; import uk.gov.hmcts.ccd.sdk.type.DynamicList; import uk.gov.hmcts.ccd.sdk.type.FieldType; From 48e914a3a0cb252b6a513e68c870878a5e024b65 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 24 Apr 2026 17:38:19 +0100 Subject: [PATCH 040/108] HDPI-6150 Check if env.CASE_TYPE_SUFFIX is needed --- Jenkinsfile_CNP | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 75f4487276..2b92aacd49 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -53,6 +53,7 @@ withPipeline(type, product, component) { setPreviewEnvVars() if (githubApi.getLabelsbyPattern(env.BRANCH_NAME, "pr-values:ccd").size() > 0) { env.CCD_ENABLED = "true" + env.CASE_TYPE_SUFFIX="${CHANGE_ID}" enableHighLevelDataSetup() } else { env.CCD_ENABLED = "false" From ee5f22c9675e3d7af2564704a42051463ab86114 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 27 Apr 2026 09:42:25 +0100 Subject: [PATCH 041/108] HDPI-6150 Confirm removal is needed --- Jenkinsfile_CNP | 1 - 1 file changed, 1 deletion(-) diff --git a/Jenkinsfile_CNP b/Jenkinsfile_CNP index 2b92aacd49..75f4487276 100644 --- a/Jenkinsfile_CNP +++ b/Jenkinsfile_CNP @@ -53,7 +53,6 @@ withPipeline(type, product, component) { setPreviewEnvVars() if (githubApi.getLabelsbyPattern(env.BRANCH_NAME, "pr-values:ccd").size() > 0) { env.CCD_ENABLED = "true" - env.CASE_TYPE_SUFFIX="${CHANGE_ID}" enableHighLevelDataSetup() } else { env.CCD_ENABLED = "false" From f64b2afa2182a279311f9455c9f2faf5e92219ba Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 27 Apr 2026 16:57:49 +0100 Subject: [PATCH 042/108] HDPI-4161 merge conflicts --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 2 -- src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index 185b0ca6de..5e1f003669 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -90,8 +90,6 @@ public PCSCase getCase(CaseViewRequest request) { caseFieldsView.setCaseFields(pcsCase); - caseFieldsView.setCaseFields(pcsCase); - //allows indexing for Global Search pcsCase.setSearchCriteria(new SearchCriteria()); diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index aba35664b1..e51fb4f5e0 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -575,5 +575,4 @@ public class PCSCase { @CCD(searchable = false, access = {ClaimantAccess.class}) private YesOrNo showConfirmEvictionJourney; - } From 74aa9526882d34d1038ee5cabf3f6667b01f6887 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 28 Apr 2026 12:30:21 +0100 Subject: [PATCH 043/108] HDPI-4161 Update tests to handle internal and external roles differing --- .../pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index 895a3bcfd5..ee13ffe9e4 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -37,10 +37,10 @@ void setUp() { @Test void shouldRegisterAccessProfileForEveryUserRole() { underTest.configure(configBuilder); - stream(UserRole.values()).forEach(userRole -> { + String expectedExternalRole = ExternalUserRole.forCcdRole(userRole).getRole(); verify(configBuilder).caseRoleToAccessProfile(argThat( - externalRole -> externalRole.getRole().endsWith(userRole.getRole()) + externalRole -> externalRole.getRole().equals(expectedExternalRole) )); verify(accessProfileBuilder).accessProfiles(userRole.getRole()); }); From ce7a25d127c1c878219861537a43fc66974c9410 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 28 Apr 2026 14:00:43 +0100 Subject: [PATCH 044/108] HDPI-4161 Switch to better naming scheme --- .../{ExternalUserRole.java => CcdRole.java} | 8 ++++---- .../pcs/ccd/accesscontrol/RoleToAccessProfiles.java | 6 +++--- .../ccd/accesscontrol/RoleToAccessProfilesTest.java | 11 +++++++---- 3 files changed, 14 insertions(+), 11 deletions(-) rename src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/{ExternalUserRole.java => CcdRole.java} (74%) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/CcdRole.java similarity index 74% rename from src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java rename to src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/CcdRole.java index 47643a072e..1872a4fbe2 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/CcdRole.java @@ -2,16 +2,16 @@ import uk.gov.hmcts.ccd.sdk.api.HasRole; -public final class ExternalUserRole implements HasRole { +public final class CcdRole implements HasRole { private final UserRole ccdUserRole; - private ExternalUserRole(UserRole ccdUserRole) { + private CcdRole(UserRole ccdUserRole) { this.ccdUserRole = ccdUserRole; } - public static ExternalUserRole forCcdRole(UserRole ccdRole) { - return new ExternalUserRole(ccdRole); + public static CcdRole forCcdRole(UserRole ccdRole) { + return new CcdRole(ccdRole); } @Override diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java index 67128c0a83..0a91c0847a 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java @@ -9,14 +9,14 @@ import java.util.Arrays; @Component -public class RoleToAccessProfiles implements CCDConfig { +public class RoleToAccessProfiles implements CCDConfig { @Override - public void configure(ConfigBuilder configBuilder) { + public void configure(ConfigBuilder configBuilder) { Arrays.stream(UserRole.values()) .forEach(userRole -> configBuilder - .caseRoleToAccessProfile(ExternalUserRole.forCcdRole(userRole)) + .caseRoleToAccessProfile(CcdRole.forCcdRole(userRole)) .accessProfiles(userRole.getRole()) .build() ); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index ee13ffe9e4..a72eece2cb 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -21,10 +21,10 @@ class RoleToAccessProfilesTest { @Mock - private ConfigBuilder configBuilder; + private ConfigBuilder configBuilder; @Mock - private CaseRoleToAccessProfileBuilder accessProfileBuilder; + private CaseRoleToAccessProfileBuilder accessProfileBuilder; private final RoleToAccessProfiles underTest = new RoleToAccessProfiles(); @@ -38,11 +38,14 @@ void setUp() { void shouldRegisterAccessProfileForEveryUserRole() { underTest.configure(configBuilder); stream(UserRole.values()).forEach(userRole -> { - String expectedExternalRole = ExternalUserRole.forCcdRole(userRole).getRole(); + String expectedExternalRole = CcdRole.forCcdRole(userRole).getRole(); verify(configBuilder).caseRoleToAccessProfile(argThat( externalRole -> externalRole.getRole().equals(expectedExternalRole) )); - verify(accessProfileBuilder).accessProfiles(userRole.getRole()); + int sharedRoleCount = (int) stream(UserRole.values()) + .filter(r -> r.getRole().equals(userRole.getRole())) + .count(); + verify(accessProfileBuilder, times(sharedRoleCount)).accessProfiles(userRole.getRole()); }); verify(accessProfileBuilder, times(UserRole.values().length)).build(); } From d181dea08064bd62becbd471a6c2c8c0e103f34e Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 28 Apr 2026 16:29:43 +0100 Subject: [PATCH 045/108] HDPI-4161 Make adjustment to role config --- .../reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java | 6 +++--- .../pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java index 0a91c0847a..e825a99d00 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java @@ -9,14 +9,14 @@ import java.util.Arrays; @Component -public class RoleToAccessProfiles implements CCDConfig { +public class RoleToAccessProfiles implements CCDConfig { @Override - public void configure(ConfigBuilder configBuilder) { + public void configure(ConfigBuilder configBuilder) { Arrays.stream(UserRole.values()) .forEach(userRole -> configBuilder - .caseRoleToAccessProfile(CcdRole.forCcdRole(userRole)) + .caseRoleToAccessProfile(userRole) .accessProfiles(userRole.getRole()) .build() ); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index a72eece2cb..003eac86d4 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -21,10 +21,10 @@ class RoleToAccessProfilesTest { @Mock - private ConfigBuilder configBuilder; + private ConfigBuilder configBuilder; @Mock - private CaseRoleToAccessProfileBuilder accessProfileBuilder; + private CaseRoleToAccessProfileBuilder accessProfileBuilder; private final RoleToAccessProfiles underTest = new RoleToAccessProfiles(); From 2fd8d595660858ef443baba76a0ec65b434bad54 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 29 Apr 2026 16:58:13 +0100 Subject: [PATCH 046/108] HDPI-4161 Make adjustment to role tests --- .../reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java | 6 +++--- .../pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java index e825a99d00..0a91c0847a 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java @@ -9,14 +9,14 @@ import java.util.Arrays; @Component -public class RoleToAccessProfiles implements CCDConfig { +public class RoleToAccessProfiles implements CCDConfig { @Override - public void configure(ConfigBuilder configBuilder) { + public void configure(ConfigBuilder configBuilder) { Arrays.stream(UserRole.values()) .forEach(userRole -> configBuilder - .caseRoleToAccessProfile(userRole) + .caseRoleToAccessProfile(CcdRole.forCcdRole(userRole)) .accessProfiles(userRole.getRole()) .build() ); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index 003eac86d4..a72eece2cb 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -21,10 +21,10 @@ class RoleToAccessProfilesTest { @Mock - private ConfigBuilder configBuilder; + private ConfigBuilder configBuilder; @Mock - private CaseRoleToAccessProfileBuilder accessProfileBuilder; + private CaseRoleToAccessProfileBuilder accessProfileBuilder; private final RoleToAccessProfiles underTest = new RoleToAccessProfiles(); From 69557c0e763e5f0f34471f01923f2fa70afa1c99 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 30 Apr 2026 10:36:46 +0100 Subject: [PATCH 047/108] HDPI-4161 add gs_profile access profile to config --- src/cftlib/java/uk/gov/hmcts/reform/pcs/CftlibConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cftlib/java/uk/gov/hmcts/reform/pcs/CftlibConfig.java b/src/cftlib/java/uk/gov/hmcts/reform/pcs/CftlibConfig.java index de1806dc37..0e8f4b36e8 100644 --- a/src/cftlib/java/uk/gov/hmcts/reform/pcs/CftlibConfig.java +++ b/src/cftlib/java/uk/gov/hmcts/reform/pcs/CftlibConfig.java @@ -70,6 +70,7 @@ private void createAccessProfiles(CFTLib lib) { roleNames.add("caseworker"); roleNames.add("caseworker-ras-validation"); + roleNames.add("GS_profile"); lib.createRoles(roleNames.toArray(new String[0])); } From 640630ce586e26cf000e6219ad61d2cdbfda7ada Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 30 Apr 2026 13:44:35 +0100 Subject: [PATCH 048/108] HDPI-4161 add gs_profile access profile to config --- .../gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java index cc5b6482f0..ccbafa9394 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java @@ -23,7 +23,8 @@ public class HighLevelDataSetupApp extends DataLoaderToDefinitionStore { new CcdRoleConfig("caseworker-pcs", "PUBLIC"), new CcdRoleConfig("caseworker-pcs-solicitor", "PUBLIC"), new CcdRoleConfig("citizen", "PUBLIC"), - new CcdRoleConfig("caseworker-ras-validation", "PUBLIC") + new CcdRoleConfig("caseworker-ras-validation", "PUBLIC"), + new CcdRoleConfig("GS_profile", "PUBLIC") }; From 5bc345fb857d3b0e36d40525f2e96d121c8cf48b Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 30 Apr 2026 16:00:22 +0100 Subject: [PATCH 049/108] HDPI-4161 revert renaming --- .../accesscontrol/{CcdRole.java => ExternalUserRole.java} | 8 ++++---- .../reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java | 8 ++++++++ .../pcs/ccd/accesscontrol/RoleToAccessProfiles.java | 6 +++--- .../pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java | 6 +++--- 4 files changed, 18 insertions(+), 10 deletions(-) rename src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/{CcdRole.java => ExternalUserRole.java} (74%) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/CcdRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java similarity index 74% rename from src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/CcdRole.java rename to src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java index 1872a4fbe2..47643a072e 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/CcdRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java @@ -2,16 +2,16 @@ import uk.gov.hmcts.ccd.sdk.api.HasRole; -public final class CcdRole implements HasRole { +public final class ExternalUserRole implements HasRole { private final UserRole ccdUserRole; - private CcdRole(UserRole ccdUserRole) { + private ExternalUserRole(UserRole ccdUserRole) { this.ccdUserRole = ccdUserRole; } - public static CcdRole forCcdRole(UserRole ccdRole) { - return new CcdRole(ccdRole); + public static ExternalUserRole forCcdRole(UserRole ccdRole) { + return new ExternalUserRole(ccdRole); } @Override diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index c59b5fee79..676fef3a55 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,6 +1,8 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_CASE_WORKER; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_SOLICITOR; import uk.gov.hmcts.ccd.sdk.api.HasAccessControl; import uk.gov.hmcts.ccd.sdk.api.HasRole; @@ -13,6 +15,12 @@ public class GlobalSearchAccess implements HasAccessControl { @Override public SetMultimap getGrants() { SetMultimap grants = HashMultimap.create(); + grants.putAll(PCS_CASE_WORKER, Permission.CRUD); + + /* + * Remove before release + */ + grants.putAll(PCS_SOLICITOR, Permission.CRUD); grants.put(HMCTS_STAFF, Permission.R); return grants; diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java index 0a91c0847a..67128c0a83 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java @@ -9,14 +9,14 @@ import java.util.Arrays; @Component -public class RoleToAccessProfiles implements CCDConfig { +public class RoleToAccessProfiles implements CCDConfig { @Override - public void configure(ConfigBuilder configBuilder) { + public void configure(ConfigBuilder configBuilder) { Arrays.stream(UserRole.values()) .forEach(userRole -> configBuilder - .caseRoleToAccessProfile(CcdRole.forCcdRole(userRole)) + .caseRoleToAccessProfile(ExternalUserRole.forCcdRole(userRole)) .accessProfiles(userRole.getRole()) .build() ); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index a72eece2cb..467a1c6b57 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -21,10 +21,10 @@ class RoleToAccessProfilesTest { @Mock - private ConfigBuilder configBuilder; + private ConfigBuilder configBuilder; @Mock - private CaseRoleToAccessProfileBuilder accessProfileBuilder; + private CaseRoleToAccessProfileBuilder accessProfileBuilder; private final RoleToAccessProfiles underTest = new RoleToAccessProfiles(); @@ -38,7 +38,7 @@ void setUp() { void shouldRegisterAccessProfileForEveryUserRole() { underTest.configure(configBuilder); stream(UserRole.values()).forEach(userRole -> { - String expectedExternalRole = CcdRole.forCcdRole(userRole).getRole(); + String expectedExternalRole = ExternalUserRole.forCcdRole(userRole).getRole(); verify(configBuilder).caseRoleToAccessProfile(argThat( externalRole -> externalRole.getRole().equals(expectedExternalRole) )); From 251b9d45f1c2eeb3d97bf46774ef12e398f89e35 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 1 May 2026 14:17:27 +0100 Subject: [PATCH 050/108] HDPI-4161 add test --- .../accesscontrol/RoleToAccessProfilesTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index 467a1c6b57..303eebf1b0 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -11,6 +11,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.State; import static java.util.Arrays.stream; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.times; @@ -34,6 +35,19 @@ void setUp() { when(accessProfileBuilder.accessProfiles(any(String.class))).thenReturn(accessProfileBuilder); } + //Tests that accessing UserRoles via ExternalRole wrapper uses prefix for Idam roles + @Test + void shouldAddIdamPrefixForIdamRolesOnly() { + stream(UserRole.values()).forEach(role -> { + String ccdRole = ExternalUserRole.forCcdRole(role).getRole(); + if (role.getRoleType() == RoleType.IDAM) { + assertThat(ccdRole).startsWith("idam:"); + } else { + assertThat(ccdRole).doesNotStartWith("idam:"); + } + }); + } + @Test void shouldRegisterAccessProfileForEveryUserRole() { underTest.configure(configBuilder); From 461be8ff46fb9e99c270482092fe5b1e08e89874 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 1 May 2026 14:48:18 +0100 Subject: [PATCH 051/108] HDPI-4161 remove unnecessary stubbing --- .../pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index 303eebf1b0..d6aa7f4322 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -1,6 +1,5 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -29,12 +28,6 @@ class RoleToAccessProfilesTest { private final RoleToAccessProfiles underTest = new RoleToAccessProfiles(); - @BeforeEach - void setUp() { - when(configBuilder.caseRoleToAccessProfile(any())).thenReturn(accessProfileBuilder); - when(accessProfileBuilder.accessProfiles(any(String.class))).thenReturn(accessProfileBuilder); - } - //Tests that accessing UserRoles via ExternalRole wrapper uses prefix for Idam roles @Test void shouldAddIdamPrefixForIdamRolesOnly() { @@ -50,6 +43,8 @@ void shouldAddIdamPrefixForIdamRolesOnly() { @Test void shouldRegisterAccessProfileForEveryUserRole() { + when(configBuilder.caseRoleToAccessProfile(any())).thenReturn(accessProfileBuilder); + when(accessProfileBuilder.accessProfiles(any(String.class))).thenReturn(accessProfileBuilder); underTest.configure(configBuilder); stream(UserRole.values()).forEach(userRole -> { String expectedExternalRole = ExternalUserRole.forCcdRole(userRole).getRole(); From cccb80741522d9545b9f7eb0a2eb98666523687d Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 5 May 2026 11:43:05 +0100 Subject: [PATCH 052/108] HDPI-4172 Add GS_profile to Auth state and case type --- .../java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java index f88892c858..56cec36809 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java @@ -7,6 +7,7 @@ import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.CitizenAccess; import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.ClaimantAccess; import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.DefendantAccess; +import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.GlobalSearchAccess; import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.RasValidationAccess; /** @@ -19,21 +20,22 @@ public enum State { @CCD( label = "Awaiting Submission to HMCTS", - access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class}, + access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class, GlobalSearchAccess.class}, hint = "${caseTitleMarkdown}" ) AWAITING_SUBMISSION_TO_HMCTS, @CCD( label = "Pending Case Issued", - access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class}, + access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class, GlobalSearchAccess.class}, hint = "${caseTitleMarkdown}" ) PENDING_CASE_ISSUED, @CCD( label = "Case Issued", - access = {CaseworkerReadAccess.class, ClaimantAccess.class, DefendantAccess.class, RasValidationAccess.class}, + access = {CaseworkerReadAccess.class, ClaimantAccess.class, DefendantAccess.class, RasValidationAccess.class, + GlobalSearchAccess.class}, hint = "${caseTitleMarkdown}" ) CASE_ISSUED From 30fc5d827a613f7f1393714b2d3bea3e3526a78b Mon Sep 17 00:00:00 2001 From: taleb Date: Mon, 18 May 2026 08:31:04 +0100 Subject: [PATCH 053/108] HDPI-5335: add roles to globalSearch access profile --- .../ccd/accesscontrol/ExternalUserRole.java | 5 +---- .../ccd/accesscontrol/GlobalSearchAccess.java | 18 +++++++++--------- .../accesscontrol/RoleToAccessProfiles.java | 9 ++++----- .../reform/pcs/ccd/accesscontrol/UserRole.java | 17 +++++++++++------ .../RoleToAccessProfilesTest.java | 5 +---- 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java index 47643a072e..e902062679 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java @@ -16,11 +16,8 @@ public static ExternalUserRole forCcdRole(UserRole ccdRole) { @Override public String getRole() { - String name = ccdUserRole.getExternalRoleName() != null - ? ccdUserRole.getExternalRoleName() - : ccdUserRole.getRole(); String rolePrefix = (ccdUserRole.getRoleType() == RoleType.IDAM) ? "idam:" : ""; - return rolePrefix + name; + return rolePrefix + ccdUserRole.getRole(); } @Override diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index 676fef3a55..602b4c8e45 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,8 +1,9 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_CASE_WORKER; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_SOLICITOR; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_CTSC; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_JUDICIARY; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_LEGAL_OPERATIONS; import uk.gov.hmcts.ccd.sdk.api.HasAccessControl; import uk.gov.hmcts.ccd.sdk.api.HasRole; @@ -12,16 +13,15 @@ import com.google.common.collect.SetMultimap; public class GlobalSearchAccess implements HasAccessControl { + @Override public SetMultimap getGrants() { SetMultimap grants = HashMultimap.create(); - grants.putAll(PCS_CASE_WORKER, Permission.CRUD); - /* - * Remove before release - */ - grants.putAll(PCS_SOLICITOR, Permission.CRUD); - grants.put(HMCTS_STAFF, Permission.R); + grants.put(HMCTS_ADMIN, Permission.R); + grants.put(HMCTS_CTSC, Permission.R); + grants.put(HMCTS_LEGAL_OPERATIONS, Permission.R); + grants.put(HMCTS_JUDICIARY, Permission.R); return grants; } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java index 67128c0a83..d5159f67d4 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java @@ -14,11 +14,10 @@ public class RoleToAccessProfiles implements CCDConfig configBuilder) { Arrays.stream(UserRole.values()) - .forEach(userRole -> - configBuilder - .caseRoleToAccessProfile(ExternalUserRole.forCcdRole(userRole)) - .accessProfiles(userRole.getRole()) - .build() + .forEach(userRole -> configBuilder + .caseRoleToAccessProfile(ExternalUserRole.forCcdRole(userRole)) + .accessProfiles(userRole.getAccessProfiles()) + .build() ); } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index dce66d9daf..0b93d381ca 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -5,6 +5,7 @@ import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; +import java.util.List; import java.util.Set; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; @@ -25,23 +26,27 @@ public enum UserRole implements HasRole { PCS_SOLICITOR("caseworker-pcs-solicitor", Permission.CRU, IDAM), RAS_VALIDATOR("caseworker-ras-validation", Set.of(R), IDAM), DEFENDANT_SOLICITOR("[DEFENDANTSOLICITOR]", Permission.CRU, RAS), - HMCTS_STAFF("GS_profile", Set.of(R), RAS, "hmcts-staff"), - HMCTS_JUDICIARY("GS_profile", Set.of(R), RAS, "hmcts-judiciary"); + + HMCTS_CTSC("hmcts-ctsc", Set.of(R), RAS, "GS_profile"), + HMCTS_ADMIN("hmcts-admin", Set.of(R), RAS, "GS_profile"), + HMCTS_LEGAL_OPERATIONS("hmcts-legal-operations", Set.of(R), RAS, "GS_profile"), + HMCTS_JUDICIARY("hmcts-judiciary", Set.of(R), RAS, "GS_profile"); + @JsonValue private final String role; private final Set caseTypePermissions; private final RoleType roleType; - private final String externalRoleName; + private final String[] accessProfiles; UserRole(String role, Set permissions, RoleType roleType) { - this(role, permissions, roleType, null); + this(role, permissions, roleType, role); } - UserRole(String role, Set permissions, RoleType roleType, String externalRoleName) { + UserRole(String role, Set permissions, RoleType roleType, String... accessProfiles) { this.role = role; this.caseTypePermissions = permissions; this.roleType = roleType; - this.externalRoleName = externalRoleName; + this.accessProfiles = accessProfiles; } public String getCaseTypePermissions() { diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index d6aa7f4322..418104018a 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -51,10 +51,7 @@ void shouldRegisterAccessProfileForEveryUserRole() { verify(configBuilder).caseRoleToAccessProfile(argThat( externalRole -> externalRole.getRole().equals(expectedExternalRole) )); - int sharedRoleCount = (int) stream(UserRole.values()) - .filter(r -> r.getRole().equals(userRole.getRole())) - .count(); - verify(accessProfileBuilder, times(sharedRoleCount)).accessProfiles(userRole.getRole()); + verify(accessProfileBuilder).accessProfiles(userRole.getAccessProfiles()); }); verify(accessProfileBuilder, times(UserRole.values().length)).build(); } From e3f2689f66fbd17749e171676dfe82a39f5b02eb Mon Sep 17 00:00:00 2001 From: taleb Date: Mon, 18 May 2026 08:31:54 +0100 Subject: [PATCH 054/108] HDPI-5335: add claimant searchParty fields :wq :wq :wq :wq :wq i d e :q :eq --- .../pcs/globalsearch/SearchCriteria.java | 5 +-- .../reform/pcs/globalsearch/SearchParty.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java index e3e78a98e5..57e7b1f9eb 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java @@ -1,5 +1,7 @@ package uk.gov.hmcts.reform.pcs.globalsearch; +import static java.util.Collections.emptyList; + import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -10,7 +12,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; -import java.util.Collections; import java.util.List; @@ -19,7 +20,7 @@ @AllArgsConstructor public class SearchCriteria implements CCDConfig { - private static final List SEARCH_CRITERIA_LIST = Collections.emptyList(); + private static final List SEARCH_CRITERIA_LIST = emptyList(); @Override public void configureDecentralised(DecentralisedConfigBuilder configBuilder) { diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java new file mode 100644 index 0000000000..506aa7abe8 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java @@ -0,0 +1,32 @@ +package uk.gov.hmcts.reform.pcs.globalsearch; + +import org.springframework.stereotype.Component; +import uk.gov.hmcts.ccd.sdk.api.CCDConfig; +import uk.gov.hmcts.ccd.sdk.api.ConfigBuilder; +import uk.gov.hmcts.ccd.sdk.api.SearchPartyField; +import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; +import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.domain.State; + +import java.util.List; + +import static java.util.List.of; + +@Component +public class SearchParty implements CCDConfig { + + private static final List SEARCH_PARTY_LIST = of( + SearchPartyField.builder() + // TODO: replace firstName with a computed fullName field on Party + .searchPartyName("fallbackClaimantName") + .caseTypeId("PCS") + .searchPartyEmailAddress("claimantContactEmail") + .build() + ); + + @Override + public void configure(final ConfigBuilder configBuilder) { + configBuilder.searchParty() + .fields(SEARCH_PARTY_LIST); + } +} From f7e74a49d5441a8073833f59b51ce6bf355e1f9e Mon Sep 17 00:00:00 2001 From: taleb Date: Mon, 18 May 2026 11:44:14 +0100 Subject: [PATCH 055/108] HDPI-5335: fix failing test --- .../uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java | 1 - .../pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index 0b93d381ca..4c18fe6064 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -5,7 +5,6 @@ import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; -import java.util.List; import java.util.Set; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index 418104018a..9df97125a0 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -28,7 +29,6 @@ class RoleToAccessProfilesTest { private final RoleToAccessProfiles underTest = new RoleToAccessProfiles(); - //Tests that accessing UserRoles via ExternalRole wrapper uses prefix for Idam roles @Test void shouldAddIdamPrefixForIdamRolesOnly() { stream(UserRole.values()).forEach(role -> { @@ -45,13 +45,15 @@ void shouldAddIdamPrefixForIdamRolesOnly() { void shouldRegisterAccessProfileForEveryUserRole() { when(configBuilder.caseRoleToAccessProfile(any())).thenReturn(accessProfileBuilder); when(accessProfileBuilder.accessProfiles(any(String.class))).thenReturn(accessProfileBuilder); + underTest.configure(configBuilder); + stream(UserRole.values()).forEach(userRole -> { String expectedExternalRole = ExternalUserRole.forCcdRole(userRole).getRole(); verify(configBuilder).caseRoleToAccessProfile(argThat( externalRole -> externalRole.getRole().equals(expectedExternalRole) )); - verify(accessProfileBuilder).accessProfiles(userRole.getAccessProfiles()); + verify(accessProfileBuilder, atLeastOnce()).accessProfiles(userRole.getAccessProfiles()); }); verify(accessProfileBuilder, times(UserRole.values().length)).build(); } From 1d98450e2a88b137b523a4a954bf65cd28668925 Mon Sep 17 00:00:00 2001 From: taleb Date: Mon, 18 May 2026 12:28:15 +0100 Subject: [PATCH 056/108] HDPI-5335: add GS roles to HighLevelDataSetupApp --- .../hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java index ccbafa9394..e1a73d3419 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java @@ -24,7 +24,11 @@ public class HighLevelDataSetupApp extends DataLoaderToDefinitionStore { new CcdRoleConfig("caseworker-pcs-solicitor", "PUBLIC"), new CcdRoleConfig("citizen", "PUBLIC"), new CcdRoleConfig("caseworker-ras-validation", "PUBLIC"), - new CcdRoleConfig("GS_profile", "PUBLIC") + new CcdRoleConfig("GS_profile", "PUBLIC"), + new CcdRoleConfig("hmcts-ctsc", "PUBLIC"), + new CcdRoleConfig("hmcts-admin", "PUBLIC"), + new CcdRoleConfig("hmcts-legal-operations", "PUBLIC"), + new CcdRoleConfig("hmcts-judiciary", "PUBLIC") }; From ab3a79593987f63dd309d77ba2b9dfaf3556ee65 Mon Sep 17 00:00:00 2001 From: taleb Date: Mon, 18 May 2026 10:01:26 +0100 Subject: [PATCH 057/108] HDPI-5335: fix failing test --- .../pcs/ccd/accesscontrol/GlobalSearchAccessTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java index e5204d72f3..2ede32d2f3 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java @@ -4,7 +4,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_CTSC; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_JUDICIARY; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_LEGAL_OPERATIONS; import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; @@ -27,7 +30,10 @@ void setUp() { @Test void shouldGrantGlobalSearchAccess() { SetMultimap grants = underTest.getGrants(); - assertThat(grants.asMap()).contains(entry(HMCTS_STAFF, Set.of(R))); + assertThat(grants.asMap()).contains(entry(HMCTS_ADMIN, Set.of(R))); + assertThat(grants.asMap()).contains(entry(HMCTS_CTSC, Set.of(R))); + assertThat(grants.asMap()).contains(entry(HMCTS_LEGAL_OPERATIONS, Set.of(R))); + assertThat(grants.asMap()).contains(entry(HMCTS_JUDICIARY, Set.of(R))); } } From 91629e7c2c14fb67e28c9314da194e1b260c52cf Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 18 May 2026 16:59:31 +0100 Subject: [PATCH 058/108] Revert "HDPI-5335: fix failing test" This reverts commit ab3a79593987f63dd309d77ba2b9dfaf3556ee65. --- .../pcs/ccd/accesscontrol/GlobalSearchAccessTest.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java index 2ede32d2f3..e5204d72f3 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java @@ -4,10 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_CTSC; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_JUDICIARY; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_LEGAL_OPERATIONS; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; @@ -30,10 +27,7 @@ void setUp() { @Test void shouldGrantGlobalSearchAccess() { SetMultimap grants = underTest.getGrants(); - assertThat(grants.asMap()).contains(entry(HMCTS_ADMIN, Set.of(R))); - assertThat(grants.asMap()).contains(entry(HMCTS_CTSC, Set.of(R))); - assertThat(grants.asMap()).contains(entry(HMCTS_LEGAL_OPERATIONS, Set.of(R))); - assertThat(grants.asMap()).contains(entry(HMCTS_JUDICIARY, Set.of(R))); + assertThat(grants.asMap()).contains(entry(HMCTS_STAFF, Set.of(R))); } } From 95b1f74c3a78b03a786cc28bba1e5e08b3c4c70c Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 18 May 2026 16:59:48 +0100 Subject: [PATCH 059/108] Revert "HDPI-5335: add GS roles to HighLevelDataSetupApp" This reverts commit 1d98450e2a88b137b523a4a954bf65cd28668925. --- .../hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java index e1a73d3419..ccbafa9394 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java @@ -24,11 +24,7 @@ public class HighLevelDataSetupApp extends DataLoaderToDefinitionStore { new CcdRoleConfig("caseworker-pcs-solicitor", "PUBLIC"), new CcdRoleConfig("citizen", "PUBLIC"), new CcdRoleConfig("caseworker-ras-validation", "PUBLIC"), - new CcdRoleConfig("GS_profile", "PUBLIC"), - new CcdRoleConfig("hmcts-ctsc", "PUBLIC"), - new CcdRoleConfig("hmcts-admin", "PUBLIC"), - new CcdRoleConfig("hmcts-legal-operations", "PUBLIC"), - new CcdRoleConfig("hmcts-judiciary", "PUBLIC") + new CcdRoleConfig("GS_profile", "PUBLIC") }; From 8bd2f08a074c907eaa7e19abbdac82d263c91ed8 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 18 May 2026 16:59:54 +0100 Subject: [PATCH 060/108] Revert "HDPI-5335: fix failing test" This reverts commit f7e74a49d5441a8073833f59b51ce6bf355e1f9e. --- .../uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java | 1 + .../pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index 4c18fe6064..0b93d381ca 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -5,6 +5,7 @@ import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; +import java.util.List; import java.util.Set; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index 9df97125a0..418104018a 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -13,7 +13,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,6 +28,7 @@ class RoleToAccessProfilesTest { private final RoleToAccessProfiles underTest = new RoleToAccessProfiles(); + //Tests that accessing UserRoles via ExternalRole wrapper uses prefix for Idam roles @Test void shouldAddIdamPrefixForIdamRolesOnly() { stream(UserRole.values()).forEach(role -> { @@ -45,15 +45,13 @@ void shouldAddIdamPrefixForIdamRolesOnly() { void shouldRegisterAccessProfileForEveryUserRole() { when(configBuilder.caseRoleToAccessProfile(any())).thenReturn(accessProfileBuilder); when(accessProfileBuilder.accessProfiles(any(String.class))).thenReturn(accessProfileBuilder); - underTest.configure(configBuilder); - stream(UserRole.values()).forEach(userRole -> { String expectedExternalRole = ExternalUserRole.forCcdRole(userRole).getRole(); verify(configBuilder).caseRoleToAccessProfile(argThat( externalRole -> externalRole.getRole().equals(expectedExternalRole) )); - verify(accessProfileBuilder, atLeastOnce()).accessProfiles(userRole.getAccessProfiles()); + verify(accessProfileBuilder).accessProfiles(userRole.getAccessProfiles()); }); verify(accessProfileBuilder, times(UserRole.values().length)).build(); } From 69108b6623ff65fe3c2bf21d5157482f9a7b8788 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 18 May 2026 16:59:59 +0100 Subject: [PATCH 061/108] Revert "HDPI-5335: add claimant searchParty fields" This reverts commit e3f2689f66fbd17749e171676dfe82a39f5b02eb. --- .../pcs/globalsearch/SearchCriteria.java | 5 ++- .../reform/pcs/globalsearch/SearchParty.java | 32 ------------------- 2 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java index 57e7b1f9eb..e3e78a98e5 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchCriteria.java @@ -1,7 +1,5 @@ package uk.gov.hmcts.reform.pcs.globalsearch; -import static java.util.Collections.emptyList; - import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -12,6 +10,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; +import java.util.Collections; import java.util.List; @@ -20,7 +19,7 @@ @AllArgsConstructor public class SearchCriteria implements CCDConfig { - private static final List SEARCH_CRITERIA_LIST = emptyList(); + private static final List SEARCH_CRITERIA_LIST = Collections.emptyList(); @Override public void configureDecentralised(DecentralisedConfigBuilder configBuilder) { diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java deleted file mode 100644 index 506aa7abe8..0000000000 --- a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java +++ /dev/null @@ -1,32 +0,0 @@ -package uk.gov.hmcts.reform.pcs.globalsearch; - -import org.springframework.stereotype.Component; -import uk.gov.hmcts.ccd.sdk.api.CCDConfig; -import uk.gov.hmcts.ccd.sdk.api.ConfigBuilder; -import uk.gov.hmcts.ccd.sdk.api.SearchPartyField; -import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; -import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; -import uk.gov.hmcts.reform.pcs.ccd.domain.State; - -import java.util.List; - -import static java.util.List.of; - -@Component -public class SearchParty implements CCDConfig { - - private static final List SEARCH_PARTY_LIST = of( - SearchPartyField.builder() - // TODO: replace firstName with a computed fullName field on Party - .searchPartyName("fallbackClaimantName") - .caseTypeId("PCS") - .searchPartyEmailAddress("claimantContactEmail") - .build() - ); - - @Override - public void configure(final ConfigBuilder configBuilder) { - configBuilder.searchParty() - .fields(SEARCH_PARTY_LIST); - } -} From 5366bb5bd7d64b18e835a6ec2f00fe4ecf61ba30 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 18 May 2026 17:00:07 +0100 Subject: [PATCH 062/108] Revert "HDPI-5335: add roles to globalSearch access profile" This reverts commit 30fc5d827a613f7f1393714b2d3bea3e3526a78b. --- .../ccd/accesscontrol/ExternalUserRole.java | 5 ++++- .../ccd/accesscontrol/GlobalSearchAccess.java | 18 +++++++++--------- .../accesscontrol/RoleToAccessProfiles.java | 9 +++++---- .../reform/pcs/ccd/accesscontrol/UserRole.java | 17 ++++++----------- .../RoleToAccessProfilesTest.java | 5 ++++- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java index e902062679..47643a072e 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java @@ -16,8 +16,11 @@ public static ExternalUserRole forCcdRole(UserRole ccdRole) { @Override public String getRole() { + String name = ccdUserRole.getExternalRoleName() != null + ? ccdUserRole.getExternalRoleName() + : ccdUserRole.getRole(); String rolePrefix = (ccdUserRole.getRoleType() == RoleType.IDAM) ? "idam:" : ""; - return rolePrefix + ccdUserRole.getRole(); + return rolePrefix + name; } @Override diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index 602b4c8e45..676fef3a55 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,9 +1,8 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_CTSC; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_JUDICIARY; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_LEGAL_OPERATIONS; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_CASE_WORKER; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_SOLICITOR; import uk.gov.hmcts.ccd.sdk.api.HasAccessControl; import uk.gov.hmcts.ccd.sdk.api.HasRole; @@ -13,15 +12,16 @@ import com.google.common.collect.SetMultimap; public class GlobalSearchAccess implements HasAccessControl { - @Override public SetMultimap getGrants() { SetMultimap grants = HashMultimap.create(); + grants.putAll(PCS_CASE_WORKER, Permission.CRUD); - grants.put(HMCTS_ADMIN, Permission.R); - grants.put(HMCTS_CTSC, Permission.R); - grants.put(HMCTS_LEGAL_OPERATIONS, Permission.R); - grants.put(HMCTS_JUDICIARY, Permission.R); + /* + * Remove before release + */ + grants.putAll(PCS_SOLICITOR, Permission.CRUD); + grants.put(HMCTS_STAFF, Permission.R); return grants; } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java index d5159f67d4..67128c0a83 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java @@ -14,10 +14,11 @@ public class RoleToAccessProfiles implements CCDConfig configBuilder) { Arrays.stream(UserRole.values()) - .forEach(userRole -> configBuilder - .caseRoleToAccessProfile(ExternalUserRole.forCcdRole(userRole)) - .accessProfiles(userRole.getAccessProfiles()) - .build() + .forEach(userRole -> + configBuilder + .caseRoleToAccessProfile(ExternalUserRole.forCcdRole(userRole)) + .accessProfiles(userRole.getRole()) + .build() ); } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index 0b93d381ca..dce66d9daf 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -5,7 +5,6 @@ import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; -import java.util.List; import java.util.Set; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; @@ -26,27 +25,23 @@ public enum UserRole implements HasRole { PCS_SOLICITOR("caseworker-pcs-solicitor", Permission.CRU, IDAM), RAS_VALIDATOR("caseworker-ras-validation", Set.of(R), IDAM), DEFENDANT_SOLICITOR("[DEFENDANTSOLICITOR]", Permission.CRU, RAS), - - HMCTS_CTSC("hmcts-ctsc", Set.of(R), RAS, "GS_profile"), - HMCTS_ADMIN("hmcts-admin", Set.of(R), RAS, "GS_profile"), - HMCTS_LEGAL_OPERATIONS("hmcts-legal-operations", Set.of(R), RAS, "GS_profile"), - HMCTS_JUDICIARY("hmcts-judiciary", Set.of(R), RAS, "GS_profile"); - + HMCTS_STAFF("GS_profile", Set.of(R), RAS, "hmcts-staff"), + HMCTS_JUDICIARY("GS_profile", Set.of(R), RAS, "hmcts-judiciary"); @JsonValue private final String role; private final Set caseTypePermissions; private final RoleType roleType; - private final String[] accessProfiles; + private final String externalRoleName; UserRole(String role, Set permissions, RoleType roleType) { - this(role, permissions, roleType, role); + this(role, permissions, roleType, null); } - UserRole(String role, Set permissions, RoleType roleType, String... accessProfiles) { + UserRole(String role, Set permissions, RoleType roleType, String externalRoleName) { this.role = role; this.caseTypePermissions = permissions; this.roleType = roleType; - this.accessProfiles = accessProfiles; + this.externalRoleName = externalRoleName; } public String getCaseTypePermissions() { diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index 418104018a..d6aa7f4322 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -51,7 +51,10 @@ void shouldRegisterAccessProfileForEveryUserRole() { verify(configBuilder).caseRoleToAccessProfile(argThat( externalRole -> externalRole.getRole().equals(expectedExternalRole) )); - verify(accessProfileBuilder).accessProfiles(userRole.getAccessProfiles()); + int sharedRoleCount = (int) stream(UserRole.values()) + .filter(r -> r.getRole().equals(userRole.getRole())) + .count(); + verify(accessProfileBuilder, times(sharedRoleCount)).accessProfiles(userRole.getRole()); }); verify(accessProfileBuilder, times(UserRole.values().length)).build(); } From e05ac2523f3a6936a0b9d36731bd377694ebda0b Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 18 May 2026 17:06:12 +0100 Subject: [PATCH 063/108] HDPI-5335 Testing revert of Role changes --- bin/staff-idam-ids.json | 3 ++- .../reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java | 4 ++-- .../gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java | 7 +++++-- .../pcs/ccd/accesscontrol/GlobalSearchAccessTest.java | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/bin/staff-idam-ids.json b/bin/staff-idam-ids.json index d195fac523..6907e4f81b 100644 --- a/bin/staff-idam-ids.json +++ b/bin/staff-idam-ids.json @@ -1,5 +1,6 @@ { "userIds": [ - "4ea633f5-615b-4428-8d0c-748190d5035c" + "4ea633f5-615b-4428-8d0c-748190d5035c", + "b4cb1fc9-c6d7-42e9-a329-b9883417a7f6" ] } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index 676fef3a55..c844087986 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,6 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_CASE_WORKER; import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_SOLICITOR; @@ -21,7 +21,7 @@ public SetMultimap getGrants() { * Remove before release */ grants.putAll(PCS_SOLICITOR, Permission.CRUD); - grants.put(HMCTS_STAFF, Permission.R); + grants.put(HMCTS_ADMIN, Permission.R); return grants; } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index dce66d9daf..5521858cc1 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -25,8 +25,11 @@ public enum UserRole implements HasRole { PCS_SOLICITOR("caseworker-pcs-solicitor", Permission.CRU, IDAM), RAS_VALIDATOR("caseworker-ras-validation", Set.of(R), IDAM), DEFENDANT_SOLICITOR("[DEFENDANTSOLICITOR]", Permission.CRU, RAS), - HMCTS_STAFF("GS_profile", Set.of(R), RAS, "hmcts-staff"), - HMCTS_JUDICIARY("GS_profile", Set.of(R), RAS, "hmcts-judiciary"); + HMCTS_ADMIN("GS_profile", Set.of(R), RAS, "hmcts-admin"), + HMCTS_JUDICIARY("GS_profile", Set.of(R), RAS, "hmcts-judiciary"), + HMCTS_CTSC("GS_profile", Set.of(R), RAS, "hmcts-ctsc"), + HMCTS_LEGAL_OPERATIONS("GS_profile", Set.of(R), RAS, "hmcts-legal-operations"),; + @JsonValue private final String role; private final Set caseTypePermissions; diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java index e5204d72f3..9d6e3c2062 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_STAFF; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; @@ -27,7 +27,7 @@ void setUp() { @Test void shouldGrantGlobalSearchAccess() { SetMultimap grants = underTest.getGrants(); - assertThat(grants.asMap()).contains(entry(HMCTS_STAFF, Set.of(R))); + assertThat(grants.asMap()).contains(entry(HMCTS_ADMIN, Set.of(R))); } } From 349214594be67d8641d83ab8f408f5e9fdb636a3 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 19 May 2026 13:40:41 +0100 Subject: [PATCH 064/108] HDPI-5335 Add tab only shown to GS profile --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index 9fa96bc2dd..b9644ffe5d 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -101,6 +101,10 @@ public void configure(final ConfigBuilder builder) { .field(PCSCase::getLinkedCasesComponentLauncher, null, "#ARGUMENT(LinkedCases)") .field(PCSCase::getCaseLinks, "LinkedCasesComponentLauncher!=\"\"", "#ARGUMENT(LinkedCases)"); + builder.tab("TestingTab", "TestingTab") + .forRoles(UserRole.HMCTS_ADMIN) + .field(PCSCase::getPropertyAddress); + buildCasePartiesTab(builder); configureCaseFileCategories(builder); From 0979654e7f6033e2109ebf12c7692f6adbee350c Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 19 May 2026 13:55:48 +0100 Subject: [PATCH 065/108] HDPI-5335 Add tab only shown to GS profile --- src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java index 131bf2efc9..13469a7ace 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java @@ -69,6 +69,7 @@ void shouldConfigureCaseTypeTabs() { final Tab.TabBuilder caseLinksTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); final Tab.TabBuilder caseFileViewTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); final Tab.TabBuilder casePartiesTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); + final Tab.TabBuilder testingTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); final Search.SearchBuilder searchBuilder = Search.SearchBuilder.builder(PCSCase.class, utils); final SearchCases.SearchCasesBuilder searchCasesBuilder = @@ -86,6 +87,7 @@ void shouldConfigureCaseTypeTabs() { when(builder.tab("caseLinks", "Linked Cases")).thenReturn(caseLinksTabBuilder); when(builder.tab("caseFileView", "Case File View")).thenReturn(caseFileViewTabBuilder); when(builder.tab("caseParties", "Case Parties")).thenReturn(casePartiesTabBuilder); + when(builder.tab("TestingTab", "TestingTab")).thenReturn(casePartiesTabBuilder); when(builder.categories(UserRole.PCS_SOLICITOR)) .thenReturn(CaseCategory.CaseCategoryBuilder.builder(UserRole.PCS_SOLICITOR)); From 291508a033cbd6092e075fdef811c44229ef8a48 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 19 May 2026 15:54:16 +0100 Subject: [PATCH 066/108] HDPI-5335 update staff supported juridictions --- charts/pcs-api/values.ccd.preview.template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index ccd9fa660f..c998a02a11 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -199,7 +199,7 @@ xui-webapp: JURISDICTIONS: PCS,CIVIL GLOBAL_SEARCH_SERVICES: PCS,CIVIL WA_SUPPORTED_JURISDICTIONS: PCS,CIVIL - STAFF_SUPPORTED_JURISDICTIONS: PCS + STAFF_SUPPORTED_JURISDICTIONS: PCS,CIVIL,SSCS FEATURE_REDIS_ENABLED: false REDISCLOUD_URL: http://dummyrediscloudurl FEATURE_APP_INSIGHTS_ENABLED: false From 2219262efe5859dc13ac41c8cf43010c612cd62d Mon Sep 17 00:00:00 2001 From: taleb Date: Tue, 19 May 2026 17:07:16 +0100 Subject: [PATCH 067/108] HDPI-5335:n update jurisdictions --- charts/pcs-api/values.ccd.preview.template.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/pcs-api/values.ccd.preview.template.yaml b/charts/pcs-api/values.ccd.preview.template.yaml index c998a02a11..1a4fbc291d 100644 --- a/charts/pcs-api/values.ccd.preview.template.yaml +++ b/charts/pcs-api/values.ccd.preview.template.yaml @@ -196,9 +196,9 @@ xui-webapp: SERVICES_CCD_DATA_STORE_API: http://${SERVICE_NAME}-ccd-data-store-api SERVICES_TERMS_AND_CONDITIONS: http://xui-terms-and-conditions-aat.service.core-compute-aat.internal SERVICES_HEARINGS_COMPONENT_API: http://jurisdiction-hearings-api-aat.service.core-compute-aat.internal - JURISDICTIONS: PCS,CIVIL - GLOBAL_SEARCH_SERVICES: PCS,CIVIL - WA_SUPPORTED_JURISDICTIONS: PCS,CIVIL + JURISDICTIONS: PCS + GLOBAL_SEARCH_SERVICES: PCS,CIVIL,SSCS + WA_SUPPORTED_JURISDICTIONS: PCS,CIVIL,SSCS STAFF_SUPPORTED_JURISDICTIONS: PCS,CIVIL,SSCS FEATURE_REDIS_ENABLED: false REDISCLOUD_URL: http://dummyrediscloudurl From 033c8e792c5c9afafe37886b8806435d6583aec1 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 20 May 2026 12:03:25 +0100 Subject: [PATCH 068/108] HDPI-5335 Add roles for HLD from sscs to test globalsearch --- .../pcs/ccd/config/HighLevelDataSetupApp.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java index ccbafa9394..d3cd4f343f 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/config/HighLevelDataSetupApp.java @@ -22,8 +22,26 @@ public class HighLevelDataSetupApp extends DataLoaderToDefinitionStore { private static final CcdRoleConfig[] CCD_ROLES = { new CcdRoleConfig("caseworker-pcs", "PUBLIC"), new CcdRoleConfig("caseworker-pcs-solicitor", "PUBLIC"), - new CcdRoleConfig("citizen", "PUBLIC"), new CcdRoleConfig("caseworker-ras-validation", "PUBLIC"), + new CcdRoleConfig("citizen", "PUBLIC"), + new CcdRoleConfig("caseworker", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-systemupdate", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-anonymouscitizen", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-callagent", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-judge", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-judge-salaried", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-clerk", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-dwpresponsewriter", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-registrar", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-superuser", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-teamleader", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-panelmember", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-bulkscan", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-pcqextractor", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-hmrcresponsewriter", "PUBLIC"), + new CcdRoleConfig("caseworker-sscs-ibcaresponsewriter", "PUBLIC"), + new CcdRoleConfig("caseworker-wa-task-configuration", "RESTRICTED"), new CcdRoleConfig("GS_profile", "PUBLIC") }; From ae344996e168904f418ea18d9d1781ff961e5882 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 20 May 2026 15:20:11 +0100 Subject: [PATCH 069/108] HDPI-5335 Cleanup code --- bin/staff-idam-ids.json | 3 +-- .../reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/bin/staff-idam-ids.json b/bin/staff-idam-ids.json index 6907e4f81b..d195fac523 100644 --- a/bin/staff-idam-ids.json +++ b/bin/staff-idam-ids.json @@ -1,6 +1,5 @@ { "userIds": [ - "4ea633f5-615b-4428-8d0c-748190d5035c", - "b4cb1fc9-c6d7-42e9-a329-b9883417a7f6" + "4ea633f5-615b-4428-8d0c-748190d5035c" ] } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index c844087986..879a5b3c94 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,8 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_CASE_WORKER; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.PCS_SOLICITOR; import uk.gov.hmcts.ccd.sdk.api.HasAccessControl; import uk.gov.hmcts.ccd.sdk.api.HasRole; @@ -15,12 +13,8 @@ public class GlobalSearchAccess implements HasAccessControl { @Override public SetMultimap getGrants() { SetMultimap grants = HashMultimap.create(); - grants.putAll(PCS_CASE_WORKER, Permission.CRUD); - /* - * Remove before release - */ - grants.putAll(PCS_SOLICITOR, Permission.CRUD); + //assigns access profile "GS_profile" which is shared between multiple UserRole's. grants.put(HMCTS_ADMIN, Permission.R); return grants; From 47e1d25162fda9b8142f6c1fe76221bcdeeaa692 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 20 May 2026 17:03:28 +0100 Subject: [PATCH 070/108] HDPI-5335 Remove testing code --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index b9644ffe5d..9fa96bc2dd 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -101,10 +101,6 @@ public void configure(final ConfigBuilder builder) { .field(PCSCase::getLinkedCasesComponentLauncher, null, "#ARGUMENT(LinkedCases)") .field(PCSCase::getCaseLinks, "LinkedCasesComponentLauncher!=\"\"", "#ARGUMENT(LinkedCases)"); - builder.tab("TestingTab", "TestingTab") - .forRoles(UserRole.HMCTS_ADMIN) - .field(PCSCase::getPropertyAddress); - buildCasePartiesTab(builder); configureCaseFileCategories(builder); From a9de490dd8e751ef865e64ca7e066875d8a609d5 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 20 May 2026 17:20:23 +0100 Subject: [PATCH 071/108] HDPI-5335 Remove testing code --- src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java index 13469a7ace..131bf2efc9 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java @@ -69,7 +69,6 @@ void shouldConfigureCaseTypeTabs() { final Tab.TabBuilder caseLinksTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); final Tab.TabBuilder caseFileViewTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); final Tab.TabBuilder casePartiesTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder testingTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); final Search.SearchBuilder searchBuilder = Search.SearchBuilder.builder(PCSCase.class, utils); final SearchCases.SearchCasesBuilder searchCasesBuilder = @@ -87,7 +86,6 @@ void shouldConfigureCaseTypeTabs() { when(builder.tab("caseLinks", "Linked Cases")).thenReturn(caseLinksTabBuilder); when(builder.tab("caseFileView", "Case File View")).thenReturn(caseFileViewTabBuilder); when(builder.tab("caseParties", "Case Parties")).thenReturn(casePartiesTabBuilder); - when(builder.tab("TestingTab", "TestingTab")).thenReturn(casePartiesTabBuilder); when(builder.categories(UserRole.PCS_SOLICITOR)) .thenReturn(CaseCategory.CaseCategoryBuilder.builder(UserRole.PCS_SOLICITOR)); From af808a9255000b8c41e19b022c136a2f9e1d1035 Mon Sep 17 00:00:00 2001 From: taleb Date: Tue, 19 May 2026 23:42:34 +0100 Subject: [PATCH 072/108] HDPI-5335: add support for multi access profiles --- .../uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 14 +++--- .../pcs/ccd/accesscontrol/AccessProfile.java | 45 +++++++++++++++++++ .../ccd/accesscontrol/ExternalUserRole.java | 6 +-- .../ccd/accesscontrol/GlobalSearchAccess.java | 8 ++-- .../accesscontrol/RoleToAccessProfiles.java | 2 +- .../pcs/ccd/accesscontrol/RoleType.java | 13 +++++- .../pcs/ccd/accesscontrol/UserRole.java | 39 +++++++++------- .../hmcts/reform/pcs/ccd/CaseTypeTest.java | 43 +++++++++--------- .../accesscontrol/GlobalSearchAccessTest.java | 4 +- .../RoleToAccessProfilesTest.java | 6 +-- 10 files changed, 118 insertions(+), 62 deletions(-) create mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index 9fa96bc2dd..8e56a2f758 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -4,7 +4,7 @@ import org.springframework.stereotype.Component; import uk.gov.hmcts.ccd.sdk.api.CCDConfig; import uk.gov.hmcts.ccd.sdk.api.ConfigBuilder; -import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; +import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.AccessProfile; import uk.gov.hmcts.reform.pcs.ccd.domain.CaseFileCategory; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; @@ -18,7 +18,7 @@ * Setup some common possessions case type configuration. */ @Component -public class CaseType implements CCDConfig { +public class CaseType implements CCDConfig { private static final String CASE_TYPE_ID = "PCS"; private static final String CASE_TYPE_NAME = "Possession"; @@ -49,7 +49,7 @@ private static String withSuffix(String base, String separator) { } @Override - public void configure(final ConfigBuilder builder) { + public void configure(final ConfigBuilder builder) { builder.setCallbackHost(getenv().getOrDefault("CASE_API_URL", "http://localhost:3206")); builder.caseType(getCaseType(), getCaseTypeName(), CASE_TYPE_DESCRIPTION); @@ -97,7 +97,7 @@ public void configure(final ConfigBuilder builder) { .field(PCSCase::getCaseFileView, null, "#ARGUMENT(CaseFileView)"); builder.tab("caseLinks", "Linked Cases") - .forRoles(UserRole.PCS_SOLICITOR) + .forRoles(AccessProfile.PCS_SOLICITOR) .field(PCSCase::getLinkedCasesComponentLauncher, null, "#ARGUMENT(LinkedCases)") .field(PCSCase::getCaseLinks, "LinkedCasesComponentLauncher!=\"\"", "#ARGUMENT(LinkedCases)"); @@ -106,9 +106,9 @@ public void configure(final ConfigBuilder builder) { configureCaseFileCategories(builder); } - private void configureCaseFileCategories(ConfigBuilder builder) { + private void configureCaseFileCategories(ConfigBuilder builder) { for (CaseFileCategory category : CaseFileCategory.values()) { - builder.categories(UserRole.PCS_SOLICITOR) + builder.categories(AccessProfile.PCS_SOLICITOR) .categoryID(category.getId()) .categoryLabel(category.getLabel()) .displayOrder(category.getDisplayOrder()) @@ -116,7 +116,7 @@ private void configureCaseFileCategories(ConfigBuilder } } - private void buildCasePartiesTab(ConfigBuilder builder) { + private void buildCasePartiesTab(ConfigBuilder builder) { builder.tab("caseParties", "Case Parties") .label("Case Parties", null, "#### Case Parties") .field("casePartiesTab_ClaimantDetails") diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java new file mode 100644 index 0000000000..5b55199f3d --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java @@ -0,0 +1,45 @@ +package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; + +import static java.util.Arrays.stream; +import static uk.gov.hmcts.ccd.sdk.api.Permission.CRU; +import static uk.gov.hmcts.ccd.sdk.api.Permission.R; + +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Set; +import lombok.Getter; +import uk.gov.hmcts.ccd.sdk.api.HasRole; +import uk.gov.hmcts.ccd.sdk.api.Permission; + +@Getter +public enum AccessProfile implements HasRole { + + CREATOR("[CREATOR]", CRU), + RAS_VALIDATOR("caseworker-ras-validation", Set.of(R)), + CITIZEN("citizen", CRU), + DEFENDANT("[DEFENDANT]", CRU), + CLAIMANT_SOLICITOR("[CLAIMANTSOLICITOR]", CRU), + DEFENDANT_SOLICITOR("[DEFENDANTSOLICITOR]", CRU), + PCS_CASE_WORKER("caseworker-pcs", Set.of(R)), + PCS_SOLICITOR("caseworker-pcs-solicitor", CRU), + + GS_PROFILE("GS_profile", Set.of(R)); + + @JsonValue + private final String role; + private final Set caseTypePermissions; + + AccessProfile(String role, Set permissions) { + this.role = role; + this.caseTypePermissions = permissions; + } + + public static String[] toRoles(AccessProfile... profiles) { + return stream(profiles) + .map(AccessProfile::getRole) + .toArray(String[]::new); + } + + public String getCaseTypePermissions() { + return Permission.toString(caseTypePermissions); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java index 47643a072e..b6acb2e802 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/ExternalUserRole.java @@ -16,11 +16,7 @@ public static ExternalUserRole forCcdRole(UserRole ccdRole) { @Override public String getRole() { - String name = ccdUserRole.getExternalRoleName() != null - ? ccdUserRole.getExternalRoleName() - : ccdUserRole.getRole(); - String rolePrefix = (ccdUserRole.getRoleType() == RoleType.IDAM) ? "idam:" : ""; - return rolePrefix + name; + return ccdUserRole.getRoleType().prefix() + ccdUserRole.getRole(); } @Override diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java index 879a5b3c94..8a1cb8b86b 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccess.java @@ -1,6 +1,6 @@ package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.AccessProfile.GS_PROFILE; import uk.gov.hmcts.ccd.sdk.api.HasAccessControl; import uk.gov.hmcts.ccd.sdk.api.HasRole; @@ -10,13 +10,11 @@ import com.google.common.collect.SetMultimap; public class GlobalSearchAccess implements HasAccessControl { + @Override public SetMultimap getGrants() { SetMultimap grants = HashMultimap.create(); - - //assigns access profile "GS_profile" which is shared between multiple UserRole's. - grants.put(HMCTS_ADMIN, Permission.R); - + grants.put(GS_PROFILE, Permission.R); return grants; } } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java index 67128c0a83..5f0f868660 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfiles.java @@ -17,7 +17,7 @@ public void configure(ConfigBuilder configBuil .forEach(userRole -> configBuilder .caseRoleToAccessProfile(ExternalUserRole.forCcdRole(userRole)) - .accessProfiles(userRole.getRole()) + .accessProfiles(userRole.getAccessProfiles()) .build() ); } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleType.java index 7ef4042251..4271a1f6ff 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleType.java @@ -2,7 +2,16 @@ enum RoleType { - IDAM, - RAS + IDAM("idam:"), + RAS(""); + private final String prefix; + + RoleType(String prefix) { + this.prefix = prefix; + } + + public String prefix() { + return prefix; + } } diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index 5521858cc1..61dd9ae073 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -7,7 +7,9 @@ import java.util.Set; +import static uk.gov.hmcts.ccd.sdk.api.Permission.CRU; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.AccessProfile.GS_PROFILE; import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.RoleType.IDAM; import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.RoleType.RAS; @@ -17,34 +19,41 @@ @Getter public enum UserRole implements HasRole { - CITIZEN("citizen", Permission.CRU, IDAM), - CREATOR("[CREATOR]", Permission.CRU, RAS), - DEFENDANT("[DEFENDANT]", Permission.CRU, RAS), - CLAIMANT_SOLICITOR("[CLAIMANTSOLICITOR]", Permission.CRU, RAS), - PCS_CASE_WORKER("caseworker-pcs", Set.of(R), IDAM), - PCS_SOLICITOR("caseworker-pcs-solicitor", Permission.CRU, IDAM), + CREATOR("[CREATOR]", CRU, RAS), RAS_VALIDATOR("caseworker-ras-validation", Set.of(R), IDAM), - DEFENDANT_SOLICITOR("[DEFENDANTSOLICITOR]", Permission.CRU, RAS), - HMCTS_ADMIN("GS_profile", Set.of(R), RAS, "hmcts-admin"), - HMCTS_JUDICIARY("GS_profile", Set.of(R), RAS, "hmcts-judiciary"), - HMCTS_CTSC("GS_profile", Set.of(R), RAS, "hmcts-ctsc"), - HMCTS_LEGAL_OPERATIONS("GS_profile", Set.of(R), RAS, "hmcts-legal-operations"),; + + CITIZEN("citizen", CRU, IDAM), + DEFENDANT("[DEFENDANT]", CRU, RAS), + CLAIMANT_SOLICITOR("[CLAIMANTSOLICITOR]", CRU, RAS), + DEFENDANT_SOLICITOR("[DEFENDANTSOLICITOR]", CRU, RAS), + + PCS_CASE_WORKER("caseworker-pcs", Set.of(R), IDAM), + PCS_SOLICITOR("caseworker-pcs-solicitor", CRU, IDAM), + + HMCTS_ADMIN("hmcts-admin", Set.of(R), RAS, GS_PROFILE), + HMCTS_JUDICIARY("hmcts-judiciary", Set.of(R), RAS, GS_PROFILE), + HMCTS_CTSC("hmcts-ctsc", Set.of(R), RAS, GS_PROFILE), + HMCTS_LEGAL_OPERATIONS("hmcts-legal-operations", Set.of(R), RAS, GS_PROFILE); @JsonValue private final String role; private final Set caseTypePermissions; private final RoleType roleType; - private final String externalRoleName; + private final String[] accessProfiles; UserRole(String role, Set permissions, RoleType roleType) { - this(role, permissions, roleType, null); + this(role, permissions, roleType, role); + } + + UserRole(String role, Set permissions, RoleType roleType, AccessProfile... accessProfiles) { + this(role, permissions, roleType, AccessProfile.toRoles(accessProfiles)); } - UserRole(String role, Set permissions, RoleType roleType, String externalRoleName) { + UserRole(String role, Set permissions, RoleType roleType, String... accessProfiles) { this.role = role; this.caseTypePermissions = permissions; this.roleType = roleType; - this.externalRoleName = externalRoleName; + this.accessProfiles = accessProfiles; } public String getCaseTypePermissions() { diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java index 131bf2efc9..14ea41ac71 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java @@ -11,8 +11,9 @@ import uk.gov.hmcts.ccd.sdk.api.Search; import uk.gov.hmcts.ccd.sdk.api.SearchCases; import uk.gov.hmcts.ccd.sdk.api.Tab; +import uk.gov.hmcts.ccd.sdk.api.Tab.TabBuilder; import uk.gov.hmcts.ccd.sdk.api.TabField; -import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; +import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.AccessProfile; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; @@ -26,7 +27,7 @@ class CaseTypeTest { private CaseType caseType; @Mock - private ConfigBuilderImpl builder; + private ConfigBuilderImpl builder; @Mock private PropertyUtils utils; @@ -61,15 +62,15 @@ void shouldGetCaseTypeName() { @Test void shouldConfigureCaseTypeTabs() { // Given - final Tab.TabBuilder nextStepsTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder summaryTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder caseHistoryTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder hiddenTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder serviceRequestTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder caseLinksTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder caseFileViewTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder casePartiesTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Search.SearchBuilder searchBuilder = + final TabBuilder nextStepsTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final TabBuilder summaryTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final TabBuilder caseHistoryTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final TabBuilder hiddenTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final TabBuilder serviceRequestTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final TabBuilder caseLinksTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final TabBuilder caseFileViewTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final TabBuilder casePartiesTabBuilder = TabBuilder.builder(PCSCase.class, utils); + final Search.SearchBuilder searchBuilder = Search.SearchBuilder.builder(PCSCase.class, utils); final SearchCases.SearchCasesBuilder searchCasesBuilder = SearchCases.SearchCasesBuilder.builder(PCSCase.class, utils); @@ -86,19 +87,19 @@ void shouldConfigureCaseTypeTabs() { when(builder.tab("caseLinks", "Linked Cases")).thenReturn(caseLinksTabBuilder); when(builder.tab("caseFileView", "Case File View")).thenReturn(caseFileViewTabBuilder); when(builder.tab("caseParties", "Case Parties")).thenReturn(casePartiesTabBuilder); - when(builder.categories(UserRole.PCS_SOLICITOR)) - .thenReturn(CaseCategory.CaseCategoryBuilder.builder(UserRole.PCS_SOLICITOR)); + when(builder.categories(AccessProfile.PCS_SOLICITOR)) + .thenReturn(CaseCategory.CaseCategoryBuilder.builder(AccessProfile.PCS_SOLICITOR)); // When caseType.configure(builder); - final Tab nextStepsTab = nextStepsTabBuilder.build(); - final Tab summaryTab = summaryTabBuilder.build(); - final Tab caseHistoryTab = caseHistoryTabBuilder.build(); - final Tab hiddenTab = hiddenTabBuilder.build(); - final Tab serviceRequestTab = serviceRequestTabBuilder.build(); - final Tab caseLinksTab = caseLinksTabBuilder.build(); - final Tab casePartiesTab = casePartiesTabBuilder.build(); - final Tab caseFileViewTab = caseFileViewTabBuilder.build(); + final Tab nextStepsTab = nextStepsTabBuilder.build(); + final Tab summaryTab = summaryTabBuilder.build(); + final Tab caseHistoryTab = caseHistoryTabBuilder.build(); + final Tab hiddenTab = hiddenTabBuilder.build(); + final Tab serviceRequestTab = serviceRequestTabBuilder.build(); + final Tab caseLinksTab = caseLinksTabBuilder.build(); + final Tab casePartiesTab = casePartiesTabBuilder.build(); + final Tab caseFileViewTab = caseFileViewTabBuilder.build(); // Then assertThat(nextStepsTab.getFields()).extracting(TabField::getId).contains("nextStepsMarkdown"); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java index 9d6e3c2062..839dc6486d 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/GlobalSearchAccessTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static uk.gov.hmcts.ccd.sdk.api.Permission.R; -import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole.HMCTS_ADMIN; +import static uk.gov.hmcts.reform.pcs.ccd.accesscontrol.AccessProfile.GS_PROFILE; import uk.gov.hmcts.ccd.sdk.api.HasRole; import uk.gov.hmcts.ccd.sdk.api.Permission; @@ -27,7 +27,7 @@ void setUp() { @Test void shouldGrantGlobalSearchAccess() { SetMultimap grants = underTest.getGrants(); - assertThat(grants.asMap()).contains(entry(HMCTS_ADMIN, Set.of(R))); + assertThat(grants.asMap()).contains(entry(GS_PROFILE, Set.of(R))); } } diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java index d6aa7f4322..dd5178f1aa 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/RoleToAccessProfilesTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -51,10 +52,7 @@ void shouldRegisterAccessProfileForEveryUserRole() { verify(configBuilder).caseRoleToAccessProfile(argThat( externalRole -> externalRole.getRole().equals(expectedExternalRole) )); - int sharedRoleCount = (int) stream(UserRole.values()) - .filter(r -> r.getRole().equals(userRole.getRole())) - .count(); - verify(accessProfileBuilder, times(sharedRoleCount)).accessProfiles(userRole.getRole()); + verify(accessProfileBuilder, atLeastOnce()).accessProfiles(userRole.getAccessProfiles()); }); verify(accessProfileBuilder, times(UserRole.values().length)).build(); } From cc97154020e301398d74d442a426dd9e55c0ff6f Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 21 May 2026 11:26:11 +0100 Subject: [PATCH 073/108] HDPI-5335 Only GS access for Case Issued state --- .../resources/cftlib-am-role-assignments.json | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/cftlib/resources/cftlib-am-role-assignments.json b/src/cftlib/resources/cftlib-am-role-assignments.json index a76894ca41..a850b57a67 100644 --- a/src/cftlib/resources/cftlib-am-role-assignments.json +++ b/src/cftlib/resources/cftlib-am-role-assignments.json @@ -15,5 +15,37 @@ "authorisations": [] } ] + }, + { + "email": "pcs-solicitor1@test.com", + "id": "f6484bbb-c10e-319b-ab8d-14361a7d2a23", + "roleAssignments": [ + { + "roleType": "ORGANISATION", + "roleName": "hmcts-admin", + "grantType": "STANDARD", + "roleCategory": "ADMIN", + "classification": "PUBLIC", + "readOnly": false, + "attributes": {}, + "authorisations": [] + } + ] + }, + { + "email": "pcs-solicitor1@test.com", + "id": "f6484bbb-c10e-319b-ab8d-14361a7d2a23", + "roleAssignments": [ + { + "roleType": "ORGANISATION", + "roleName": "[HMCTS-ADMIN]", + "grantType": "STANDARD", + "roleCategory": "ADMIN", + "classification": "PUBLIC", + "readOnly": false, + "attributes": {}, + "authorisations": [] + } + ] } ] From b582d0af3963c3d470657894e2a8ec0091a6a2ae Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 21 May 2026 11:28:14 +0100 Subject: [PATCH 074/108] HDPI-5335 Add back GS access for Pending case issued --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java index 56cec36809..3e6de06d30 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java @@ -20,7 +20,7 @@ public enum State { @CCD( label = "Awaiting Submission to HMCTS", - access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class, GlobalSearchAccess.class}, + access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class}, hint = "${caseTitleMarkdown}" ) AWAITING_SUBMISSION_TO_HMCTS, From acc998a3c8e842dc568935bf613b3623a8009db3 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 22 May 2026 10:54:22 +0100 Subject: [PATCH 075/108] HDPI-5335 merge conflict --- src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java index 9354859774..4d9a5e1d5e 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java @@ -14,7 +14,6 @@ import uk.gov.hmcts.ccd.sdk.api.Tab.TabBuilder; import uk.gov.hmcts.ccd.sdk.api.TabField; import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.AccessProfile; -import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; @@ -68,7 +67,7 @@ void shouldConfigureCaseTypeTabs() { final TabBuilder caseHistoryTabBuilder = TabBuilder.builder(PCSCase.class, utils); final TabBuilder hiddenTabBuilder = TabBuilder.builder(PCSCase.class, utils); final TabBuilder serviceRequestTabBuilder = TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder caseNotesTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); + final Tab.TabBuilder caseNotesTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); final TabBuilder caseLinksTabBuilder = TabBuilder.builder(PCSCase.class, utils); final TabBuilder caseFileViewTabBuilder = TabBuilder.builder(PCSCase.class, utils); final TabBuilder casePartiesTabBuilder = TabBuilder.builder(PCSCase.class, utils); From 08df69d9a9f17b37a813147786d16e87bdca9a4c Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 26 May 2026 11:19:56 +0100 Subject: [PATCH 076/108] HDPI-4009 Index Search Parties --- .../gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 37 ++++++++++++++++++- .../reform/pcs/globalsearch/SearchParty.java | 36 ++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index 71a0d9b427..dc1e4c9a27 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -9,6 +9,7 @@ import uk.gov.hmcts.ccd.sdk.type.Document; import uk.gov.hmcts.ccd.sdk.type.ListValue; import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; +import uk.gov.hmcts.ccd.sdk.type.SearchParty; import uk.gov.hmcts.ccd.sdk.type.YesOrNo; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; @@ -38,6 +39,7 @@ import uk.gov.hmcts.reform.pcs.exception.CaseNotFoundException; import uk.gov.hmcts.reform.pcs.security.SecurityContextService; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.Set; @@ -90,12 +92,43 @@ public PCSCase getCase(CaseViewRequest request) { caseFieldsView.setCaseFields(pcsCase); - //allows indexing for Global Search - pcsCase.setSearchCriteria(new SearchCriteria()); + pcsCase.setSearchCriteria(buildSearchCriteriaForIndexing(pcsCase)); return pcsCase; } + private SearchCriteria buildSearchCriteriaForIndexing(PCSCase pcsCase) { + List searchParties = Optional.ofNullable(pcsCase.getParties()) + .orElse(List.of()) + .stream() + .map(ListValue::getValue) + .map(this::toSearchParty) + .toList(); + + return SearchCriteria.builder() + .parties(ListValueUtils.wrapListItems(searchParties)) + .build(); + } + + private SearchParty toSearchParty(Party party) { + AddressUK address = party.getAddress(); + return SearchParty.builder() + .collectionFieldName("parties") + .name(joinNonBlank(party.getFirstName(), party.getLastName())) + .emailAddress(party.getEmailAddress()) + .addressLine1(address == null ? null : address.getAddressLine1()) + .postcode(address == null ? null : address.getPostCode()) + .dateOfBirth(party.getDateOfBirth()) + .build(); + } + + private static String joinNonBlank(String... parts) { + String joined = Arrays.stream(parts) + .filter(p -> p != null && !p.isBlank()) + .collect(Collectors.joining(" ")); + return joined.isEmpty() ? null : joined; + } + private boolean caseHasUnsubmittedData(long caseReference, State state) { if (State.AWAITING_SUBMISSION_TO_HMCTS == state) { return draftCaseDataService.hasUnsubmittedCaseData(caseReference, resumePossessionClaim); diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java new file mode 100644 index 0000000000..d5ce571175 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java @@ -0,0 +1,36 @@ +package uk.gov.hmcts.reform.pcs.globalsearch; + +import org.springframework.stereotype.Component; +import uk.gov.hmcts.ccd.sdk.api.CCDConfig; +import uk.gov.hmcts.ccd.sdk.api.ConfigBuilder; +import uk.gov.hmcts.ccd.sdk.api.SearchPartyField; +import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; +import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.domain.State; + +import java.util.List; + +import static java.util.List.of; + +@Component +public class SearchParty implements CCDConfig { + + private static final List SEARCH_PARTY_LIST = of( + SearchPartyField.builder() + // TODO: replace firstName with a computed fullName field on Party + .searchPartyName("firstName") + .searchPartyEmailAddress("emailAddress") + .searchPartyAddressLine1("address.AddressLine1") + .searchPartyPostCode("address.PostCode") + .searchPartyDOB("dateOfBirth") + .searchPartyCollectionFieldName("parties") + .searchPartyDOD("") + .build() + ); + + @Override + public void configure(final ConfigBuilder configBuilder) { + configBuilder.searchParty() + .fields(SEARCH_PARTY_LIST); + } +} \ No newline at end of file From fa9137f6a79cb0660fa98cb99080033e29898042 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 28 May 2026 09:00:45 +0100 Subject: [PATCH 077/108] HDPI-4009 Test changing Jurisdiction_name --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index 54ecc6afd2..6d1661696a 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -24,7 +24,7 @@ public class CaseType implements CCDConfig { private static final String CASE_TYPE_NAME = "Possession"; private static final String CASE_TYPE_DESCRIPTION = "Possession Case Type"; private static final String JURISDICTION_ID = "PCS"; - private static final String JURISDICTION_NAME = "Civil Possession"; + private static final String JURISDICTION_NAME = "Civil Possession Test"; private static final String JURISDICTION_DESCRIPTION = "Civil Possession Jurisdiction"; @Value("${hmcts.hmctsOrgId}") From 94b9efc9d99282dbce2b91077fe05d6761d770ff Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 28 May 2026 11:32:38 +0100 Subject: [PATCH 078/108] HDPI-4009 Merge updates --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 3 ++- .../hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java | 8 ++++++++ .../java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index a3c4f3c146..5b61fb970c 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -107,7 +107,8 @@ public void configure(final ConfigBuilder builder .field(PCSCase::getCaseLinks, "LinkedCasesComponentLauncher!=\"\"", "#ARGUMENT(LinkedCases)"); builder.tab("caseFlags", "Case flags") - .forRoles(AccessProfile.JUDGE, AccessProfile.FEE_PAID_JUDGE, UserRole.CIRCUIT_JUDGE, UserRole.LEADERSHIP_JUDGE, + .forRoles(AccessProfile.JUDGE, AccessProfile.FEE_PAID_JUDGE, AccessProfile.CIRCUIT_JUDGE, + AccessProfile.LEADERSHIP_JUDGE, AccessProfile.CTSC_ADMIN, AccessProfile.HEARING_CENTRE_ADMIN, AccessProfile.WLU_ADMIN) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java index 5b55199f3d..ba7cbdc61a 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfile.java @@ -22,6 +22,14 @@ public enum AccessProfile implements HasRole { PCS_CASE_WORKER("caseworker-pcs", Set.of(R)), PCS_SOLICITOR("caseworker-pcs-solicitor", CRU), + JUDGE("judge", Set.of(R)), + FEE_PAID_JUDGE("fee-paid-judge", Set.of(R)), + CIRCUIT_JUDGE("circuit-judge", Set.of(R)), + LEADERSHIP_JUDGE("leadership-judge", Set.of(R)), + CTSC_ADMIN("ctsc", Permission.CRU), + HEARING_CENTRE_ADMIN("hearing-centre-admin", Permission.CRU), + WLU_ADMIN("wlu-admin", Permission.CRU), + GS_PROFILE("GS_profile", Set.of(R)); @JsonValue diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java index a33671e783..65d35c2b86 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/State.java @@ -28,7 +28,7 @@ public enum State { @CCD( label = "Pending Case Issued", - access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class, GlobalSearchAccess.class + access = {ClaimantAccess.class, CitizenAccess.class, RasValidationAccess.class, GlobalSearchAccess.class, InternalCaseFlagAccess.class}, hint = "${caseTitleMarkdown}" ) From 16a2bc6884431eea756ef1a0fa5885d6f1662519 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 28 May 2026 11:48:36 +0100 Subject: [PATCH 079/108] HDPI-4009 checkstyle --- src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java index d02823d74e..b49342531f 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java @@ -14,7 +14,6 @@ import uk.gov.hmcts.ccd.sdk.api.Tab.TabBuilder; import uk.gov.hmcts.ccd.sdk.api.TabField; import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.AccessProfile; -import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.State; From e72be788fdbd65df663dc6edbcde512aae3e670e Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 11:58:36 +0100 Subject: [PATCH 080/108] HDPI-4009 Update case-flags to enrich partylist data rather than replace (and lose) parties. --- .../reform/pcs/ccd/view/CaseFlagsView.java | 42 +++---- .../pcs/ccd/view/CaseFlagsViewTest.java | 110 ++++++++++++++---- 2 files changed, 109 insertions(+), 43 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java index 1ec7e7d660..b8376b6ab5 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java @@ -13,10 +13,14 @@ import uk.gov.hmcts.reform.pcs.ccd.entity.BaseCaseFlag; import uk.gov.hmcts.reform.pcs.ccd.util.YesOrNoConverter; import uk.gov.hmcts.reform.pcs.ccd.entity.party.PartyEntity; +import uk.gov.hmcts.reform.pcs.ccd.entity.party.PartyRole; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; import static java.util.Objects.requireNonNullElse; @@ -89,29 +93,27 @@ private List> getPaths(String entityPaths) { } private void mapComplexPartyFlagFields(PCSCase pcsCase, PcsCaseEntity pcsCaseEntity) { - List> mappedParties = pcsCaseEntity.getParties().stream() - .filter(partyEntity -> partyEntity.getOrgName() == null || partyEntity.getOrgName().isEmpty()) - .map(this::mapPartyWithDefendantFlags) - .toList(); + if (CollectionUtils.isEmpty(pcsCase.getParties())) { + return; + } - pcsCase.setParties(mappedParties); + Map defendantEntitiesById = pcsCaseEntity.getParties().stream() + .filter(this::isDefendant) + .collect(Collectors.toMap(partyEntity -> partyEntity.getId().toString(), Function.identity())); + + pcsCase.getParties().forEach(partyListValue -> { + Party party = partyListValue.getValue(); + PartyEntity defendantEntity = defendantEntitiesById.get(party.getId()); + if (defendantEntity != null) { + party.setDefendantFlags(mapDefendantFlags(defendantEntity)); + } + }); } - private ListValue mapPartyWithDefendantFlags(PartyEntity partyEntity) { - return ListValue.builder() - .id(partyEntity.getId().toString()) - .value( - Party.builder() - .nameKnown(partyEntity.getNameKnown()) - .addressKnown(partyEntity.getAddressKnown()) - .phoneNumberProvided(partyEntity.getPhoneNumberProvided()) - .emailAddress(partyEntity.getEmailAddress()) - .firstName(partyEntity.getFirstName()) - .lastName(partyEntity.getLastName()) - .defendantFlags(mapDefendantFlags(partyEntity)) - .build() - ) - .build(); + private boolean isDefendant(PartyEntity partyEntity) { + return !CollectionUtils.isEmpty(partyEntity.getClaimParties()) + && partyEntity.getClaimParties().stream() + .anyMatch(claimParty -> claimParty.getRole() == PartyRole.DEFENDANT); } private Flags mapDefendantFlags(PartyEntity partyEntity) { diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java index 74bd7be586..2e3f7a99e5 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java @@ -4,14 +4,18 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.ccd.sdk.type.ListValue; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.entity.PcsCaseEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.CaseFlagEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.CasePartyFlagEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.FlagRefDataEntity; +import uk.gov.hmcts.reform.pcs.ccd.entity.party.ClaimPartyEntity; import uk.gov.hmcts.reform.pcs.ccd.entity.party.PartyEntity; +import uk.gov.hmcts.reform.pcs.ccd.entity.party.PartyRole; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; @@ -65,32 +69,79 @@ void shouldMapBasicCaseFlagFieldsWhenCaseFlagsExist() { @Test void shouldMapComplexPartyFlagFieldsWhenPartiesExist() { - // Given - PartyEntity partyEntityFirst = createPartyEntity(null); - PartyEntity partyEntitySecond = createPartyEntity("King Smith"); - + // Given - a defendant (with flags) and a non-defendant organisation party, + // both already mapped onto the case earlier (as PCSCaseView does) + PartyEntity defendantEntity = createPartyEntity(null); + markAsDefendant(defendantEntity); + defendantEntity.setDefendantFlags(List.of(createMockCasePartyFlagsEntity())); - CasePartyFlagEntity defendantFlags = createMockCasePartyFlagsEntity(); - partyEntityFirst.setDefendantFlags(List.of(defendantFlags)); + PartyEntity orgEntity = createPartyEntity("King Smith"); - PCSCase pcsCase = PCSCase.builder().build(); + PCSCase pcsCase = PCSCase.builder() + .parties(List.of(mappedParty(defendantEntity), mappedParty(orgEntity))) + .build(); PcsCaseEntity pcsCaseEntity = new PcsCaseEntity(); - - pcsCaseEntity.setParties(Set.of(partyEntityFirst, partyEntitySecond)); + pcsCaseEntity.setParties(Set.of(defendantEntity, orgEntity)); // When underTest.setCaseFields(pcsCase, pcsCaseEntity); - // Then + // Then - both parties remain, but only the defendant is given flags assertNotNull(pcsCase.getParties()); + assertEquals(2, pcsCase.getParties().size()); + + Party mappedDefendant = findPartyById(pcsCase, defendantEntity.getId().toString()); + assertNotNull(mappedDefendant.getDefendantFlags()); + assertEquals(1, mappedDefendant.getDefendantFlags().getDetails().size()); + assertEquals("PF0015", + mappedDefendant.getDefendantFlags().getDetails().getFirst().getValue().getFlagCode()); + + Party mappedOrgParty = findPartyById(pcsCase, orgEntity.getId().toString()); + assertNull(mappedOrgParty.getDefendantFlags()); + } + + @Test + void shouldNotMapDefendantFlagsForNonDefendantIndividual() { + // Given - an individual (no orgName) who is an underlessee, not a defendant + PartyEntity individualUnderlessee = PartyEntity.builder() + .id(UUID.randomUUID()) + .firstName("Under") + .lastName("Lessee") + .build(); + individualUnderlessee.setClaimParties(new HashSet<>(Set.of( + ClaimPartyEntity.builder().role(PartyRole.UNDERLESSEE_OR_MORTGAGEE).build()))); + + PCSCase pcsCase = PCSCase.builder() + .parties(List.of(mappedParty(individualUnderlessee))) + .build(); + PcsCaseEntity pcsCaseEntity = new PcsCaseEntity(); + pcsCaseEntity.setParties(Set.of(individualUnderlessee)); + + // When + underTest.setCaseFields(pcsCase, pcsCaseEntity); + + // Then - retained, but no defendant flags applied assertEquals(1, pcsCase.getParties().size()); - Party party = pcsCase.getParties().getFirst().getValue(); - assertNotNull(party.getDefendantFlags()); - assertEquals(1, party.getDefendantFlags().getDetails().size()); - assertEquals("PF0015", party.getDefendantFlags().getDetails().getFirst().getValue().getFlagCode()); + Party mapped = pcsCase.getParties().getFirst().getValue(); + assertNull(mapped.getDefendantFlags()); + assertEquals("Under", mapped.getFirstName()); + assertEquals("Lessee", mapped.getLastName()); + } + + private Party findPartyById(PCSCase pcsCase, String id) { + return pcsCase.getParties().stream() + .map(ListValue::getValue) + .filter(party -> id.equals(party.getId())) + .findFirst() + .orElseThrow(); + } + + private void markAsDefendant(PartyEntity partyEntity) { + partyEntity.setClaimParties(new HashSet<>(Set.of( + ClaimPartyEntity.builder().role(PartyRole.DEFENDANT).build()))); } - private PartyEntity createPartyEntity(String orgName) { //, String firstName, String lastName + private PartyEntity createPartyEntity(String orgName) { return PartyEntity.builder() .id(UUID.randomUUID()) @@ -98,15 +149,28 @@ private PartyEntity createPartyEntity(String orgName) { //, String firstName, S .build(); } + private ListValue mappedParty(PartyEntity entity) { + return ListValue.builder() + .value(Party.builder() + .id(entity.getId().toString()) + .orgName(entity.getOrgName()) + .firstName(entity.getFirstName()) + .lastName(entity.getLastName()) + .build()) + .build(); + } + @Test void shouldMapComplexPartyFlagFieldsWhenPartiesExistsWithNoFlags() { - // Given - PartyEntity partyEntity = new PartyEntity(); - partyEntity.setId(UUID.randomUUID()); + // Given - a defendant with no party flags + PartyEntity defendantEntity = createPartyEntity(null); + markAsDefendant(defendantEntity); - PCSCase pcsCase = PCSCase.builder().build(); + PCSCase pcsCase = PCSCase.builder() + .parties(List.of(mappedParty(defendantEntity))) + .build(); PcsCaseEntity pcsCaseEntity = new PcsCaseEntity(); - pcsCaseEntity.setParties(Set.of(partyEntity)); + pcsCaseEntity.setParties(Set.of(defendantEntity)); // When underTest.setCaseFields(pcsCase, pcsCaseEntity); @@ -134,15 +198,15 @@ void shouldHandleNullCaseFlagsGracefully() { @Test void shouldHandleNullPartiesGracefully() { - // Given + // Given - no parties have been mapped onto the case PcsCaseEntity pcsCaseEntity = new PcsCaseEntity(); PCSCase pcsCase = PCSCase.builder().build(); // When underTest.setCaseFields(pcsCase, pcsCaseEntity); - // Then - assertEquals(0, pcsCase.getParties().size()); + // Then - nothing to enrich, no failure + assertNull(pcsCase.getParties()); } private CaseFlagEntity createMockCaseFlagsEntity() { From 9c68853be91d96c0b7992126491a76e04d2aa622 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 11:59:30 +0100 Subject: [PATCH 081/108] HDPI-4009 Check if underlesse / mortgagees are individuals or orgs so we can store first/last name or org name. --- .../domain/UnderlesseeMortgageeDetails.java | 25 ++++++++++++--- .../UnderlesseeOrMortgageeDetailsPage.java | 10 ++++-- .../pcs/ccd/service/party/PartyService.java | 8 ++++- .../pcs/ccd/service/PartyServiceTest.java | 31 +++++++++++++------ 4 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java index 5e522c903e..354299a516 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java @@ -24,12 +24,29 @@ public class UnderlesseeMortgageeDetails { @CCD(label = "Do you know the underlessee or mortgagee’s name?") private VerticalYesNo nameKnown; - @CCD(label = "What is their name?", - hint = "Enter their first and last name, or the company or organisation name", - showCondition = "nameKnown=\"YES\"", + @CCD(label = "Is the underlessee or mortgagee an individual or an organisation?", + showCondition = "nameKnown=\"YES\"" + ) + private IndividualOrOrganisation partyType; + + @CCD(label = "First name", + showCondition = "nameKnown=\"YES\" AND partyType=\"INDIVIDUAL\"", + max = 60 + ) + private String firstName; + + @CCD(label = "Last name", + showCondition = "nameKnown=\"YES\" AND partyType=\"INDIVIDUAL\"", + max = 60 + ) + private String lastName; + + @CCD(label = "What is the organisation’s name?", + hint = "Enter the company or organisation name", + showCondition = "nameKnown=\"YES\" AND partyType=\"ORGANISATION\"", max = 60 ) - private String name; + private String organisationName; @CCD(label = """ --- diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java index 1459b9bc13..ff554f6cdd 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java @@ -33,7 +33,10 @@ public void addTo(PageBuilder pageBuilder) { .complex(PCSCase::getUnderlesseeOrMortgagee1) .readonlyNoSummary(UnderlesseeMortgageeDetails::getNameSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getNameKnown) - .mandatory(UnderlesseeMortgageeDetails::getName) + .mandatory(UnderlesseeMortgageeDetails::getPartyType) + .mandatory(UnderlesseeMortgageeDetails::getFirstName) + .mandatory(UnderlesseeMortgageeDetails::getLastName) + .mandatory(UnderlesseeMortgageeDetails::getOrganisationName) .readonlyNoSummary(UnderlesseeMortgageeDetails::getAddressSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getAddressKnown) .complex(UnderlesseeMortgageeDetails::getAddress) @@ -55,7 +58,10 @@ public void addTo(PageBuilder pageBuilder) { "addAdditionalUnderlesseeOrMortgagee=\"YES\"") .readonlyNoSummary(UnderlesseeMortgageeDetails::getNameSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getNameKnown) - .mandatory(UnderlesseeMortgageeDetails::getName) + .mandatory(UnderlesseeMortgageeDetails::getPartyType) + .mandatory(UnderlesseeMortgageeDetails::getFirstName) + .mandatory(UnderlesseeMortgageeDetails::getLastName) + .mandatory(UnderlesseeMortgageeDetails::getOrganisationName) .readonlyNoSummary(UnderlesseeMortgageeDetails::getAddressSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getAddressKnown) .complex(UnderlesseeMortgageeDetails::getAddress) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java index a27e73ecc2..a525ec90a2 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java @@ -8,6 +8,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantContactPreferences; import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantInformation; import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; +import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.UnderlesseeMortgageeDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; @@ -190,7 +191,12 @@ private PartyEntity createUnderlesseeOrMortgagee(UnderlesseeMortgageeDetails und VerticalYesNo nameKnown = underlesseeMortgageeDetails.getNameKnown(); underlesseeMortgageeEntity.setNameKnown(nameKnown); if (nameKnown == VerticalYesNo.YES) { - underlesseeMortgageeEntity.setOrgName(underlesseeMortgageeDetails.getName()); + if (underlesseeMortgageeDetails.getPartyType() == IndividualOrOrganisation.INDIVIDUAL) { + underlesseeMortgageeEntity.setFirstName(underlesseeMortgageeDetails.getFirstName()); + underlesseeMortgageeEntity.setLastName(underlesseeMortgageeDetails.getLastName()); + } else { + underlesseeMortgageeEntity.setOrgName(underlesseeMortgageeDetails.getOrganisationName()); + } } VerticalYesNo addressKnown = underlesseeMortgageeDetails.getAddressKnown(); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java index d14df1d19c..655394effd 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java @@ -17,6 +17,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantContactPreferences; import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantInformation; import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; +import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.UnderlesseeMortgageeDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; @@ -815,14 +816,17 @@ void shouldBuildListWithMultipleUnderlessees() { UnderlesseeMortgageeDetails underlessee1Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name("underlessee 1 name") + .partyType(IndividualOrOrganisation.INDIVIDUAL) + .firstName("underlessee 1 first name") + .lastName("underlessee 1 last name") .addressKnown(VerticalYesNo.YES) .address(underlessee1Address) .build(); UnderlesseeMortgageeDetails underlessee2Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name("underlessee 2 name") + .partyType(IndividualOrOrganisation.ORGANISATION) + .organisationName("underlessee 2 name") .addressKnown(VerticalYesNo.NO) .build(); @@ -839,7 +843,8 @@ void shouldBuildListWithMultipleUnderlessees() { PartyEntity expectedUnderlessee1 = PartyEntity.builder() .nameKnown(VerticalYesNo.YES) - .orgName("underlessee 1 name") + .firstName("underlessee 1 first name") + .lastName("underlessee 1 last name") .addressKnown(VerticalYesNo.YES) .address(mappedUnderlessee1Address) .build(); @@ -887,14 +892,16 @@ void shouldIgnoreMultipleUnderlesseesIfAdditionalUnderlesseesNotIndicated() { UnderlesseeMortgageeDetails underlessee1Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name("underlessee 1 name") + .partyType(IndividualOrOrganisation.ORGANISATION) + .organisationName("underlessee 1 name") .addressKnown(VerticalYesNo.YES) .address(underlessee1Address) .build(); UnderlesseeMortgageeDetails underlessee2Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name("underlessee 2 name") + .partyType(IndividualOrOrganisation.ORGANISATION) + .organisationName("underlessee 2 name") .addressKnown(VerticalYesNo.NO) .build(); @@ -936,23 +943,27 @@ private static Stream singleUnderlesseeScenarios() { .build() ), argumentSet( - "Name known, address not known", + "Individual name known, address not known", UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name("expected underlessee name") + .partyType(IndividualOrOrganisation.INDIVIDUAL) + .firstName("expected first name") + .lastName("expected last name") .addressKnown(VerticalYesNo.NO) .build(), PartyEntity.builder() .nameKnown(VerticalYesNo.YES) - .orgName("expected underlessee name") + .firstName("expected first name") + .lastName("expected last name") .addressKnown(VerticalYesNo.NO) .build() ), argumentSet( - "Name known, address known", + "Organisation name known, address known", UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name("expected underlessee name") + .partyType(IndividualOrOrganisation.ORGANISATION) + .organisationName("expected underlessee name") .addressKnown(VerticalYesNo.YES) .address(correspondenceAddress) .build(), From fcc9085e76ca10eadfff8cd8664ff20ba2b4d61e Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 11:59:48 +0100 Subject: [PATCH 082/108] HDPI-4009 remove debugging --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index 5b61fb970c..323f1885f2 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -24,7 +24,7 @@ public class CaseType implements CCDConfig { private static final String CASE_TYPE_NAME = "Possession"; private static final String CASE_TYPE_DESCRIPTION = "Possession Case Type"; private static final String JURISDICTION_ID = "PCS"; - private static final String JURISDICTION_NAME = "Civil Possession Test"; + private static final String JURISDICTION_NAME = "Civil Possession"; private static final String JURISDICTION_DESCRIPTION = "Civil Possession Jurisdiction"; @Value("${hmcts.hmctsOrgId}") From 801d2b1fd6f7f15f5a7e3de6e94a08723283a9c5 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 12:15:03 +0100 Subject: [PATCH 083/108] HDPI-4009 add enum to differentiate between individual and organisation --- .../ccd/domain/IndividualOrOrganisation.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java new file mode 100644 index 0000000000..8ae570a05c --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java @@ -0,0 +1,25 @@ +package uk.gov.hmcts.reform.pcs.ccd.domain; + +import uk.gov.hmcts.ccd.sdk.api.HasLabel; + +/** + * Indicates whether a party is an individual (a person) or an organisation, + * so their name can be captured and stored in the appropriate fields. + */ +public enum IndividualOrOrganisation implements HasLabel { + + INDIVIDUAL("Individual"), + ORGANISATION("Organisation"); + + private final String label; + + IndividualOrOrganisation(String label) { + this.label = label; + } + + @Override + public String getLabel() { + return label; + } + +} From 926984a40cbf7d7ef75aac31fc90b3f72b4dfef9 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 12:21:19 +0100 Subject: [PATCH 084/108] HDPI-4009 add enum to differentiate between individual and organisation --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index 1da096da2e..a32fc76a19 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -141,7 +141,7 @@ private void buildCasePartiesTab(ConfigBuilder bu .field("casePartiesTab_DefendantsDetails"); } - private void buildSummaryTab(ConfigBuilder builder) { + private void buildSummaryTab(ConfigBuilder builder) { builder.tab("summary", "Summary") .label("confirmEvictionSummaryMarkupLabel", null, "${confirmEvictionSummaryMarkup}") .field("confirmEvictionSummaryMarkup", NEVER_SHOW) From 398058a8edf5e6b7919bc3afb054199e12f89860 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 15:08:36 +0100 Subject: [PATCH 085/108] HDPI-4009 Remove SearchParty.java --- .../reform/pcs/globalsearch/SearchParty.java | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java b/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java deleted file mode 100644 index d5ce571175..0000000000 --- a/src/main/java/uk/gov/hmcts/reform/pcs/globalsearch/SearchParty.java +++ /dev/null @@ -1,36 +0,0 @@ -package uk.gov.hmcts.reform.pcs.globalsearch; - -import org.springframework.stereotype.Component; -import uk.gov.hmcts.ccd.sdk.api.CCDConfig; -import uk.gov.hmcts.ccd.sdk.api.ConfigBuilder; -import uk.gov.hmcts.ccd.sdk.api.SearchPartyField; -import uk.gov.hmcts.reform.pcs.ccd.accesscontrol.UserRole; -import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; -import uk.gov.hmcts.reform.pcs.ccd.domain.State; - -import java.util.List; - -import static java.util.List.of; - -@Component -public class SearchParty implements CCDConfig { - - private static final List SEARCH_PARTY_LIST = of( - SearchPartyField.builder() - // TODO: replace firstName with a computed fullName field on Party - .searchPartyName("firstName") - .searchPartyEmailAddress("emailAddress") - .searchPartyAddressLine1("address.AddressLine1") - .searchPartyPostCode("address.PostCode") - .searchPartyDOB("dateOfBirth") - .searchPartyCollectionFieldName("parties") - .searchPartyDOD("") - .build() - ); - - @Override - public void configure(final ConfigBuilder configBuilder) { - configBuilder.searchParty() - .fields(SEARCH_PARTY_LIST); - } -} \ No newline at end of file From e2f6c54bc9496cc83ef995199fcf19cf77e9cfc6 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 17:09:27 +0100 Subject: [PATCH 086/108] HDPI-4009 Allow searching for property claimant is repossessing --- .../gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 35 +++++++++++++++---- .../hmcts/reform/pcs/ccd/PCSCaseViewTest.java | 25 +++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index fc0eb70e19..f002134ec8 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -44,6 +44,7 @@ import java.util.Arrays; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; @@ -116,18 +117,40 @@ public PCSCase getCase(CaseViewRequest request) { } private SearchCriteria buildSearchCriteriaForIndexing(PCSCase pcsCase) { - List searchParties = Optional.ofNullable(pcsCase.getParties()) - .orElse(List.of()) - .stream() - .map(ListValue::getValue) - .map(this::toSearchParty) - .toList(); + List searchParties = new ArrayList<>( + Optional.ofNullable(pcsCase.getParties()) + .orElse(List.of()) + .stream() + .map(ListValue::getValue) + .map(this::toSearchParty) + .toList()); + + // Global search only indexes postcodes that appear on a SearchParty. + // We add the property to be repossessed address as an extra SearchParty here to make it searchable. + SearchParty propertySearchParty = toPropertySearchParty(pcsCase.getPropertyAddress()); + if (propertySearchParty != null) { + searchParties.add(propertySearchParty); + } return SearchCriteria.builder() .parties(ListValueUtils.wrapListItems(searchParties)) .build(); } + private SearchParty toPropertySearchParty(AddressUK propertyAddress) { + if (propertyAddress == null + || propertyAddress.getPostCode() == null + || propertyAddress.getPostCode().isBlank()) { + return null; + } + + return SearchParty.builder() + .collectionFieldName("parties") + .addressLine1(propertyAddress.getAddressLine1()) + .postcode(propertyAddress.getPostCode()) + .build(); + } + private SearchParty toSearchParty(Party party) { AddressUK address = party.getAddress(); return SearchParty.builder() diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java index 930f144b80..839c638286 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java @@ -10,6 +10,8 @@ import uk.gov.hmcts.ccd.sdk.CaseViewRequest; import uk.gov.hmcts.ccd.sdk.type.AddressUK; import uk.gov.hmcts.ccd.sdk.type.ListValue; +import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; +import uk.gov.hmcts.ccd.sdk.type.SearchParty; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.State; @@ -190,6 +192,29 @@ void shouldMapPropertyAddress() { assertThat(pcsCase.getPropertyAddress()).isEqualTo(addressUK); } + @Test + void shouldIndexPropertyPostcodeAsSearchPartyWithoutPollutingParties() { + // Given - a property address with a postcode and no real parties + AddressEntity addressEntity = mock(AddressEntity.class); + when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); + AddressUK addressUK = stubAddressEntityModelMapper(addressEntity); + when(addressUK.getPostCode()).thenReturn("AB1 2CD"); + when(addressUK.getAddressLine1()).thenReturn("1 Test Street"); + + // When + PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); + + // Then - the property postcode is indexed as a SearchParty for global search + SearchCriteria searchCriteria = pcsCase.getSearchCriteria(); + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .extracting(SearchParty::getPostcode) + .contains("AB1 2CD"); + + // And the property is NOT added to the real parties list (no downstream pollution) + assertThat(pcsCase.getParties()).isEmpty(); + } + @Test void shouldMapPartyEntity() { // Given From 7b45d1a31d92753088b2f418c4975d2bf38a5575 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 1 Jun 2026 17:51:44 +0100 Subject: [PATCH 087/108] HDPI-4009 remove 'parties' field --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index f002134ec8..e430941000 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -145,7 +145,6 @@ private SearchParty toPropertySearchParty(AddressUK propertyAddress) { } return SearchParty.builder() - .collectionFieldName("parties") .addressLine1(propertyAddress.getAddressLine1()) .postcode(propertyAddress.getPostCode()) .build(); @@ -154,7 +153,6 @@ private SearchParty toPropertySearchParty(AddressUK propertyAddress) { private SearchParty toSearchParty(Party party) { AddressUK address = party.getAddress(); return SearchParty.builder() - .collectionFieldName("parties") .name(joinNonBlank(party.getFirstName(), party.getLastName())) .emailAddress(party.getEmailAddress()) .addressLine1(address == null ? null : address.getAddressLine1()) From f33bc62cd0cec39a3c12a68b1ca92d17bcd2e014 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 3 Jun 2026 15:15:27 +0100 Subject: [PATCH 088/108] HDPI-4009 Add testing for new branches --- .../hmcts/reform/pcs/ccd/PCSCaseViewTest.java | 61 +++++++++++++++++++ .../ccd/accesscontrol/AccessProfileTest.java | 22 +++++++ 2 files changed, 83 insertions(+) create mode 100644 src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfileTest.java diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java index 978299767a..407370b5aa 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java @@ -218,6 +218,67 @@ void shouldIndexPropertyPostcodeAsSearchPartyWithoutPollutingParties() { assertThat(pcsCase.getParties()).isEmpty(); } + @Test + void shouldIndexPropertyAddressLine1AndPostcodeOnSearchParty() { + // Given - a property address with both an address line and a postcode + AddressEntity addressEntity = mock(AddressEntity.class); + when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); + AddressUK addressUK = stubAddressEntityModelMapper(addressEntity); + when(addressUK.getPostCode()).thenReturn("AB1 2CD"); + when(addressUK.getAddressLine1()).thenReturn("1 Test Street"); + + // When + PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); + + // Then - both fields are copied onto the property SearchParty + assertThat(pcsCase.getSearchCriteria().getParties()) + .extracting(ListValue::getValue) + .anySatisfy(searchParty -> { + assertThat(searchParty.getAddressLine1()).isEqualTo("1 Test Street"); + assertThat(searchParty.getPostcode()).isEqualTo("AB1 2CD"); + }); + } + + @Test + void shouldNotIndexPropertyWhenAddressIsNull() { + // Given - no property address (pcsCaseEntity.getPropertyAddress() returns null) + + // When + PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); + + // Then - no property SearchParty is added + assertThat(pcsCase.getSearchCriteria().getParties()).isEmpty(); + } + + @Test + void shouldNotIndexPropertyWhenPostcodeIsNull() { + // Given - a property address with no postcode + AddressEntity addressEntity = mock(AddressEntity.class); + when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); + stubAddressEntityModelMapper(addressEntity); + + // When + PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); + + // Then - no property SearchParty is added + assertThat(pcsCase.getSearchCriteria().getParties()).isEmpty(); + } + + @Test + void shouldNotIndexPropertyWhenPostcodeIsBlank() { + // Given - a property address with a blank postcode + AddressEntity addressEntity = mock(AddressEntity.class); + when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); + AddressUK addressUK = stubAddressEntityModelMapper(addressEntity); + when(addressUK.getPostCode()).thenReturn(" "); + + // When + PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); + + // Then - no property SearchParty is added + assertThat(pcsCase.getSearchCriteria().getParties()).isEmpty(); + } + @Test void shouldMapPartyEntity() { // Given diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfileTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfileTest.java new file mode 100644 index 0000000000..aa04539f75 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/AccessProfileTest.java @@ -0,0 +1,22 @@ +package uk.gov.hmcts.reform.pcs.ccd.accesscontrol; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class AccessProfileTest { + + @Test + void shouldMapProfilesToTheirRoleStringsInOrder() { + String[] roles = AccessProfile.toRoles(AccessProfile.CREATOR, AccessProfile.CITIZEN); + + assertThat(roles).containsExactly("[CREATOR]", "citizen"); + } + + @Test + void shouldReturnEmptyArrayWhenNoProfilesGiven() { + String[] roles = AccessProfile.toRoles(); + + assertThat(roles).isEmpty(); + } +} From 0732e9b344c0f61f6ec62947198ebca122218d82 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Wed, 3 Jun 2026 16:14:57 +0100 Subject: [PATCH 089/108] HDPI-4009 serach criteria separated out --- .../globalsearch/SearchCriteriaIndexer.java | 83 +++++++ .../SearchCriteriaIndexerTest.java | 230 ++++++++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java create mode 100644 src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java new file mode 100644 index 0000000000..4c19ae70f2 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java @@ -0,0 +1,83 @@ +package uk.gov.hmcts.reform.pcs.ccd.view.globalsearch; + +import org.springframework.stereotype.Component; +import uk.gov.hmcts.ccd.sdk.type.AddressUK; +import uk.gov.hmcts.ccd.sdk.type.ListValue; +import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; +import uk.gov.hmcts.ccd.sdk.type.SearchParty; +import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.domain.Party; +import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Builds the {@link SearchCriteria} used to index a case for global search. + * + *

Global search only indexes postcodes that appear on a SearchParty, so the property to be + * repossessed is added as an extra SearchParty alongside the real parties to make it searchable. + */ +@Component +public class SearchCriteriaIndexer { + + /** + * Builds the {@link SearchCriteria} for indexing the given case in global search. + * @param pcsCase the case to index + * @return search criteria covering the case parties and the property to be repossessed + */ + public SearchCriteria buildSearchCriteria(PCSCase pcsCase) { + List searchParties = new ArrayList<>( + Optional.ofNullable(pcsCase.getParties()) + .orElse(List.of()) + .stream() + .map(ListValue::getValue) + .map(this::toSearchParty) + .toList()); + + // Global search only indexes postcodes that appear on a SearchParty. + // We add the property to be repossessed address as an extra SearchParty here to make it searchable. + SearchParty propertySearchParty = toPropertySearchParty(pcsCase.getPropertyAddress()); + if (propertySearchParty != null) { + searchParties.add(propertySearchParty); + } + + return SearchCriteria.builder() + .parties(ListValueUtils.wrapListItems(searchParties)) + .build(); + } + + private SearchParty toPropertySearchParty(AddressUK propertyAddress) { + if (propertyAddress == null + || propertyAddress.getPostCode() == null + || propertyAddress.getPostCode().isBlank()) { + return null; + } + + return SearchParty.builder() + .addressLine1(propertyAddress.getAddressLine1()) + .postcode(propertyAddress.getPostCode()) + .build(); + } + + private SearchParty toSearchParty(Party party) { + AddressUK address = party.getAddress(); + return SearchParty.builder() + .name(joinNonBlank(party.getFirstName(), party.getLastName())) + .emailAddress(party.getEmailAddress()) + .addressLine1(address == null ? null : address.getAddressLine1()) + .postcode(address == null ? null : address.getPostCode()) + .dateOfBirth(party.getDateOfBirth()) + .build(); + } + + private static String joinNonBlank(String... parts) { + String joined = Arrays.stream(parts) + .filter(p -> p != null && !p.isBlank()) + .collect(Collectors.joining(" ")); + return joined.isEmpty() ? null : joined; + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java new file mode 100644 index 0000000000..2ed7ae1eb1 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java @@ -0,0 +1,230 @@ +package uk.gov.hmcts.reform.pcs.ccd.view.globalsearch; + +import org.junit.jupiter.api.Test; +import uk.gov.hmcts.ccd.sdk.type.AddressUK; +import uk.gov.hmcts.ccd.sdk.type.ListValue; +import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; +import uk.gov.hmcts.ccd.sdk.type.SearchParty; +import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.domain.Party; +import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; + +import java.time.LocalDate; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SearchCriteriaIndexerTest { + + private final SearchCriteriaIndexer underTest = new SearchCriteriaIndexer(); + + @Test + void shouldIndexPartyDetailsAsSearchParty() { + // Given + LocalDate dateOfBirth = LocalDate.of(1990, 1, 2); + Party party = Party.builder() + .firstName("Jane") + .lastName("Doe") + .emailAddress("jane@example.com") + .dateOfBirth(dateOfBirth) + .address(AddressUK.builder() + .addressLine1("1 Party Street") + .postCode("PA1 2RT") + .build()) + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .satisfies(searchParty -> { + assertThat(searchParty.getName()).isEqualTo("Jane Doe"); + assertThat(searchParty.getEmailAddress()).isEqualTo("jane@example.com"); + assertThat(searchParty.getAddressLine1()).isEqualTo("1 Party Street"); + assertThat(searchParty.getPostcode()).isEqualTo("PA1 2RT"); + assertThat(searchParty.getDateOfBirth()).isEqualTo(dateOfBirth); + }); + } + + @Test + void shouldOmitBlankNamePartsWhenBuildingPartyName() { + // Given - only a last name is known + Party party = Party.builder() + .firstName(" ") + .lastName("Doe") + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - blank parts are dropped, leaving just the known name + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .extracting(SearchParty::getName) + .isEqualTo("Doe"); + } + + @Test + void shouldSetNullNameWhenNoNamePartsKnown() { + // Given - neither first nor last name known + Party party = Party.builder().build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .extracting(SearchParty::getName) + .isNull(); + } + + @Test + void shouldHandlePartyWithNoAddress() { + // Given - a party with no address + Party party = Party.builder() + .firstName("Jane") + .lastName("Doe") + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - address-derived fields are left null + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .satisfies(searchParty -> { + assertThat(searchParty.getAddressLine1()).isNull(); + assertThat(searchParty.getPostcode()).isNull(); + }); + } + + @Test + void shouldIndexPropertyAddressAsExtraSearchParty() { + // Given - no parties, just a property to be repossessed + PCSCase pcsCase = PCSCase.builder() + .propertyAddress(AddressUK.builder() + .addressLine1("1 Property Street") + .postCode("PR1 2PT") + .build()) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - the property is added as a SearchParty so its postcode is searchable + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .satisfies(searchParty -> { + assertThat(searchParty.getAddressLine1()).isEqualTo("1 Property Street"); + assertThat(searchParty.getPostcode()).isEqualTo("PR1 2PT"); + }); + } + + @Test + void shouldIndexBothPartiesAndPropertyAddress() { + // Given + Party party = Party.builder().firstName("Jane").lastName("Doe").build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .propertyAddress(AddressUK.builder().postCode("PR1 2PT").build()) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - both the party and the property appear as search parties + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .extracting(SearchParty::getPostcode) + .containsExactlyInAnyOrder(null, "PR1 2PT"); + } + + @Test + void shouldNotIndexPropertyWhenAddressIsNull() { + // Given + PCSCase pcsCase = PCSCase.builder().build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then + assertThat(searchCriteria.getParties()).isEmpty(); + } + + @Test + void shouldNotIndexPropertyWhenPostcodeIsNull() { + // Given - a property address with no postcode + PCSCase pcsCase = PCSCase.builder() + .propertyAddress(AddressUK.builder().addressLine1("1 Property Street").build()) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then + assertThat(searchCriteria.getParties()).isEmpty(); + } + + @Test + void shouldNotIndexPropertyWhenPostcodeIsBlank() { + // Given - a property address with a blank postcode + PCSCase pcsCase = PCSCase.builder() + .propertyAddress(AddressUK.builder().postCode(" ").build()) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then + assertThat(searchCriteria.getParties()).isEmpty(); + } + + @Test + void shouldReturnEmptySearchPartiesWhenNoPartiesOrProperty() { + // Given + PCSCase pcsCase = PCSCase.builder().build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then + assertThat(searchCriteria.getParties()).isEmpty(); + } + + @Test + void shouldNotAddPropertyToTheCasePartiesList() { + // Given - a property address and an existing real party + Party party = Party.builder().firstName("Jane").lastName("Doe").build(); + List> originalParties = ListValueUtils.wrapListItems(List.of(party)); + PCSCase pcsCase = PCSCase.builder() + .parties(originalParties) + .propertyAddress(AddressUK.builder().postCode("PR1 2PT").build()) + .build(); + + // When + underTest.buildSearchCriteria(pcsCase); + + // Then - the property is only added to the search criteria, not the real parties list + assertThat(pcsCase.getParties()).containsExactlyElementsOf(originalParties); + } +} From ab1c8d032816017ed83bf55f4f88a18906a580b9 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 4 Jun 2026 09:10:03 +0100 Subject: [PATCH 090/108] HDPI-4009 serach criteria separated out --- .../gov/hmcts/reform/pcs/ccd/PCSCaseView.java | 60 +----------- .../hmcts/reform/pcs/ccd/PCSCaseViewTest.java | 91 +++---------------- 2 files changed, 15 insertions(+), 136 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java index e430941000..12d431fa8f 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java @@ -8,8 +8,6 @@ import uk.gov.hmcts.ccd.sdk.type.AddressUK; import uk.gov.hmcts.ccd.sdk.type.Document; import uk.gov.hmcts.ccd.sdk.type.ListValue; -import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; -import uk.gov.hmcts.ccd.sdk.type.SearchParty; import uk.gov.hmcts.ccd.sdk.type.YesOrNo; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; @@ -38,13 +36,12 @@ import uk.gov.hmcts.reform.pcs.ccd.view.StatementOfTruthView; import uk.gov.hmcts.reform.pcs.ccd.view.TenancyLicenceView; import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.CaseFieldsView; +import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.SearchCriteriaIndexer; import uk.gov.hmcts.reform.pcs.ccd.view.CaseFlagsView; import uk.gov.hmcts.reform.pcs.exception.CaseNotFoundException; import uk.gov.hmcts.reform.pcs.security.SecurityContextService; -import java.util.Arrays; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; @@ -82,6 +79,7 @@ public class PCSCaseView implements CaseView { private final PartiesView partiesView; private final GenAppsView genAppsView; private final CaseFlagsView flagsView; + private final SearchCriteriaIndexer searchCriteriaIndexer; /** @@ -111,63 +109,11 @@ public PCSCase getCase(CaseViewRequest request) { caseFieldsView.setCaseFields(pcsCase); - pcsCase.setSearchCriteria(buildSearchCriteriaForIndexing(pcsCase)); + pcsCase.setSearchCriteria(searchCriteriaIndexer.buildSearchCriteria(pcsCase)); return pcsCase; } - private SearchCriteria buildSearchCriteriaForIndexing(PCSCase pcsCase) { - List searchParties = new ArrayList<>( - Optional.ofNullable(pcsCase.getParties()) - .orElse(List.of()) - .stream() - .map(ListValue::getValue) - .map(this::toSearchParty) - .toList()); - - // Global search only indexes postcodes that appear on a SearchParty. - // We add the property to be repossessed address as an extra SearchParty here to make it searchable. - SearchParty propertySearchParty = toPropertySearchParty(pcsCase.getPropertyAddress()); - if (propertySearchParty != null) { - searchParties.add(propertySearchParty); - } - - return SearchCriteria.builder() - .parties(ListValueUtils.wrapListItems(searchParties)) - .build(); - } - - private SearchParty toPropertySearchParty(AddressUK propertyAddress) { - if (propertyAddress == null - || propertyAddress.getPostCode() == null - || propertyAddress.getPostCode().isBlank()) { - return null; - } - - return SearchParty.builder() - .addressLine1(propertyAddress.getAddressLine1()) - .postcode(propertyAddress.getPostCode()) - .build(); - } - - private SearchParty toSearchParty(Party party) { - AddressUK address = party.getAddress(); - return SearchParty.builder() - .name(joinNonBlank(party.getFirstName(), party.getLastName())) - .emailAddress(party.getEmailAddress()) - .addressLine1(address == null ? null : address.getAddressLine1()) - .postcode(address == null ? null : address.getPostCode()) - .dateOfBirth(party.getDateOfBirth()) - .build(); - } - - private static String joinNonBlank(String... parts) { - String joined = Arrays.stream(parts) - .filter(p -> p != null && !p.isBlank()) - .collect(Collectors.joining(" ")); - return joined.isEmpty() ? null : joined; - } - private boolean caseHasUnsubmittedData(long caseReference, State state) { if (State.AWAITING_SUBMISSION_TO_HMCTS == state) { return draftCaseDataService.hasUnsubmittedCaseData(caseReference, resumePossessionClaim); diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java index 407370b5aa..169c439a79 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java @@ -11,7 +11,6 @@ import uk.gov.hmcts.ccd.sdk.type.AddressUK; import uk.gov.hmcts.ccd.sdk.type.ListValue; import uk.gov.hmcts.ccd.sdk.type.SearchCriteria; -import uk.gov.hmcts.ccd.sdk.type.SearchParty; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.State; @@ -43,6 +42,7 @@ import uk.gov.hmcts.reform.pcs.ccd.view.StatementOfTruthView; import uk.gov.hmcts.reform.pcs.ccd.view.TenancyLicenceView; import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.CaseFieldsView; +import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.SearchCriteriaIndexer; import uk.gov.hmcts.reform.pcs.exception.CaseNotFoundException; import uk.gov.hmcts.reform.pcs.postcodecourt.model.LegislativeCountry; import uk.gov.hmcts.reform.pcs.security.SecurityContextService; @@ -120,6 +120,8 @@ class PCSCaseViewTest { private PartiesView partiesView; @Mock private CaseFlagsView caseFlagsView; + @Mock + private SearchCriteriaIndexer searchCriteriaIndexer; private PCSCaseView underTest; @@ -133,7 +135,8 @@ void setUp() { alternativesToPossessionView, asbProhibitedConductView, rentArrearsView, noticeOfPossessionView, statementOfTruthView, caseFieldsView, caseLinkView, enforcementOrderMediator, - caseNoteView, caseTabView, partiesView, genAppsView, caseFlagsView + caseNoteView, caseTabView, partiesView, genAppsView, caseFlagsView, + searchCriteriaIndexer ); } @@ -196,87 +199,17 @@ void shouldMapPropertyAddress() { } @Test - void shouldIndexPropertyPostcodeAsSearchPartyWithoutPollutingParties() { - // Given - a property address with a postcode and no real parties - AddressEntity addressEntity = mock(AddressEntity.class); - when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); - AddressUK addressUK = stubAddressEntityModelMapper(addressEntity); - when(addressUK.getPostCode()).thenReturn("AB1 2CD"); - when(addressUK.getAddressLine1()).thenReturn("1 Test Street"); - - // When - PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); - - // Then - the property postcode is indexed as a SearchParty for global search - SearchCriteria searchCriteria = pcsCase.getSearchCriteria(); - assertThat(searchCriteria.getParties()) - .extracting(ListValue::getValue) - .extracting(SearchParty::getPostcode) - .contains("AB1 2CD"); - - // And the property is NOT added to the real parties list (no downstream pollution) - assertThat(pcsCase.getParties()).isEmpty(); - } - - @Test - void shouldIndexPropertyAddressLine1AndPostcodeOnSearchParty() { - // Given - a property address with both an address line and a postcode - AddressEntity addressEntity = mock(AddressEntity.class); - when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); - AddressUK addressUK = stubAddressEntityModelMapper(addressEntity); - when(addressUK.getPostCode()).thenReturn("AB1 2CD"); - when(addressUK.getAddressLine1()).thenReturn("1 Test Street"); - - // When - PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); - - // Then - both fields are copied onto the property SearchParty - assertThat(pcsCase.getSearchCriteria().getParties()) - .extracting(ListValue::getValue) - .anySatisfy(searchParty -> { - assertThat(searchParty.getAddressLine1()).isEqualTo("1 Test Street"); - assertThat(searchParty.getPostcode()).isEqualTo("AB1 2CD"); - }); - } - - @Test - void shouldNotIndexPropertyWhenAddressIsNull() { - // Given - no property address (pcsCaseEntity.getPropertyAddress() returns null) - - // When - PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); - - // Then - no property SearchParty is added - assertThat(pcsCase.getSearchCriteria().getParties()).isEmpty(); - } - - @Test - void shouldNotIndexPropertyWhenPostcodeIsNull() { - // Given - a property address with no postcode - AddressEntity addressEntity = mock(AddressEntity.class); - when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); - stubAddressEntityModelMapper(addressEntity); - - // When - PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); - - // Then - no property SearchParty is added - assertThat(pcsCase.getSearchCriteria().getParties()).isEmpty(); - } - - @Test - void shouldNotIndexPropertyWhenPostcodeIsBlank() { - // Given - a property address with a blank postcode - AddressEntity addressEntity = mock(AddressEntity.class); - when(pcsCaseEntity.getPropertyAddress()).thenReturn(addressEntity); - AddressUK addressUK = stubAddressEntityModelMapper(addressEntity); - when(addressUK.getPostCode()).thenReturn(" "); + void shouldSetSearchCriteriaFromIndexer() { + // Given + SearchCriteria searchCriteria = SearchCriteria.builder().build(); + when(searchCriteriaIndexer.buildSearchCriteria(any(PCSCase.class))).thenReturn(searchCriteria); // When PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE)); - // Then - no property SearchParty is added - assertThat(pcsCase.getSearchCriteria().getParties()).isEmpty(); + // Then - indexing is delegated to the indexer and its result is set on the case + verify(searchCriteriaIndexer).buildSearchCriteria(pcsCase); + assertThat(pcsCase.getSearchCriteria()).isSameAs(searchCriteria); } @Test From 931130ea4e3d9d71dfe00c569bbb2857bb58f09a Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 4 Jun 2026 10:34:45 +0100 Subject: [PATCH 091/108] HDPI-4009 merge conflcit --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java index 6e9bf56251..3640be4f98 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/CaseType.java @@ -175,7 +175,7 @@ private void buildSummaryTab(ConfigBuilder builde .field("summaryTab_NoticeDetails"); } - private void buildCaseDetailsTab(ConfigBuilder builder) { + private void buildCaseDetailsTab(ConfigBuilder builder) { builder.tab("caseDetails", "Case Details") .label("Case details", null, "# Case details") .field("detailsTab_ClaimDetails") From e91dfac54508053c4c55f4c190b07e79d752da17 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 4 Jun 2026 11:30:17 +0100 Subject: [PATCH 092/108] HDPI-4009 merge conflcit --- .../reform/pcs/ccd/view/CaseTabView.java | 21 +++++++++++++------ .../hmcts/reform/pcs/ccd/CaseTypeTest.java | 3 ++- .../reform/pcs/ccd/view/CaseTabViewTest.java | 19 +++++++++++------ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java index 6ff8c8ae81..7bdcb5595a 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java @@ -9,6 +9,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.DemotionOfTenancy; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; +import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.SuspensionOfRightToBuy; import uk.gov.hmcts.reform.pcs.ccd.domain.SuspensionOfRightToBuyDemotionOfTenancy; @@ -144,13 +145,21 @@ private ListValue buildUnderlesseeOrMortgageParty( } private ListValue buildUnderlesseeOrMortgageParty(UnderlesseeMortgageeDetails underlesseeMortgageeDetails) { + Party.PartyBuilder partyBuilder = Party.builder() + .nameKnown(underlesseeMortgageeDetails.getNameKnown()) + .addressKnown(underlesseeMortgageeDetails.getAddressKnown()) + .address(underlesseeMortgageeDetails.getAddress()); + + if (underlesseeMortgageeDetails.getPartyType() == IndividualOrOrganisation.INDIVIDUAL) { + partyBuilder + .firstName(underlesseeMortgageeDetails.getFirstName()) + .lastName(underlesseeMortgageeDetails.getLastName()); + } else { + partyBuilder.orgName(underlesseeMortgageeDetails.getOrganisationName()); + } + return ListValue.builder() - .value(Party.builder() - .nameKnown(underlesseeMortgageeDetails.getNameKnown()) - .orgName(underlesseeMortgageeDetails.getName()) - .addressKnown(underlesseeMortgageeDetails.getAddressKnown()) - .address(underlesseeMortgageeDetails.getAddress()) - .build()) + .value(partyBuilder.build()) .build(); } diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java index c4896750c5..903df960f6 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/CaseTypeTest.java @@ -72,7 +72,8 @@ void shouldConfigureCaseTypeTabs() { final TabBuilder caseFileViewTabBuilder = TabBuilder.builder(PCSCase.class, utils); final TabBuilder casePartiesTabBuilder = TabBuilder.builder(PCSCase.class, utils); final Tab.TabBuilder caseFlagsTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); - final Tab.TabBuilder caseDetailsTabBuilder = Tab.TabBuilder.builder(PCSCase.class, utils); + final Tab.TabBuilder caseDetailsTabBuilder = + Tab.TabBuilder.builder(PCSCase.class, utils); final Search.SearchBuilder searchBuilder = Search.SearchBuilder.builder(PCSCase.class, utils); final SearchCases.SearchCasesBuilder searchCasesBuilder = diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java index 6550ee75ed..1a054a6b8a 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java @@ -10,6 +10,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.DemotionOfTenancy; import uk.gov.hmcts.reform.pcs.ccd.domain.DemotionOfTenancyHousingAct; +import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.SuspensionOfRightToBuy; @@ -531,12 +532,15 @@ void shouldNotOverwriteExistingDraftDefendantsWhenDefendantOneIsMissing() { @Test void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsMoreThanOneParty() { - // Given - String name1 = "name1"; + // Given - an individual underlessee/mortgagee + String firstName1 = "first1"; + String lastName1 = "last1"; AddressUK address1 = AddressUK.builder().build(); UnderlesseeMortgageeDetails underlesseeMortgageeDetails1 = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name(name1) + .partyType(IndividualOrOrganisation.INDIVIDUAL) + .firstName(firstName1) + .lastName(lastName1) .addressKnown(VerticalYesNo.YES) .address(address1) .build(); @@ -578,7 +582,9 @@ void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsMoreThanOneParty() { assertThat(allUnderlesseeOrMortgagees).hasSize(2); Party party1 = allUnderlesseeOrMortgagees.getFirst().getValue(); assertThat(party1.getNameKnown()).isEqualTo(VerticalYesNo.YES); - assertThat(party1.getOrgName()).isEqualTo(name1); + assertThat(party1.getFirstName()).isEqualTo(firstName1); + assertThat(party1.getLastName()).isEqualTo(lastName1); + assertThat(party1.getOrgName()).isNull(); assertThat(party1.getAddressKnown()).isEqualTo(VerticalYesNo.YES); assertThat(party1.getAddress()).isEqualTo(address1); @@ -591,12 +597,13 @@ void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsMoreThanOneParty() { @Test void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsOnlyOneParty() { - // Given + // Given - an organisation underlessee/mortgagee String name1 = "name1"; AddressUK address1 = AddressUK.builder().build(); UnderlesseeMortgageeDetails underlesseeMortgageeDetails1 = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .name(name1) + .partyType(IndividualOrOrganisation.ORGANISATION) + .organisationName(name1) .addressKnown(VerticalYesNo.YES) .address(address1) .build(); From d88ec31570113320601226bd149a76c9259912ba Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 4 Jun 2026 17:04:19 +0100 Subject: [PATCH 093/108] HDPI-4009 also index org name --- .../globalsearch/SearchCriteriaIndexer.java | 6 +- .../SearchCriteriaIndexerTest.java | 65 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java index 4c19ae70f2..815bc7e197 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java @@ -15,6 +15,8 @@ import java.util.Optional; import java.util.stream.Collectors; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + /** * Builds the {@link SearchCriteria} used to index a case for global search. * @@ -66,7 +68,9 @@ private SearchParty toPropertySearchParty(AddressUK propertyAddress) { private SearchParty toSearchParty(Party party) { AddressUK address = party.getAddress(); return SearchParty.builder() - .name(joinNonBlank(party.getFirstName(), party.getLastName())) + .name(isNotBlank(party.getOrgName()) + ? party.getOrgName() + : joinNonBlank(party.getFirstName(), party.getLastName())) .emailAddress(party.getEmailAddress()) .addressLine1(address == null ? null : address.getAddressLine1()) .postcode(address == null ? null : address.getPostCode()) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java index 2ed7ae1eb1..8ae1686dc4 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java @@ -93,6 +93,71 @@ void shouldSetNullNameWhenNoNamePartsKnown() { .isNull(); } + @Test + void shouldUseOrgNameAsSearchPartyNameWhenPresent() { + // Given - an organisation party + Party party = Party.builder().orgName("Acme Ltd").build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .extracting(SearchParty::getName) + .isEqualTo("Acme Ltd"); + } + + @Test + void shouldPreferOrgNameOverIndividualNameWhenBothPresent() { + // Given - a party with both an org name and individual name parts + Party party = Party.builder() + .orgName("Acme Ltd") + .firstName("Jane") + .lastName("Doe") + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - the org name takes precedence + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .extracting(SearchParty::getName) + .isEqualTo("Acme Ltd"); + } + + @Test + void shouldFallBackToIndividualNameWhenOrgNameIsBlank() { + // Given - a blank org name but a known individual name + Party party = Party.builder() + .orgName(" ") + .firstName("Jane") + .lastName("Doe") + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - the blank org name is ignored and the individual name is used + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .extracting(SearchParty::getName) + .isEqualTo("Jane Doe"); + } + @Test void shouldHandlePartyWithNoAddress() { // Given - a party with no address From 8e4e64576a368f02acab1c3ded603008081eb056 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 9 Jun 2026 11:05:50 +0100 Subject: [PATCH 094/108] HDPI-5335 remove out of scope changes --- .../ccd/domain/IndividualOrOrganisation.java | 25 --------------- .../domain/UnderlesseeMortgageeDetails.java | 25 +++------------ .../UnderlesseeOrMortgageeDetailsPage.java | 10 ++---- .../pcs/ccd/service/party/PartyService.java | 8 +---- .../reform/pcs/ccd/view/CaseTabView.java | 21 ++++--------- .../pcs/ccd/service/PartyServiceTest.java | 31 ++++++------------- .../reform/pcs/ccd/view/CaseTabViewTest.java | 19 ++++-------- 7 files changed, 29 insertions(+), 110 deletions(-) delete mode 100644 src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java deleted file mode 100644 index 8ae570a05c..0000000000 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/IndividualOrOrganisation.java +++ /dev/null @@ -1,25 +0,0 @@ -package uk.gov.hmcts.reform.pcs.ccd.domain; - -import uk.gov.hmcts.ccd.sdk.api.HasLabel; - -/** - * Indicates whether a party is an individual (a person) or an organisation, - * so their name can be captured and stored in the appropriate fields. - */ -public enum IndividualOrOrganisation implements HasLabel { - - INDIVIDUAL("Individual"), - ORGANISATION("Organisation"); - - private final String label; - - IndividualOrOrganisation(String label) { - this.label = label; - } - - @Override - public String getLabel() { - return label; - } - -} diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java index 354299a516..5e522c903e 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/UnderlesseeMortgageeDetails.java @@ -24,29 +24,12 @@ public class UnderlesseeMortgageeDetails { @CCD(label = "Do you know the underlessee or mortgagee’s name?") private VerticalYesNo nameKnown; - @CCD(label = "Is the underlessee or mortgagee an individual or an organisation?", - showCondition = "nameKnown=\"YES\"" - ) - private IndividualOrOrganisation partyType; - - @CCD(label = "First name", - showCondition = "nameKnown=\"YES\" AND partyType=\"INDIVIDUAL\"", - max = 60 - ) - private String firstName; - - @CCD(label = "Last name", - showCondition = "nameKnown=\"YES\" AND partyType=\"INDIVIDUAL\"", - max = 60 - ) - private String lastName; - - @CCD(label = "What is the organisation’s name?", - hint = "Enter the company or organisation name", - showCondition = "nameKnown=\"YES\" AND partyType=\"ORGANISATION\"", + @CCD(label = "What is their name?", + hint = "Enter their first and last name, or the company or organisation name", + showCondition = "nameKnown=\"YES\"", max = 60 ) - private String organisationName; + private String name; @CCD(label = """ --- diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java index ff554f6cdd..1459b9bc13 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/page/resumepossessionclaim/UnderlesseeOrMortgageeDetailsPage.java @@ -33,10 +33,7 @@ public void addTo(PageBuilder pageBuilder) { .complex(PCSCase::getUnderlesseeOrMortgagee1) .readonlyNoSummary(UnderlesseeMortgageeDetails::getNameSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getNameKnown) - .mandatory(UnderlesseeMortgageeDetails::getPartyType) - .mandatory(UnderlesseeMortgageeDetails::getFirstName) - .mandatory(UnderlesseeMortgageeDetails::getLastName) - .mandatory(UnderlesseeMortgageeDetails::getOrganisationName) + .mandatory(UnderlesseeMortgageeDetails::getName) .readonlyNoSummary(UnderlesseeMortgageeDetails::getAddressSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getAddressKnown) .complex(UnderlesseeMortgageeDetails::getAddress) @@ -58,10 +55,7 @@ public void addTo(PageBuilder pageBuilder) { "addAdditionalUnderlesseeOrMortgagee=\"YES\"") .readonlyNoSummary(UnderlesseeMortgageeDetails::getNameSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getNameKnown) - .mandatory(UnderlesseeMortgageeDetails::getPartyType) - .mandatory(UnderlesseeMortgageeDetails::getFirstName) - .mandatory(UnderlesseeMortgageeDetails::getLastName) - .mandatory(UnderlesseeMortgageeDetails::getOrganisationName) + .mandatory(UnderlesseeMortgageeDetails::getName) .readonlyNoSummary(UnderlesseeMortgageeDetails::getAddressSectionLabel) .mandatory(UnderlesseeMortgageeDetails::getAddressKnown) .complex(UnderlesseeMortgageeDetails::getAddress) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java index 345d8810af..983f84402f 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/service/party/PartyService.java @@ -9,7 +9,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantContactPreferences; import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantInformation; import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; -import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.UnderlesseeMortgageeDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; @@ -219,12 +218,7 @@ private PartyEntity createUnderlesseeOrMortgagee(UnderlesseeMortgageeDetails und VerticalYesNo nameKnown = underlesseeMortgageeDetails.getNameKnown(); underlesseeMortgageeEntity.setNameKnown(nameKnown); if (nameKnown == VerticalYesNo.YES) { - if (underlesseeMortgageeDetails.getPartyType() == IndividualOrOrganisation.INDIVIDUAL) { - underlesseeMortgageeEntity.setFirstName(underlesseeMortgageeDetails.getFirstName()); - underlesseeMortgageeEntity.setLastName(underlesseeMortgageeDetails.getLastName()); - } else { - underlesseeMortgageeEntity.setOrgName(underlesseeMortgageeDetails.getOrganisationName()); - } + underlesseeMortgageeEntity.setOrgName(underlesseeMortgageeDetails.getName()); } VerticalYesNo addressKnown = underlesseeMortgageeDetails.getAddressKnown(); diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java index 7bdcb5595a..6ff8c8ae81 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabView.java @@ -9,7 +9,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.DemotionOfTenancy; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; -import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.SuspensionOfRightToBuy; import uk.gov.hmcts.reform.pcs.ccd.domain.SuspensionOfRightToBuyDemotionOfTenancy; @@ -145,21 +144,13 @@ private ListValue buildUnderlesseeOrMortgageParty( } private ListValue buildUnderlesseeOrMortgageParty(UnderlesseeMortgageeDetails underlesseeMortgageeDetails) { - Party.PartyBuilder partyBuilder = Party.builder() - .nameKnown(underlesseeMortgageeDetails.getNameKnown()) - .addressKnown(underlesseeMortgageeDetails.getAddressKnown()) - .address(underlesseeMortgageeDetails.getAddress()); - - if (underlesseeMortgageeDetails.getPartyType() == IndividualOrOrganisation.INDIVIDUAL) { - partyBuilder - .firstName(underlesseeMortgageeDetails.getFirstName()) - .lastName(underlesseeMortgageeDetails.getLastName()); - } else { - partyBuilder.orgName(underlesseeMortgageeDetails.getOrganisationName()); - } - return ListValue.builder() - .value(partyBuilder.build()) + .value(Party.builder() + .nameKnown(underlesseeMortgageeDetails.getNameKnown()) + .orgName(underlesseeMortgageeDetails.getName()) + .addressKnown(underlesseeMortgageeDetails.getAddressKnown()) + .address(underlesseeMortgageeDetails.getAddress()) + .build()) .build(); } diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java index d9ffff3049..12c8811866 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/service/PartyServiceTest.java @@ -17,7 +17,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantContactPreferences; import uk.gov.hmcts.reform.pcs.ccd.domain.ClaimantInformation; import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; -import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.UnderlesseeMortgageeDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; @@ -936,17 +935,14 @@ void shouldBuildListWithMultipleUnderlessees() { UnderlesseeMortgageeDetails underlessee1Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.INDIVIDUAL) - .firstName("underlessee 1 first name") - .lastName("underlessee 1 last name") + .name("underlessee 1 name") .addressKnown(VerticalYesNo.YES) .address(underlessee1Address) .build(); UnderlesseeMortgageeDetails underlessee2Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.ORGANISATION) - .organisationName("underlessee 2 name") + .name("underlessee 2 name") .addressKnown(VerticalYesNo.NO) .build(); @@ -963,8 +959,7 @@ void shouldBuildListWithMultipleUnderlessees() { PartyEntity expectedUnderlessee1 = PartyEntity.builder() .nameKnown(VerticalYesNo.YES) - .firstName("underlessee 1 first name") - .lastName("underlessee 1 last name") + .orgName("underlessee 1 name") .addressKnown(VerticalYesNo.YES) .address(mappedUnderlessee1Address) .build(); @@ -1012,16 +1007,14 @@ void shouldIgnoreMultipleUnderlesseesIfAdditionalUnderlesseesNotIndicated() { UnderlesseeMortgageeDetails underlessee1Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.ORGANISATION) - .organisationName("underlessee 1 name") + .name("underlessee 1 name") .addressKnown(VerticalYesNo.YES) .address(underlessee1Address) .build(); UnderlesseeMortgageeDetails underlessee2Details = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.ORGANISATION) - .organisationName("underlessee 2 name") + .name("underlessee 2 name") .addressKnown(VerticalYesNo.NO) .build(); @@ -1063,27 +1056,23 @@ private static Stream singleUnderlesseeScenarios() { .build() ), argumentSet( - "Individual name known, address not known", + "Name known, address not known", UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.INDIVIDUAL) - .firstName("expected first name") - .lastName("expected last name") + .name("expected underlessee name") .addressKnown(VerticalYesNo.NO) .build(), PartyEntity.builder() .nameKnown(VerticalYesNo.YES) - .firstName("expected first name") - .lastName("expected last name") + .orgName("expected underlessee name") .addressKnown(VerticalYesNo.NO) .build() ), argumentSet( - "Organisation name known, address known", + "Name known, address known", UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.ORGANISATION) - .organisationName("expected underlessee name") + .name("expected underlessee name") .addressKnown(VerticalYesNo.YES) .address(correspondenceAddress) .build(), diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java index 1a054a6b8a..6550ee75ed 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseTabViewTest.java @@ -10,7 +10,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.DefendantDetails; import uk.gov.hmcts.reform.pcs.ccd.domain.DemotionOfTenancy; import uk.gov.hmcts.reform.pcs.ccd.domain.DemotionOfTenancyHousingAct; -import uk.gov.hmcts.reform.pcs.ccd.domain.IndividualOrOrganisation; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.SuspensionOfRightToBuy; @@ -532,15 +531,12 @@ void shouldNotOverwriteExistingDraftDefendantsWhenDefendantOneIsMissing() { @Test void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsMoreThanOneParty() { - // Given - an individual underlessee/mortgagee - String firstName1 = "first1"; - String lastName1 = "last1"; + // Given + String name1 = "name1"; AddressUK address1 = AddressUK.builder().build(); UnderlesseeMortgageeDetails underlesseeMortgageeDetails1 = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.INDIVIDUAL) - .firstName(firstName1) - .lastName(lastName1) + .name(name1) .addressKnown(VerticalYesNo.YES) .address(address1) .build(); @@ -582,9 +578,7 @@ void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsMoreThanOneParty() { assertThat(allUnderlesseeOrMortgagees).hasSize(2); Party party1 = allUnderlesseeOrMortgagees.getFirst().getValue(); assertThat(party1.getNameKnown()).isEqualTo(VerticalYesNo.YES); - assertThat(party1.getFirstName()).isEqualTo(firstName1); - assertThat(party1.getLastName()).isEqualTo(lastName1); - assertThat(party1.getOrgName()).isNull(); + assertThat(party1.getOrgName()).isEqualTo(name1); assertThat(party1.getAddressKnown()).isEqualTo(VerticalYesNo.YES); assertThat(party1.getAddress()).isEqualTo(address1); @@ -597,13 +591,12 @@ void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsMoreThanOneParty() { @Test void shouldSetDraftUnderlesseeOrMortgagePartiesWhenThereIsOnlyOneParty() { - // Given - an organisation underlessee/mortgagee + // Given String name1 = "name1"; AddressUK address1 = AddressUK.builder().build(); UnderlesseeMortgageeDetails underlesseeMortgageeDetails1 = UnderlesseeMortgageeDetails.builder() .nameKnown(VerticalYesNo.YES) - .partyType(IndividualOrOrganisation.ORGANISATION) - .organisationName(name1) + .name(name1) .addressKnown(VerticalYesNo.YES) .address(address1) .build(); From 9eab21f4698b97fe4d7ae30b170d3cd0a9912667 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Tue, 9 Jun 2026 11:48:47 +0100 Subject: [PATCH 095/108] HDPI-5335 remove out of scope changes --- .../resources/cftlib-am-role-assignments.json | 32 ------------------- .../pcs/ccd/accesscontrol/UserRole.java | 1 + 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/src/cftlib/resources/cftlib-am-role-assignments.json b/src/cftlib/resources/cftlib-am-role-assignments.json index a850b57a67..a76894ca41 100644 --- a/src/cftlib/resources/cftlib-am-role-assignments.json +++ b/src/cftlib/resources/cftlib-am-role-assignments.json @@ -15,37 +15,5 @@ "authorisations": [] } ] - }, - { - "email": "pcs-solicitor1@test.com", - "id": "f6484bbb-c10e-319b-ab8d-14361a7d2a23", - "roleAssignments": [ - { - "roleType": "ORGANISATION", - "roleName": "hmcts-admin", - "grantType": "STANDARD", - "roleCategory": "ADMIN", - "classification": "PUBLIC", - "readOnly": false, - "attributes": {}, - "authorisations": [] - } - ] - }, - { - "email": "pcs-solicitor1@test.com", - "id": "f6484bbb-c10e-319b-ab8d-14361a7d2a23", - "roleAssignments": [ - { - "roleType": "ORGANISATION", - "roleName": "[HMCTS-ADMIN]", - "grantType": "STANDARD", - "roleCategory": "ADMIN", - "classification": "PUBLIC", - "readOnly": false, - "attributes": {}, - "authorisations": [] - } - ] } ] diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java index 04debe65ef..037f90ca61 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/UserRole.java @@ -43,6 +43,7 @@ public enum UserRole implements HasRole { JUDGE("judge", Set.of(R), RAS), SYSTEM_USER("pcs-system-update", Permission.CRU, IDAM); + @JsonValue private final String role; private final Set caseTypePermissions; From 966329fa2c572ae9842480ddc649cfb08848d114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CKunchhal?= <“ankita.kunchhal@hmcts.net”> Date: Wed, 10 Jun 2026 09:30:09 +0100 Subject: [PATCH 096/108] Add global search functionality and enhance validation with retry logic --- .../globalSearch.page.data.ts | 3 +- .../CommonComponent/globalSearch.spec.ts | 38 ++++++++- .../commonComponent/globalSearch.action.ts | 79 ++++++++++++++++--- src/e2eTest/utils/registry/action.registry.ts | 1 + 4 files changed, 107 insertions(+), 14 deletions(-) diff --git a/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts b/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts index c1c17affac..826ad0a551 100644 --- a/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts +++ b/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts @@ -46,5 +46,6 @@ export const globalSearch = searchButton: 'Search', invalidCaseReferenceInputText: '0000000000000000', invalidPostcodeInputText: 'ZZ99 9ZZ', - invalidNameInputText: 'XYZ_NonExistent_Name_ABC' + invalidNameInputText: 'XYZ_NonExistent_Name_ABC', + nextLink: 'Next page' } diff --git a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts index 13a9bf34c2..aa929ba560 100644 --- a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts +++ b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts @@ -1,4 +1,5 @@ import { test } from '@utils/test-fixtures'; +import { expect } from '@playwright/test'; import { initializeExecutor, performAction, performValidation } from '@utils/controller'; import { globalSearch} from '@data/page-data-figma'; import { dismissCookieBanner } from '@config/cookie-banner'; @@ -60,7 +61,40 @@ const runGlobalSearchScenarios = () => { await performAction('searchByCaseReference', process.env.CASE_NUMBER); await performAction('validateResults'); }); + + test('Search by postcode', async ({ page }) => { + await performAction('accessingTheSearch'); + await performAction('inputText', globalSearch.postCodeLabel, globalSearch.postcodeInputText); + await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); + await performAction('clickButton', globalSearch.searchButton); + await page.locator('button[type="submit"]').click(); + await performAction('validateResultsWithRetry'); + }); + + test('Search by email address', async ({ page }) => { + await performAction('accessingTheSearch'); + await performAction('inputText', globalSearch.emailAddressLabel, globalSearch.emailAddressInputText); + await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); + await performAction('clickButton', globalSearch.searchButton); + await page.locator('button[type="submit"]').click(); + }); + + test('first line of address', async ({ page }) => { + await performAction('accessingTheSearch'); + await performAction('inputText', globalSearch.firstLineOfAddressLabel, globalSearch.firstLineOfAddressInputText); + await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); + await performAction('clickButton', globalSearch.searchButton); + await page.locator('button[type="submit"]').click(); + }); + test('Search by party name', async ({ page }) => { + await performAction('accessingTheSearch'); + await performAction('inputText', globalSearch.nameLabel, globalSearch.nameInputText); + await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); + await performAction('clickButton', globalSearch.searchButton); + await page.locator('button[type="submit"]').click(); + }); + test('Invalid case reference', async () => { await performAction('accessingTheSearch'); await performAction('invalidCaseReferenceSearch', globalSearch.invalidCaseReferenceInputText); @@ -75,9 +109,9 @@ const runGlobalSearchScenarios = () => { [ { roleName: 'CTSC User', account: user.ctscAdministrator }, - { roleName: 'Judge', account: user.judge } + { roleName: 'Judge User', account: user.judge } ].forEach(({ roleName, account }) => { - test.describe(`[Global Search - ${roleName} - @globalSearch @CC @nightly]`, () => { + test.describe(`[Common Component Global Search - ${roleName}] @CC @globalSearch @nightly`, () => { test.beforeEach(async ({ page, context }) => { await setupGlobalSearchUser(page, context, account); }); diff --git a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts index 2fe1d6e8e1..1d83b3258b 100644 --- a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts +++ b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts @@ -1,4 +1,4 @@ -import { expect, Page } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; import { performAction, performValidation } from '../../../controller'; import { actionRecord, IAction } from '@utils/interfaces'; import { globalSearch, noResultFound, searchResults, workAccess } from '@data/page-data-figma'; @@ -9,10 +9,11 @@ export class GlobalSearchCaseAction implements IAction { const actionsMap = new Map Promise>([ ['accessingTheSearch', () => this.accessingTheSearch(page)], ['searchByCaseReference', () => this.searchByCaseReference(fieldName as string, page)], - ['invalidCaseReferenceSearch', () => this.invalidCaseReferenceSearch(fieldName as string, page)], - ['changeSearchLink', () => this.changeSearchLink(fieldName as string, page)], + ['invalidCaseReferenceSearch', () => this.invalidCaseReferenceSearch(page)], + ['changeSearchLink', () => this.changeSearchLink(page)], ['handleJudgeBookingPage', () => this.handleJudgeBookingPage(page)], - ['validateResults', () => this.validateResults(page)] + ['validateResults', () => this.validateResults(page)], + ['validateResultsWithRetry', () => this.validateResultsWithRetry(page)] ]); const actionToPerform = actionsMap.get(action); @@ -32,7 +33,7 @@ export class GlobalSearchCaseAction implements IAction { await performValidation('mainHeader', searchResults.mainHeader); } - private async invalidCaseReferenceSearch(invalidCaseReference: string, page: Page): Promise { + private async invalidCaseReferenceSearch(page: Page): Promise { await performAction('inputText', globalSearch.DigitCaseReferenceLabel, globalSearch.invalidCaseReferenceInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption1); await performAction('clickButton', globalSearch.searchButton); @@ -40,7 +41,7 @@ export class GlobalSearchCaseAction implements IAction { await performValidation('mainHeader', noResultFound.mainHeader); } - private async changeSearchLink(changeSearch: string, page: Page): Promise { + private async changeSearchLink(page: Page): Promise { await performAction('clickLink', searchResults.changeSearchLink); await performValidation('mainHeader', globalSearch.mainHeader); } @@ -55,13 +56,16 @@ export class GlobalSearchCaseAction implements IAction { private async validateResults(page: Page): Promise { const caseReference = String(process.env.CASE_NUMBER ?? ''); - const resultRow = page.locator('tr').filter({ hasText: caseReference }); - const caseCell = resultRow.locator('td').first(); + const normalizedCaseReference = caseReference.replace(/\D/g, ''); await expect(page.getByRole('heading', { name: searchResults.mainHeader })).toBeVisible(); - await expect(resultRow).toContainText(caseReference); - await expect(caseCell).toContainText(caseReference); + + const resultRow = await this.findCaseReferenceRowAcrossPages(page, normalizedCaseReference); + const caseCell = resultRow.locator('td').first(); const caseCellText = (await caseCell.innerText()).trim(); - const caseNameText = caseCellText.replace(caseReference, '').trim(); + const normalizedCellText = caseCellText.replace(/\D/g, ''); + const formattedCaseReference = caseReference.replace(/(\d{4})(?=\d)/g, '$1-'); + expect(normalizedCellText).toContain(normalizedCaseReference); + const caseNameText = caseCellText.replace(caseReference, '').replace(formattedCaseReference, '').trim(); expect(caseNameText.length).toBeGreaterThan(0); await expect(resultRow).toContainText(searchResults.serviceLabel); await expect(resultRow).toContainText(searchResults.stateLabel); @@ -71,4 +75,57 @@ export class GlobalSearchCaseAction implements IAction { await performAction('clickTab', home.caseSummary); await performValidation('mainHeader', home.caseSummary); } + + private async validateResultsWithRetry(page: Page): Promise { + const attempts = 6; + const waitMs = 5000; + + for (let attempt = 1; attempt <= attempts; attempt++) { + try { + await this.validateResults(page); + return; + } catch (error: any) { + const shouldRetry = String(error?.message ?? '').includes('was not found on any paginated search result page'); + if (!shouldRetry || attempt === attempts) { + throw error; + } + + await page.waitForTimeout(waitMs); + await page.reload({ waitUntil: 'domcontentloaded' }); + await expect(page.getByRole('heading', { name: searchResults.mainHeader })).toBeVisible(); + } + } + } + + private async findCaseReferenceRowAcrossPages(page: Page, normalizedCaseReference: string): Promise { + const maxPagesToScan = 50; + const rows = page.locator('tbody tr'); + + for (let pageIndex = 0; pageIndex < maxPagesToScan; pageIndex++) { + const rowCount = await rows.count(); + for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) { + const row = rows.nth(rowIndex); + const firstCellText = (await row.locator('td').first().innerText()).trim(); + const normalizedRowCaseReference = firstCellText.replace(/\D/g, ''); + if (normalizedRowCaseReference.includes(normalizedCaseReference)) { + return row; + } + } + + const nextPageLink = page.getByRole('link', { name: globalSearch.nextLink, exact: true }); + if ((await nextPageLink.count()) === 0 || !(await nextPageLink.isVisible())) { + break; + } + + const currentPageMarker = page.locator('.hmcts-pagination__item--current').first(); + const previousMarkerText = (await currentPageMarker.count()) > 0 ? (await currentPageMarker.innerText()).trim() : ''; + await nextPageLink.click(); + if (previousMarkerText) { + await expect(currentPageMarker).not.toHaveText(previousMarkerText, { timeout: 10000 }); + } + await expect(rows.first()).toBeVisible({ timeout: 10000 }); + } + + throw new Error(`Case reference '${normalizedCaseReference}' was not found on any paginated search result page.`); + } } \ No newline at end of file diff --git a/src/e2eTest/utils/registry/action.registry.ts b/src/e2eTest/utils/registry/action.registry.ts index 5c3d56e0bc..9a1e1c4a56 100644 --- a/src/e2eTest/utils/registry/action.registry.ts +++ b/src/e2eTest/utils/registry/action.registry.ts @@ -98,6 +98,7 @@ export class ActionRegistry { ['changeSearchLink', new GlobalSearchCaseAction()], ['handleJudgeBookingPage', new GlobalSearchCaseAction()], ['validateResults', new GlobalSearchCaseAction()], + ['validateResultsWithRetry', new GlobalSearchCaseAction()], ['selectClaimingCosts', new CreateCaseAction()], ['wantToUploadDocuments', new CreateCaseAction()], ['uploadAdditionalDocs', new CreateCaseAction()], From 718e67b330e286b09aacfa6407b2d9061cd3ad1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CKunchhal?= <“ankita.kunchhal@hmcts.net”> Date: Wed, 10 Jun 2026 10:17:28 +0100 Subject: [PATCH 097/108] Add PR tag --- src/e2eTest/tests/CommonComponent/globalSearch.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts index aa929ba560..1d531ddff5 100644 --- a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts +++ b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts @@ -111,7 +111,7 @@ const runGlobalSearchScenarios = () => { { roleName: 'CTSC User', account: user.ctscAdministrator }, { roleName: 'Judge User', account: user.judge } ].forEach(({ roleName, account }) => { - test.describe(`[Common Component Global Search - ${roleName}] @CC @globalSearch @nightly`, () => { + test.describe(`[Common Component Global Search - ${roleName}] @CC @globalSearch @nightly @PR`, () => { test.beforeEach(async ({ page, context }) => { await setupGlobalSearchUser(page, context, account); }); From 75b8729889b730df4199d25a28fedb1121c54313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CKunchhal?= <“ankita.kunchhal@hmcts.net”> Date: Wed, 10 Jun 2026 11:46:19 +0100 Subject: [PATCH 098/108] Revert "Add PR tag" This reverts commit 718e67b330e286b09aacfa6407b2d9061cd3ad1d. --- src/e2eTest/tests/CommonComponent/globalSearch.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts index 87e26b153c..ffa0dcb5ab 100644 --- a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts +++ b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts @@ -111,7 +111,6 @@ const runGlobalSearchScenarios = () => { { roleName: 'CTSC User', account: user.ctscAdministrator }, { roleName: 'Judge User', account: user.judge } ].forEach(({ roleName, account }) => { - test.describe(`[Common Component Global Search - ${roleName}] @CC @globalSearch @nightly @PR`, () => { test.describe(`[Global Search - ${roleName} - @nightly @CC @caseFlags]`, () => { test.beforeEach(async ({ page, context }) => { await setupGlobalSearchUser(page, context, account); From 12782d88784e43514cfd3df59c2ef60c056ad5ac Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 11 Jun 2026 10:00:20 +0100 Subject: [PATCH 099/108] HDPI-5335 update searchparties to include address for all parties when matching --- .../globalsearch/SearchCriteriaIndexer.java | 17 +++-- .../SearchCriteriaIndexerTest.java | 65 +++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java index 815bc7e197..549f1033bb 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java @@ -7,6 +7,7 @@ import uk.gov.hmcts.ccd.sdk.type.SearchParty; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; +import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; import java.util.ArrayList; @@ -32,17 +33,19 @@ public class SearchCriteriaIndexer { * @return search criteria covering the case parties and the property to be repossessed */ public SearchCriteria buildSearchCriteria(PCSCase pcsCase) { + AddressUK propertyAddress = pcsCase.getPropertyAddress(); + List searchParties = new ArrayList<>( Optional.ofNullable(pcsCase.getParties()) .orElse(List.of()) .stream() .map(ListValue::getValue) - .map(this::toSearchParty) + .map(party -> toSearchParty(party, propertyAddress)) .toList()); // Global search only indexes postcodes that appear on a SearchParty. // We add the property to be repossessed address as an extra SearchParty here to make it searchable. - SearchParty propertySearchParty = toPropertySearchParty(pcsCase.getPropertyAddress()); + SearchParty propertySearchParty = toPropertySearchParty(propertyAddress); if (propertySearchParty != null) { searchParties.add(propertySearchParty); } @@ -65,8 +68,14 @@ private SearchParty toPropertySearchParty(AddressUK propertyAddress) { .build(); } - private SearchParty toSearchParty(Party party) { - AddressUK address = party.getAddress(); + private SearchParty toSearchParty(Party party, AddressUK propertyAddress) { + // When a party's address is the same as the property to be repossessed, the address is not + // duplicated on the party — only the addressSameAsProperty flag is stored. We resolve it back + // to the property address here so the party's SearchParty carries both the name and postcode, + // allowing a combined name + postcode global search to match within a single SearchParty. + AddressUK address = party.getAddressSameAsProperty() == VerticalYesNo.YES + ? propertyAddress + : party.getAddress(); return SearchParty.builder() .name(isNotBlank(party.getOrgName()) ? party.getOrgName() diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java index 8ae1686dc4..a04389d2e6 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java @@ -7,6 +7,7 @@ import uk.gov.hmcts.ccd.sdk.type.SearchParty; import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase; import uk.gov.hmcts.reform.pcs.ccd.domain.Party; +import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; import java.time.LocalDate; @@ -182,6 +183,70 @@ void shouldHandlePartyWithNoAddress() { }); } + @Test + void shouldUsePropertyAddressForPartyWhenAddressIsSameAsProperty() { + // Given - a party whose address is the same as the property, so it carries no address of its + // own (only the flag). The property address must be resolved onto the party's SearchParty so a + // combined name + postcode search matches within a single object. + Party party = Party.builder() + .firstName("John") + .lastName("Doe") + .addressSameAsProperty(VerticalYesNo.YES) + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .propertyAddress(AddressUK.builder() + .addressLine1("2 Second Avenue") + .postCode("W3 7RX") + .build()) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - the party SearchParty carries both the name and the property postcode + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .anySatisfy(searchParty -> { + assertThat(searchParty.getName()).isEqualTo("John Doe"); + assertThat(searchParty.getAddressLine1()).isEqualTo("2 Second Avenue"); + assertThat(searchParty.getPostcode()).isEqualTo("W3 7RX"); + }); + } + + @Test + void shouldUsePartyOwnAddressWhenAddressIsNotSameAsProperty() { + // Given - a party with its own address that differs from the property + Party party = Party.builder() + .firstName("John") + .lastName("Doe") + .addressSameAsProperty(VerticalYesNo.NO) + .address(AddressUK.builder() + .addressLine1("1 Party Street") + .postCode("PA1 2RT") + .build()) + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .propertyAddress(AddressUK.builder() + .addressLine1("2 Second Avenue") + .postCode("W3 7RX") + .build()) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - the party keeps its own address, not the property address + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .anySatisfy(searchParty -> { + assertThat(searchParty.getName()).isEqualTo("John Doe"); + assertThat(searchParty.getAddressLine1()).isEqualTo("1 Party Street"); + assertThat(searchParty.getPostcode()).isEqualTo("PA1 2RT"); + }); + } + @Test void shouldIndexPropertyAddressAsExtraSearchParty() { // Given - no parties, just a property to be repossessed From 0077f6e47b10febe0a20c1d85f2c17cbb2d0023e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CKunchhal?= <“ankita.kunchhal@hmcts.net”> Date: Thu, 11 Jun 2026 10:30:30 +0100 Subject: [PATCH 100/108] Refactor global search tests to use submitGlobalSearch action for form submission --- .../tests/CommonComponent/globalSearch.spec.ts | 16 ++++++++-------- .../commonComponent/globalSearch.action.ts | 5 +++++ src/e2eTest/utils/registry/action.registry.ts | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts index ffa0dcb5ab..f451aa288c 100644 --- a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts +++ b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts @@ -62,37 +62,37 @@ const runGlobalSearchScenarios = () => { await performAction('validateResults'); }); - test('Search by postcode', async ({ page }) => { + test('Search by postcode', async () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.postCodeLabel, globalSearch.postcodeInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); await performAction('clickButton', globalSearch.searchButton); - await page.locator('button[type="submit"]').click(); + await performAction('submitGlobalSearch'); await performAction('validateResultsWithRetry'); }); - test('Search by email address', async ({ page }) => { + test('Search by email address', async () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.emailAddressLabel, globalSearch.emailAddressInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); await performAction('clickButton', globalSearch.searchButton); - await page.locator('button[type="submit"]').click(); + await performAction('submitGlobalSearch'); }); - test('first line of address', async ({ page }) => { + test('first line of address', async () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.firstLineOfAddressLabel, globalSearch.firstLineOfAddressInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); await performAction('clickButton', globalSearch.searchButton); - await page.locator('button[type="submit"]').click(); + await performAction('submitGlobalSearch'); }); - test('Search by party name', async ({ page }) => { + test('Search by party name', async () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.nameLabel, globalSearch.nameInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); await performAction('clickButton', globalSearch.searchButton); - await page.locator('button[type="submit"]').click(); + await performAction('submitGlobalSearch'); }); test('Invalid case reference', async () => { diff --git a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts index 1d83b3258b..34a77f04b5 100644 --- a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts +++ b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts @@ -12,6 +12,7 @@ export class GlobalSearchCaseAction implements IAction { ['invalidCaseReferenceSearch', () => this.invalidCaseReferenceSearch(page)], ['changeSearchLink', () => this.changeSearchLink(page)], ['handleJudgeBookingPage', () => this.handleJudgeBookingPage(page)], + ['submitGlobalSearch', () => this.submitGlobalSearch(page)], ['validateResults', () => this.validateResults(page)], ['validateResultsWithRetry', () => this.validateResultsWithRetry(page)] ]); @@ -54,6 +55,10 @@ export class GlobalSearchCaseAction implements IAction { await performValidation('mainHeader', caseList.mainHeader); } + private async submitGlobalSearch(page: Page): Promise { + await page.locator('button[type="submit"]').click(); + } + private async validateResults(page: Page): Promise { const caseReference = String(process.env.CASE_NUMBER ?? ''); const normalizedCaseReference = caseReference.replace(/\D/g, ''); diff --git a/src/e2eTest/utils/registry/action.registry.ts b/src/e2eTest/utils/registry/action.registry.ts index 17863acef7..f24ff42ba1 100644 --- a/src/e2eTest/utils/registry/action.registry.ts +++ b/src/e2eTest/utils/registry/action.registry.ts @@ -98,6 +98,7 @@ export class ActionRegistry { ['invalidCaseReferenceSearch', new GlobalSearchCaseAction()], ['changeSearchLink', new GlobalSearchCaseAction()], ['handleJudgeBookingPage', new GlobalSearchCaseAction()], + ['submitGlobalSearch', new GlobalSearchCaseAction()], ['validateResults', new GlobalSearchCaseAction()], ['validateResultsWithRetry', new GlobalSearchCaseAction()], ['selectClaimingCosts', new CreateCaseAction()], From d55e8bbd292171add9fbd2d16599dc02cd8a1a0e Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 11 Jun 2026 10:45:52 +0100 Subject: [PATCH 101/108] HDPI-5335 allow searching of unknown names --- .../globalsearch/SearchCriteriaIndexer.java | 16 +++++++++-- .../SearchCriteriaIndexerTest.java | 28 +++++++++++++++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java index 549f1033bb..f4841d702e 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java @@ -9,6 +9,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; +import uk.gov.hmcts.reform.pcs.ccd.view.CaseTabView; import java.util.ArrayList; import java.util.Arrays; @@ -77,9 +78,7 @@ private SearchParty toSearchParty(Party party, AddressUK propertyAddress) { ? propertyAddress : party.getAddress(); return SearchParty.builder() - .name(isNotBlank(party.getOrgName()) - ? party.getOrgName() - : joinNonBlank(party.getFirstName(), party.getLastName())) + .name(resolveSearchPartyName(party)) .emailAddress(party.getEmailAddress()) .addressLine1(address == null ? null : address.getAddressLine1()) .postcode(address == null ? null : address.getPostCode()) @@ -87,6 +86,17 @@ private SearchParty toSearchParty(Party party, AddressUK propertyAddress) { .build(); } + /** + * Resolves the name to index for a SearchParty. When the party has no known name, the + * placeholder {@link CaseTabView#NAME_UNKNOWN} is indexed + */ + private static String resolveSearchPartyName(Party party) { + String name = isNotBlank(party.getOrgName()) + ? party.getOrgName() + : joinNonBlank(party.getFirstName(), party.getLastName()); + return name != null ? name : CaseTabView.NAME_UNKNOWN; + } + private static String joinNonBlank(String... parts) { String joined = Arrays.stream(parts) .filter(p -> p != null && !p.isBlank()) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java index a04389d2e6..bc0f5fe699 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java @@ -9,6 +9,7 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; +import uk.gov.hmcts.reform.pcs.ccd.view.CaseTabView; import java.time.LocalDate; import java.util.List; @@ -76,7 +77,7 @@ void shouldOmitBlankNamePartsWhenBuildingPartyName() { } @Test - void shouldSetNullNameWhenNoNamePartsKnown() { + void shouldIndexUnknownNameWhenNoNamePartsKnown() { // Given - neither first nor last name known Party party = Party.builder().build(); PCSCase pcsCase = PCSCase.builder() @@ -86,12 +87,33 @@ void shouldSetNullNameWhenNoNamePartsKnown() { // When SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); - // Then + // Then - a placeholder name is indexed so the party remains searchable + assertThat(searchCriteria.getParties()) + .extracting(ListValue::getValue) + .singleElement() + .extracting(SearchParty::getName) + .isEqualTo(CaseTabView.NAME_UNKNOWN); + } + + @Test + void shouldIndexUnknownNameWhenNameIsNotKnown() { + // Given - a party explicitly flagged as having no known name + Party party = Party.builder() + .nameKnown(VerticalYesNo.NO) + .build(); + PCSCase pcsCase = PCSCase.builder() + .parties(ListValueUtils.wrapListItems(List.of(party))) + .build(); + + // When + SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); + + // Then - the placeholder name is indexed so the unnamed party is searchable assertThat(searchCriteria.getParties()) .extracting(ListValue::getValue) .singleElement() .extracting(SearchParty::getName) - .isNull(); + .isEqualTo(CaseTabView.NAME_UNKNOWN); } @Test From f83f3a92e270e9974f7aa4be4f8f8e8d01d3130a Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Thu, 11 Jun 2026 11:35:25 +0100 Subject: [PATCH 102/108] Revert "HDPI-5335 allow searching of unknown names" This reverts commit d55e8bbd292171add9fbd2d16599dc02cd8a1a0e. --- .../globalsearch/SearchCriteriaIndexer.java | 16 ++--------- .../SearchCriteriaIndexerTest.java | 28 ++----------------- 2 files changed, 6 insertions(+), 38 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java index f4841d702e..549f1033bb 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexer.java @@ -9,7 +9,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; -import uk.gov.hmcts.reform.pcs.ccd.view.CaseTabView; import java.util.ArrayList; import java.util.Arrays; @@ -78,7 +77,9 @@ private SearchParty toSearchParty(Party party, AddressUK propertyAddress) { ? propertyAddress : party.getAddress(); return SearchParty.builder() - .name(resolveSearchPartyName(party)) + .name(isNotBlank(party.getOrgName()) + ? party.getOrgName() + : joinNonBlank(party.getFirstName(), party.getLastName())) .emailAddress(party.getEmailAddress()) .addressLine1(address == null ? null : address.getAddressLine1()) .postcode(address == null ? null : address.getPostCode()) @@ -86,17 +87,6 @@ private SearchParty toSearchParty(Party party, AddressUK propertyAddress) { .build(); } - /** - * Resolves the name to index for a SearchParty. When the party has no known name, the - * placeholder {@link CaseTabView#NAME_UNKNOWN} is indexed - */ - private static String resolveSearchPartyName(Party party) { - String name = isNotBlank(party.getOrgName()) - ? party.getOrgName() - : joinNonBlank(party.getFirstName(), party.getLastName()); - return name != null ? name : CaseTabView.NAME_UNKNOWN; - } - private static String joinNonBlank(String... parts) { String joined = Arrays.stream(parts) .filter(p -> p != null && !p.isBlank()) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java index bc0f5fe699..a04389d2e6 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/globalsearch/SearchCriteriaIndexerTest.java @@ -9,7 +9,6 @@ import uk.gov.hmcts.reform.pcs.ccd.domain.Party; import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo; import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils; -import uk.gov.hmcts.reform.pcs.ccd.view.CaseTabView; import java.time.LocalDate; import java.util.List; @@ -77,7 +76,7 @@ void shouldOmitBlankNamePartsWhenBuildingPartyName() { } @Test - void shouldIndexUnknownNameWhenNoNamePartsKnown() { + void shouldSetNullNameWhenNoNamePartsKnown() { // Given - neither first nor last name known Party party = Party.builder().build(); PCSCase pcsCase = PCSCase.builder() @@ -87,33 +86,12 @@ void shouldIndexUnknownNameWhenNoNamePartsKnown() { // When SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); - // Then - a placeholder name is indexed so the party remains searchable - assertThat(searchCriteria.getParties()) - .extracting(ListValue::getValue) - .singleElement() - .extracting(SearchParty::getName) - .isEqualTo(CaseTabView.NAME_UNKNOWN); - } - - @Test - void shouldIndexUnknownNameWhenNameIsNotKnown() { - // Given - a party explicitly flagged as having no known name - Party party = Party.builder() - .nameKnown(VerticalYesNo.NO) - .build(); - PCSCase pcsCase = PCSCase.builder() - .parties(ListValueUtils.wrapListItems(List.of(party))) - .build(); - - // When - SearchCriteria searchCriteria = underTest.buildSearchCriteria(pcsCase); - - // Then - the placeholder name is indexed so the unnamed party is searchable + // Then assertThat(searchCriteria.getParties()) .extracting(ListValue::getValue) .singleElement() .extracting(SearchParty::getName) - .isEqualTo(CaseTabView.NAME_UNKNOWN); + .isNull(); } @Test From 0d1de293c7bca515c7ff5a2f973926f723a726e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CKunchhal?= <“ankita.kunchhal@hmcts.net”> Date: Thu, 11 Jun 2026 12:23:32 +0100 Subject: [PATCH 103/108] Enhance global search functionality by updating input values, refactoring action methods, and introducing executeSearch action for improved search execution. --- .../globalSearch.page.data.ts | 4 +- .../CommonComponent/globalSearch.spec.ts | 25 +++++---- .../commonComponent/globalSearch.action.ts | 53 +++++++++++-------- src/e2eTest/utils/registry/action.registry.ts | 2 +- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts b/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts index 826ad0a551..8af9e13556 100644 --- a/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts +++ b/src/e2eTest/data/page-data-figma/page-data-common-component/globalSearch.page.data.ts @@ -18,14 +18,14 @@ export const globalSearch = otherReferenceInputText: 'Test reference', otherReferenceParagraph:'Any other reference to identify a case, for example National Insurance number, or system reference', nameLabel:'Name', - nameInputText: 'Smith', + nameInputText: 'Possession Claims Solicitor Org', nameParagraph: 'For example, name of a party or solicitor', firstLineOfAddressLabel: 'First line of address', firstLineOfAddressInputText: '2 Second Avenue', postCodeLabel: 'Postcode', postcodeInputText: 'W3 7RX', emailAddressLabel: 'Email address', - emailAddressInputText: 'test@test.com', + emailAddressInputText: 'pcs-solicitor1@test.com', dateOfBirthLabel: 'Date of birth', dateOfBirthDayLabel: 'Day', dateOfBirthMonthLabel: 'Month', diff --git a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts index f451aa288c..4e12bb9b39 100644 --- a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts +++ b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts @@ -1,5 +1,5 @@ import { test } from '@utils/test-fixtures'; -import { expect } from '@playwright/test'; +import { expect, Page, BrowserContext } from '@playwright/test'; import { initializeExecutor, performAction, performValidation } from '@utils/controller'; import { globalSearch} from '@data/page-data-figma'; import { dismissCookieBanner } from '@config/cookie-banner'; @@ -10,8 +10,8 @@ import { user} from '@data/page-data'; test.use({ storageState: undefined }); const setupGlobalSearchUser = async ( - page: any, - context: any, + page: Page, + context: BrowserContext, loggedInUser: typeof user.ctscAdministrator ) => { await context.clearCookies(); @@ -52,13 +52,13 @@ const runGlobalSearchScenarios = () => { test('Valid case reference using Mortgage and Landlord Possession Claim Service', async () => { await performAction('accessingTheSearch'); - await performAction('searchByCaseReference', process.env.CASE_NUMBER); + await performAction('searchByCaseReference', process.env.CASE_NUMBER, globalSearch.servicesDropdownOption2); await performAction('validateResults'); }); test('Valid case reference using All Services', async () => { await performAction('accessingTheSearch'); - await performAction('searchByCaseReference', process.env.CASE_NUMBER); + await performAction('searchByCaseReference', process.env.CASE_NUMBER, globalSearch.servicesDropdownOption1); await performAction('validateResults'); }); @@ -66,8 +66,7 @@ const runGlobalSearchScenarios = () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.postCodeLabel, globalSearch.postcodeInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('clickButton', globalSearch.searchButton); - await performAction('submitGlobalSearch'); + await performAction('executeSearch'); await performAction('validateResultsWithRetry'); }); @@ -75,24 +74,24 @@ const runGlobalSearchScenarios = () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.emailAddressLabel, globalSearch.emailAddressInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('clickButton', globalSearch.searchButton); - await performAction('submitGlobalSearch'); + await performAction('executeSearch'); + await performAction('validateResultsWithRetry'); }); test('first line of address', async () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.firstLineOfAddressLabel, globalSearch.firstLineOfAddressInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('clickButton', globalSearch.searchButton); - await performAction('submitGlobalSearch'); + await performAction('executeSearch'); + await performAction('validateResultsWithRetry'); }); test('Search by party name', async () => { await performAction('accessingTheSearch'); await performAction('inputText', globalSearch.nameLabel, globalSearch.nameInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('clickButton', globalSearch.searchButton); - await performAction('submitGlobalSearch'); + await performAction('executeSearch'); + await performAction('validateResultsWithRetry'); }); test('Invalid case reference', async () => { diff --git a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts index 34a77f04b5..526ad25b55 100644 --- a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts +++ b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts @@ -5,14 +5,15 @@ import { globalSearch, noResultFound, searchResults, workAccess } from '@data/pa import { caseList, home } from '@data/page-data'; export class GlobalSearchCaseAction implements IAction { - async execute(page: Page, action: string, fieldName: string | actionRecord): Promise { + async execute(page: Page, action: string, fieldName: string | actionRecord, value?: string | actionRecord): Promise { const actionsMap = new Map Promise>([ ['accessingTheSearch', () => this.accessingTheSearch(page)], - ['searchByCaseReference', () => this.searchByCaseReference(fieldName as string, page)], + ['searchByCaseReference', () => this.searchByCaseReference(fieldName as string, page, value as string | undefined)], ['invalidCaseReferenceSearch', () => this.invalidCaseReferenceSearch(page)], ['changeSearchLink', () => this.changeSearchLink(page)], ['handleJudgeBookingPage', () => this.handleJudgeBookingPage(page)], ['submitGlobalSearch', () => this.submitGlobalSearch(page)], + ['executeSearch', () => this.executeSearch(page)], ['validateResults', () => this.validateResults(page)], ['validateResultsWithRetry', () => this.validateResultsWithRetry(page)] ]); @@ -26,11 +27,11 @@ export class GlobalSearchCaseAction implements IAction { await performAction('clickButton', home.globalSearchTab); } - private async searchByCaseReference(caseReference: string, page: Page): Promise { + private async searchByCaseReference(caseReference: string, page: Page, serviceOption?: string): Promise { await performAction('inputText', globalSearch.DigitCaseReferenceLabel, caseReference); - await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); + await performAction('select', globalSearch.servicesLabel, serviceOption ?? globalSearch.servicesDropdownOption2); await performAction('clickButton', globalSearch.searchButton); - await page.locator('button[type="submit"]').click(); + await this.submitGlobalSearch(page); await performValidation('mainHeader', searchResults.mainHeader); } @@ -38,7 +39,7 @@ export class GlobalSearchCaseAction implements IAction { await performAction('inputText', globalSearch.DigitCaseReferenceLabel, globalSearch.invalidCaseReferenceInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption1); await performAction('clickButton', globalSearch.searchButton); - await page.locator('button[type="submit"]').click(); + await this.submitGlobalSearch(page); await performValidation('mainHeader', noResultFound.mainHeader); } @@ -59,6 +60,11 @@ export class GlobalSearchCaseAction implements IAction { await page.locator('button[type="submit"]').click(); } + private async executeSearch(page: Page): Promise { + await performAction('clickButton', globalSearch.searchButton); + await this.submitGlobalSearch(page); + } + private async validateResults(page: Page): Promise { const caseReference = String(process.env.CASE_NUMBER ?? ''); const normalizedCaseReference = caseReference.replace(/\D/g, ''); @@ -82,25 +88,28 @@ export class GlobalSearchCaseAction implements IAction { } private async validateResultsWithRetry(page: Page): Promise { - const attempts = 6; - const waitMs = 5000; - - for (let attempt = 1; attempt <= attempts; attempt++) { - try { - await this.validateResults(page); - return; - } catch (error: any) { - const shouldRetry = String(error?.message ?? '').includes('was not found on any paginated search result page'); - if (!shouldRetry || attempt === attempts) { - throw error; - } - - await page.waitForTimeout(waitMs); - await page.reload({ waitUntil: 'domcontentloaded' }); - await expect(page.getByRole('heading', { name: searchResults.mainHeader })).toBeVisible(); + const maxRetries = 6; + + for (let retryCount = 0; retryCount < maxRetries; retryCount++) { + try { + await this.validateResults(page); + return; + } catch (error: any) { + const shouldRetry = String(error?.message ?? '').includes( + 'was not found on any paginated search result page' + ); + + if (!shouldRetry || retryCount === maxRetries - 1) { + throw error; } + + await page.reload({ waitUntil: 'domcontentloaded' }); + await expect( + page.getByRole('heading', { name: searchResults.mainHeader }) + ).toBeVisible(); } } +} private async findCaseReferenceRowAcrossPages(page: Page, normalizedCaseReference: string): Promise { const maxPagesToScan = 50; diff --git a/src/e2eTest/utils/registry/action.registry.ts b/src/e2eTest/utils/registry/action.registry.ts index f24ff42ba1..e3fedee805 100644 --- a/src/e2eTest/utils/registry/action.registry.ts +++ b/src/e2eTest/utils/registry/action.registry.ts @@ -97,8 +97,8 @@ export class ActionRegistry { ['searchByCaseReference', new GlobalSearchCaseAction()], ['invalidCaseReferenceSearch', new GlobalSearchCaseAction()], ['changeSearchLink', new GlobalSearchCaseAction()], - ['handleJudgeBookingPage', new GlobalSearchCaseAction()], ['submitGlobalSearch', new GlobalSearchCaseAction()], + ['executeSearch', new GlobalSearchCaseAction()], ['validateResults', new GlobalSearchCaseAction()], ['validateResultsWithRetry', new GlobalSearchCaseAction()], ['selectClaimingCosts', new CreateCaseAction()], From 572dd270d91aa3343d6907cb0f64c405ce298a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CKunchhal?= <“ankita.kunchhal@hmcts.net”> Date: Thu, 11 Jun 2026 12:37:53 +0100 Subject: [PATCH 104/108] Refactor global search actions to streamline search execution and enhance code reusability --- .../CommonComponent/globalSearch.spec.ts | 34 ++++++-------- .../commonComponent/globalSearch.action.ts | 44 +++++++++---------- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts index 4e12bb9b39..124167e01b 100644 --- a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts +++ b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts @@ -44,6 +44,14 @@ test.afterEach(async () => { } }); +const runFieldSearch = async (label: string, value: string) => { + await performAction('accessingTheSearch'); + await performAction('inputText', label, value); + await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); + await performAction('executeSearch'); + await performAction('validateResultsWithRetry'); +}; + const runGlobalSearchScenarios = () => { test('Global search menu @smoke', async () => { await performAction('accessingTheSearch'); @@ -63,35 +71,19 @@ const runGlobalSearchScenarios = () => { }); test('Search by postcode', async () => { - await performAction('accessingTheSearch'); - await performAction('inputText', globalSearch.postCodeLabel, globalSearch.postcodeInputText); - await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('executeSearch'); - await performAction('validateResultsWithRetry'); + await runFieldSearch(globalSearch.postCodeLabel, globalSearch.postcodeInputText); }); test('Search by email address', async () => { - await performAction('accessingTheSearch'); - await performAction('inputText', globalSearch.emailAddressLabel, globalSearch.emailAddressInputText); - await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('executeSearch'); - await performAction('validateResultsWithRetry'); + await runFieldSearch(globalSearch.emailAddressLabel, globalSearch.emailAddressInputText); }); test('first line of address', async () => { - await performAction('accessingTheSearch'); - await performAction('inputText', globalSearch.firstLineOfAddressLabel, globalSearch.firstLineOfAddressInputText); - await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('executeSearch'); - await performAction('validateResultsWithRetry'); + await runFieldSearch(globalSearch.firstLineOfAddressLabel, globalSearch.firstLineOfAddressInputText); }); - + test('Search by party name', async () => { - await performAction('accessingTheSearch'); - await performAction('inputText', globalSearch.nameLabel, globalSearch.nameInputText); - await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption2); - await performAction('executeSearch'); - await performAction('validateResultsWithRetry'); + await runFieldSearch(globalSearch.nameLabel, globalSearch.nameInputText); }); test('Invalid case reference', async () => { diff --git a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts index 526ad25b55..bfe2270d32 100644 --- a/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts +++ b/src/e2eTest/utils/actions/custom-actions/commonComponent/globalSearch.action.ts @@ -30,16 +30,14 @@ export class GlobalSearchCaseAction implements IAction { private async searchByCaseReference(caseReference: string, page: Page, serviceOption?: string): Promise { await performAction('inputText', globalSearch.DigitCaseReferenceLabel, caseReference); await performAction('select', globalSearch.servicesLabel, serviceOption ?? globalSearch.servicesDropdownOption2); - await performAction('clickButton', globalSearch.searchButton); - await this.submitGlobalSearch(page); + await this.executeSearch(page); await performValidation('mainHeader', searchResults.mainHeader); } private async invalidCaseReferenceSearch(page: Page): Promise { await performAction('inputText', globalSearch.DigitCaseReferenceLabel, globalSearch.invalidCaseReferenceInputText); await performAction('select', globalSearch.servicesLabel, globalSearch.servicesDropdownOption1); - await performAction('clickButton', globalSearch.searchButton); - await this.submitGlobalSearch(page); + await this.executeSearch(page); await performValidation('mainHeader', noResultFound.mainHeader); } @@ -88,28 +86,28 @@ export class GlobalSearchCaseAction implements IAction { } private async validateResultsWithRetry(page: Page): Promise { - const maxRetries = 6; - - for (let retryCount = 0; retryCount < maxRetries; retryCount++) { - try { - await this.validateResults(page); - return; - } catch (error: any) { - const shouldRetry = String(error?.message ?? '').includes( - 'was not found on any paginated search result page' - ); - - if (!shouldRetry || retryCount === maxRetries - 1) { - throw error; - } + const maxRetries = 6; + + for (let retryCount = 0; retryCount < maxRetries; retryCount++) { + try { + await this.validateResults(page); + return; + } catch (error: any) { + const shouldRetry = String(error?.message ?? '').includes( + 'was not found on any paginated search result page' + ); + + if (!shouldRetry || retryCount === maxRetries - 1) { + throw error; + } - await page.reload({ waitUntil: 'domcontentloaded' }); - await expect( - page.getByRole('heading', { name: searchResults.mainHeader }) - ).toBeVisible(); + await page.reload({ waitUntil: 'domcontentloaded' }); + await expect( + page.getByRole('heading', { name: searchResults.mainHeader }) + ).toBeVisible(); + } } } -} private async findCaseReferenceRowAcrossPages(page: Page, normalizedCaseReference: string): Promise { const maxPagesToScan = 50; From cdc3f7c400b2851ae406bf9dcebfbc39f577c712 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Fri, 12 Jun 2026 16:03:29 +0100 Subject: [PATCH 105/108] Give access to allDeendants for internalCAseFlags --- src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java index 42d851b94b..f233f89ab0 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java @@ -344,7 +344,7 @@ public class PCSCase { /** * Combined list of all defendants in the case (i.e. primary defendant + additional defendants). */ - @CCD(access = {ClaimantAccess.class, CitizenAccess.class}) + @CCD(access = {ClaimantAccess.class, CitizenAccess.class, InternalCaseFlagAccess.class}) private List> allDefendants; @JsonUnwrapped(prefix = "tenancy_") From 513035e98ba30872f5be183d5fc757294550eadf Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 15 Jun 2026 12:56:32 +0100 Subject: [PATCH 106/108] fix case flags not applying --- .../reform/pcs/ccd/view/CaseFlagsView.java | 28 +++++++++---------- .../InternalCaseFlagAccessTest.java | 2 +- .../pcs/ccd/view/CaseFlagsViewTest.java | 19 ++++++++----- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java index b8376b6ab5..a34489c5ac 100644 --- a/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java +++ b/src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java @@ -18,9 +18,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; import static java.util.Objects.requireNonNullElse; @@ -93,21 +90,24 @@ private List> getPaths(String entityPaths) { } private void mapComplexPartyFlagFields(PCSCase pcsCase, PcsCaseEntity pcsCaseEntity) { - if (CollectionUtils.isEmpty(pcsCase.getParties())) { + List> partyListValues = pcsCase.getParties(); + if (CollectionUtils.isEmpty(partyListValues)) { return; } - Map defendantEntitiesById = pcsCaseEntity.getParties().stream() - .filter(this::isDefendant) - .collect(Collectors.toMap(partyEntity -> partyEntity.getId().toString(), Function.identity())); - - pcsCase.getParties().forEach(partyListValue -> { - Party party = partyListValue.getValue(); - PartyEntity defendantEntity = defendantEntitiesById.get(party.getId()); - if (defendantEntity != null) { - party.setDefendantFlags(mapDefendantFlags(defendantEntity)); + // pcsCase.parties is wrapped from pcsCaseEntity.getParties() in iteration order, but the + // entity id is dropped during the entity->domain mapping. Re-attach it onto each ListValue + // so the entity can be matched back, then apply the defendant flags. + // same party set. + List partyEntities = new ArrayList<>(pcsCaseEntity.getParties()); + for (int i = 0; i < partyListValues.size() && i < partyEntities.size(); i++) { + PartyEntity partyEntity = partyEntities.get(i); + ListValue partyListValue = partyListValues.get(i); + partyListValue.setId(partyEntity.getId().toString()); + if (isDefendant(partyEntity)) { + partyListValue.getValue().setDefendantFlags(mapDefendantFlags(partyEntity)); } - }); + } } private boolean isDefendant(PartyEntity partyEntity) { diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java index cd376e864c..819ff9b8c9 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java @@ -39,6 +39,6 @@ void shouldGrantInternalCaseFlagAccess() { assertThat(grants.get(CIRCUIT_JUDGE)).contains(Permission.R); assertThat(grants.get(LEADERSHIP_JUDGE)).contains(Permission.R); assertThat(grants.get(JUDGE)).contains(Permission.R); - assertThat(grants.asMap().size()).isEqualTo(7); + assertThat(grants.asMap().size()).isEqualTo(8); } } diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java index 2e3f7a99e5..14096240af 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsViewTest.java @@ -69,24 +69,28 @@ void shouldMapBasicCaseFlagFieldsWhenCaseFlagsExist() { @Test void shouldMapComplexPartyFlagFieldsWhenPartiesExist() { - // Given - a defendant (with flags) and a non-defendant organisation party, - // both already mapped onto the case earlier (as PCSCaseView does) + // Given - a defendant (with flags) and a non-defendant organisation party. + // The case parties are wrapped from the same entity set (as PCSCaseView does), + // with the entity id dropped during mapping, so the two collections share order. PartyEntity defendantEntity = createPartyEntity(null); markAsDefendant(defendantEntity); defendantEntity.setDefendantFlags(List.of(createMockCasePartyFlagsEntity())); PartyEntity orgEntity = createPartyEntity("King Smith"); + Set partyEntities = Set.of(defendantEntity, orgEntity); + PCSCase pcsCase = PCSCase.builder() - .parties(List.of(mappedParty(defendantEntity), mappedParty(orgEntity))) + .parties(partyEntities.stream().map(this::mappedParty).toList()) .build(); PcsCaseEntity pcsCaseEntity = new PcsCaseEntity(); - pcsCaseEntity.setParties(Set.of(defendantEntity, orgEntity)); + pcsCaseEntity.setParties(partyEntities); // When underTest.setCaseFields(pcsCase, pcsCaseEntity); - // Then - both parties remain, but only the defendant is given flags + // Then - both parties remain, each ListValue now carries its entity id, + // but only the defendant is given flags assertNotNull(pcsCase.getParties()); assertEquals(2, pcsCase.getParties().size()); @@ -130,8 +134,8 @@ void shouldNotMapDefendantFlagsForNonDefendantIndividual() { private Party findPartyById(PCSCase pcsCase, String id) { return pcsCase.getParties().stream() + .filter(partyListValue -> id.equals(partyListValue.getId())) .map(ListValue::getValue) - .filter(party -> id.equals(party.getId())) .findFirst() .orElseThrow(); } @@ -150,9 +154,10 @@ private PartyEntity createPartyEntity(String orgName) { } private ListValue mappedParty(PartyEntity entity) { + // Mirrors PCSCaseView.mapAndWrapParties: the entity id is NOT carried onto the + // domain Party or the ListValue - CaseFlagsView is responsible for attaching it. return ListValue.builder() .value(Party.builder() - .id(entity.getId().toString()) .orgName(entity.getOrgName()) .firstName(entity.getFirstName()) .lastName(entity.getLastName()) From c9d9526f9b3f2a323de5541e48992d86ac2a41f1 Mon Sep 17 00:00:00 2001 From: Toby Plunkett Date: Mon, 15 Jun 2026 13:36:44 +0100 Subject: [PATCH 107/108] revert test change --- .../pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java index 819ff9b8c9..cd376e864c 100644 --- a/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pcs/ccd/accesscontrol/InternalCaseFlagAccessTest.java @@ -39,6 +39,6 @@ void shouldGrantInternalCaseFlagAccess() { assertThat(grants.get(CIRCUIT_JUDGE)).contains(Permission.R); assertThat(grants.get(LEADERSHIP_JUDGE)).contains(Permission.R); assertThat(grants.get(JUDGE)).contains(Permission.R); - assertThat(grants.asMap().size()).isEqualTo(8); + assertThat(grants.asMap().size()).isEqualTo(7); } } From dd1e314e7d210c85ab8f78eab0e65bc2c97178a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CKunchhal?= <“ankita.kunchhal@hmcts.net”> Date: Mon, 15 Jun 2026 16:32:28 +0100 Subject: [PATCH 108/108] Refactor global search test description for clarity --- src/e2eTest/tests/CommonComponent/globalSearch.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts index 124167e01b..eefd83f10f 100644 --- a/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts +++ b/src/e2eTest/tests/CommonComponent/globalSearch.spec.ts @@ -102,7 +102,7 @@ const runGlobalSearchScenarios = () => { { roleName: 'CTSC User', account: user.ctscAdministrator }, { roleName: 'Judge User', account: user.judge } ].forEach(({ roleName, account }) => { - test.describe(`[Global Search - ${roleName} - @nightly @CC @caseFlags]`, () => { + test.describe(`[Common Component Global Search] - ${roleName} - @nightly @CC @caseFlags`, () => { test.beforeEach(async ({ page, context }) => { await setupGlobalSearchUser(page, context, account); });