Skip to content

Commit 1993f73

Browse files
toby-plunkettspnaik77adusumillipraveenAnkita-Kumbharebenouaer
authored
Hdpi 4009 enable search parties global search [V2] (#1876)
Co-authored-by: SachinNaik <sp_naik@hotmail.com> Co-authored-by: Praveen Adusumilli <47391951+adusumillipraveen@users.noreply.github.com> Co-authored-by: adusumillipraveen <praveen.adusumilli@hmcts.net> Co-authored-by: Ankita-Kumbhare <kumbhare.ankita33@gmail.com> Co-authored-by: taleb <tech@benouaer.com> Co-authored-by: ankitakunchhal <ankita.kunchhal@hmcts.net>
1 parent 49e755e commit 1993f73

8 files changed

Lines changed: 615 additions & 47 deletions

File tree

src/main/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseView.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import uk.gov.hmcts.ccd.sdk.CaseViewRequest;
88
import uk.gov.hmcts.ccd.sdk.type.AddressUK;
99
import uk.gov.hmcts.ccd.sdk.type.ListValue;
10-
import uk.gov.hmcts.ccd.sdk.type.SearchCriteria;
1110
import uk.gov.hmcts.ccd.sdk.type.YesOrNo;
1211
import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase;
1312
import uk.gov.hmcts.reform.pcs.ccd.domain.Party;
@@ -38,6 +37,7 @@
3837
import uk.gov.hmcts.reform.pcs.ccd.view.StatementOfTruthView;
3938
import uk.gov.hmcts.reform.pcs.ccd.view.TenancyLicenceView;
4039
import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.CaseFieldsView;
40+
import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.SearchCriteriaIndexer;
4141
import uk.gov.hmcts.reform.pcs.exception.CaseNotFoundException;
4242
import uk.gov.hmcts.reform.pcs.security.SecurityContextService;
4343

@@ -80,6 +80,7 @@ public class PCSCaseView implements CaseView<PCSCase, State> {
8080
private final PartiesView partiesView;
8181
private final GenAppsView genAppsView;
8282
private final CaseFlagsView flagsView;
83+
private final SearchCriteriaIndexer searchCriteriaIndexer;
8384

8485

8586
/**
@@ -109,8 +110,7 @@ public PCSCase getCase(CaseViewRequest<State> request) {
109110

110111
caseFieldsView.setCaseFields(pcsCase);
111112

112-
//allows indexing for Global Search
113-
pcsCase.setSearchCriteria(new SearchCriteria());
113+
pcsCase.setSearchCriteria(searchCriteriaIndexer.buildSearchCriteria(pcsCase));
114114

115115
return pcsCase;
116116
}

src/main/java/uk/gov/hmcts/reform/pcs/ccd/domain/PCSCase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ public class PCSCase {
345345
/**
346346
* Combined list of all defendants in the case (i.e. primary defendant + additional defendants).
347347
*/
348-
@CCD(access = {ClaimantAccess.class, CitizenAccess.class})
348+
@CCD(access = {ClaimantAccess.class, CitizenAccess.class, InternalCaseFlagAccess.class})
349349
private List<ListValue<Party>> allDefendants;
350350

351351
@JsonUnwrapped(prefix = "tenancy_")

src/main/java/uk/gov/hmcts/reform/pcs/ccd/view/CaseFlagsView.java

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import uk.gov.hmcts.reform.pcs.ccd.entity.BaseCaseFlag;
1414
import uk.gov.hmcts.reform.pcs.ccd.util.YesOrNoConverter;
1515
import uk.gov.hmcts.reform.pcs.ccd.entity.party.PartyEntity;
16+
import uk.gov.hmcts.reform.pcs.ccd.entity.party.PartyRole;
1617

1718
import java.util.ArrayList;
1819
import java.util.Arrays;
@@ -89,29 +90,30 @@ private List<ListValue<String>> getPaths(String entityPaths) {
8990
}
9091

9192
private void mapComplexPartyFlagFields(PCSCase pcsCase, PcsCaseEntity pcsCaseEntity) {
92-
List<ListValue<Party>> mappedParties = pcsCaseEntity.getParties().stream()
93-
.filter(partyEntity -> partyEntity.getOrgName() == null || partyEntity.getOrgName().isEmpty())
94-
.map(this::mapPartyWithDefendantFlags)
95-
.toList();
93+
List<ListValue<Party>> partyListValues = pcsCase.getParties();
94+
if (CollectionUtils.isEmpty(partyListValues)) {
95+
return;
96+
}
9697

97-
pcsCase.setParties(mappedParties);
98+
// pcsCase.parties is wrapped from pcsCaseEntity.getParties() in iteration order, but the
99+
// entity id is dropped during the entity->domain mapping. Re-attach it onto each ListValue
100+
// so the entity can be matched back, then apply the defendant flags.
101+
// same party set.
102+
List<PartyEntity> partyEntities = new ArrayList<>(pcsCaseEntity.getParties());
103+
for (int i = 0; i < partyListValues.size() && i < partyEntities.size(); i++) {
104+
PartyEntity partyEntity = partyEntities.get(i);
105+
ListValue<Party> partyListValue = partyListValues.get(i);
106+
partyListValue.setId(partyEntity.getId().toString());
107+
if (isDefendant(partyEntity)) {
108+
partyListValue.getValue().setDefendantFlags(mapDefendantFlags(partyEntity));
109+
}
110+
}
98111
}
99112

100-
private ListValue<Party> mapPartyWithDefendantFlags(PartyEntity partyEntity) {
101-
return ListValue.<Party>builder()
102-
.id(partyEntity.getId().toString())
103-
.value(
104-
Party.builder()
105-
.nameKnown(partyEntity.getNameKnown())
106-
.addressKnown(partyEntity.getAddressKnown())
107-
.phoneNumberProvided(partyEntity.getPhoneNumberProvided())
108-
.emailAddress(partyEntity.getEmailAddress())
109-
.firstName(partyEntity.getFirstName())
110-
.lastName(partyEntity.getLastName())
111-
.defendantFlags(mapDefendantFlags(partyEntity))
112-
.build()
113-
)
114-
.build();
113+
private boolean isDefendant(PartyEntity partyEntity) {
114+
return !CollectionUtils.isEmpty(partyEntity.getClaimParties())
115+
&& partyEntity.getClaimParties().stream()
116+
.anyMatch(claimParty -> claimParty.getRole() == PartyRole.DEFENDANT);
115117
}
116118

117119
private Flags mapDefendantFlags(PartyEntity partyEntity) {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package uk.gov.hmcts.reform.pcs.ccd.view.globalsearch;
2+
3+
import org.springframework.stereotype.Component;
4+
import uk.gov.hmcts.ccd.sdk.type.AddressUK;
5+
import uk.gov.hmcts.ccd.sdk.type.ListValue;
6+
import uk.gov.hmcts.ccd.sdk.type.SearchCriteria;
7+
import uk.gov.hmcts.ccd.sdk.type.SearchParty;
8+
import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase;
9+
import uk.gov.hmcts.reform.pcs.ccd.domain.Party;
10+
import uk.gov.hmcts.reform.pcs.ccd.domain.VerticalYesNo;
11+
import uk.gov.hmcts.reform.pcs.ccd.util.ListValueUtils;
12+
13+
import java.util.ArrayList;
14+
import java.util.Arrays;
15+
import java.util.List;
16+
import java.util.Optional;
17+
import java.util.stream.Collectors;
18+
19+
import static org.apache.commons.lang3.StringUtils.isNotBlank;
20+
21+
/**
22+
* Builds the {@link SearchCriteria} used to index a case for global search.
23+
*
24+
* <p>Global search only indexes postcodes that appear on a SearchParty, so the property to be
25+
* repossessed is added as an extra SearchParty alongside the real parties to make it searchable.
26+
*/
27+
@Component
28+
public class SearchCriteriaIndexer {
29+
30+
/**
31+
* Builds the {@link SearchCriteria} for indexing the given case in global search.
32+
* @param pcsCase the case to index
33+
* @return search criteria covering the case parties and the property to be repossessed
34+
*/
35+
public SearchCriteria buildSearchCriteria(PCSCase pcsCase) {
36+
AddressUK propertyAddress = pcsCase.getPropertyAddress();
37+
38+
List<SearchParty> searchParties = new ArrayList<>(
39+
Optional.ofNullable(pcsCase.getParties())
40+
.orElse(List.of())
41+
.stream()
42+
.map(ListValue::getValue)
43+
.map(party -> toSearchParty(party, propertyAddress))
44+
.toList());
45+
46+
// Global search only indexes postcodes that appear on a SearchParty.
47+
// We add the property to be repossessed address as an extra SearchParty here to make it searchable.
48+
SearchParty propertySearchParty = toPropertySearchParty(propertyAddress);
49+
if (propertySearchParty != null) {
50+
searchParties.add(propertySearchParty);
51+
}
52+
53+
return SearchCriteria.builder()
54+
.parties(ListValueUtils.wrapListItems(searchParties))
55+
.build();
56+
}
57+
58+
private SearchParty toPropertySearchParty(AddressUK propertyAddress) {
59+
if (propertyAddress == null
60+
|| propertyAddress.getPostCode() == null
61+
|| propertyAddress.getPostCode().isBlank()) {
62+
return null;
63+
}
64+
65+
return SearchParty.builder()
66+
.addressLine1(propertyAddress.getAddressLine1())
67+
.postcode(propertyAddress.getPostCode())
68+
.build();
69+
}
70+
71+
private SearchParty toSearchParty(Party party, AddressUK propertyAddress) {
72+
// When a party's address is the same as the property to be repossessed, the address is not
73+
// duplicated on the party — only the addressSameAsProperty flag is stored. We resolve it back
74+
// to the property address here so the party's SearchParty carries both the name and postcode,
75+
// allowing a combined name + postcode global search to match within a single SearchParty.
76+
AddressUK address = party.getAddressSameAsProperty() == VerticalYesNo.YES
77+
? propertyAddress
78+
: party.getAddress();
79+
return SearchParty.builder()
80+
.name(isNotBlank(party.getOrgName())
81+
? party.getOrgName()
82+
: joinNonBlank(party.getFirstName(), party.getLastName()))
83+
.emailAddress(party.getEmailAddress())
84+
.addressLine1(address == null ? null : address.getAddressLine1())
85+
.postcode(address == null ? null : address.getPostCode())
86+
.dateOfBirth(party.getDateOfBirth())
87+
.build();
88+
}
89+
90+
private static String joinNonBlank(String... parts) {
91+
String joined = Arrays.stream(parts)
92+
.filter(p -> p != null && !p.isBlank())
93+
.collect(Collectors.joining(" "));
94+
return joined.isEmpty() ? null : joined;
95+
}
96+
}

src/test/java/uk/gov/hmcts/reform/pcs/ccd/PCSCaseViewTest.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import uk.gov.hmcts.ccd.sdk.CaseViewRequest;
1111
import uk.gov.hmcts.ccd.sdk.type.AddressUK;
1212
import uk.gov.hmcts.ccd.sdk.type.ListValue;
13+
import uk.gov.hmcts.ccd.sdk.type.SearchCriteria;
1314
import uk.gov.hmcts.reform.pcs.ccd.domain.PCSCase;
1415
import uk.gov.hmcts.reform.pcs.ccd.domain.Party;
1516
import uk.gov.hmcts.reform.pcs.ccd.domain.State;
@@ -38,6 +39,7 @@
3839
import uk.gov.hmcts.reform.pcs.ccd.view.StatementOfTruthView;
3940
import uk.gov.hmcts.reform.pcs.ccd.view.TenancyLicenceView;
4041
import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.CaseFieldsView;
42+
import uk.gov.hmcts.reform.pcs.ccd.view.globalsearch.SearchCriteriaIndexer;
4143
import uk.gov.hmcts.reform.pcs.exception.CaseNotFoundException;
4244
import uk.gov.hmcts.reform.pcs.postcodecourt.model.LegislativeCountry;
4345
import uk.gov.hmcts.reform.pcs.security.SecurityContextService;
@@ -115,6 +117,8 @@ class PCSCaseViewTest {
115117
private PartiesView partiesView;
116118
@Mock
117119
private CaseFlagsView caseFlagsView;
120+
@Mock
121+
private SearchCriteriaIndexer searchCriteriaIndexer;
118122

119123
private PCSCaseView underTest;
120124

@@ -128,7 +132,8 @@ void setUp() {
128132
rentDetailsView, alternativesToPossessionView, asbProhibitedConductView,
129133
rentArrearsView, noticeOfPossessionView,
130134
statementOfTruthView, caseFieldsView, caseLinkView, enforcementOrderMediator,
131-
caseNoteView, caseTabView, partiesView, genAppsView, caseFlagsView
135+
caseNoteView, caseTabView, partiesView, genAppsView, caseFlagsView,
136+
searchCriteriaIndexer
132137
);
133138
}
134139

@@ -190,6 +195,20 @@ void shouldMapPropertyAddress() {
190195
assertThat(pcsCase.getPropertyAddress()).isEqualTo(addressUK);
191196
}
192197

198+
@Test
199+
void shouldSetSearchCriteriaFromIndexer() {
200+
// Given
201+
SearchCriteria searchCriteria = SearchCriteria.builder().build();
202+
when(searchCriteriaIndexer.buildSearchCriteria(any(PCSCase.class))).thenReturn(searchCriteria);
203+
204+
// When
205+
PCSCase pcsCase = underTest.getCase(request(CASE_REFERENCE, DEFAULT_STATE));
206+
207+
// Then - indexing is delegated to the indexer and its result is set on the case
208+
verify(searchCriteriaIndexer).buildSearchCriteria(pcsCase);
209+
assertThat(pcsCase.getSearchCriteria()).isSameAs(searchCriteria);
210+
}
211+
193212
@Test
194213
void shouldMapPartyEntity() {
195214
// Given
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package uk.gov.hmcts.reform.pcs.ccd.accesscontrol;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.assertj.core.api.Assertions.assertThat;
6+
7+
class AccessProfileTest {
8+
9+
@Test
10+
void shouldMapProfilesToTheirRoleStringsInOrder() {
11+
String[] roles = AccessProfile.toRoles(AccessProfile.CREATOR, AccessProfile.CITIZEN);
12+
13+
assertThat(roles).containsExactly("[CREATOR]", "citizen");
14+
}
15+
16+
@Test
17+
void shouldReturnEmptyArrayWhenNoProfilesGiven() {
18+
String[] roles = AccessProfile.toRoles();
19+
20+
assertThat(roles).isEmpty();
21+
}
22+
}

0 commit comments

Comments
 (0)