From e13a9cba018f674786fd3462513d3ec3949ef7f0 Mon Sep 17 00:00:00 2001 From: Jose Alberto Hernandez Date: Tue, 26 Mar 2024 01:06:12 -0600 Subject: [PATCH] FINERACT-2073: Client search v2 using Client Identifiers --- .../main/resources/jpa/branch/persistence.xml | 1 + .../portfolio/client/domain/Client.java | 5 ++++ .../client/domain/ClientIdentifier.java | 0 .../domain/ClientIdentifierRepository.java | 0 .../client/domain/ClientIdentifierStatus.java | 0 .../resources/jpa/document/persistence.xml | 1 + .../resources/jpa/investor/persistence.xml | 1 + .../main/resources/jpa/loan/persistence.xml | 1 + .../ClientIdentifiersApiResourceSwagger.java | 4 +++ .../search/SearchingClientRepositoryImpl.java | 7 ++++- .../src/main/resources/jpa/persistence.xml | 1 + .../main/resources/jpa/rates/persistence.xml | 1 + .../resources/jpa/savings/persistence.xml | 1 + .../client/ClientSearchTest.java | 27 +++++++++++++++++++ .../integrationtests/common/ClientHelper.java | 13 +++++++++ 15 files changed, 62 insertions(+), 1 deletion(-) rename {fineract-provider => fineract-core}/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifier.java (100%) rename {fineract-provider => fineract-core}/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierRepository.java (100%) rename {fineract-provider => fineract-core}/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierStatus.java (100%) diff --git a/fineract-branch/src/main/resources/jpa/branch/persistence.xml b/fineract-branch/src/main/resources/jpa/branch/persistence.xml index 49d7498ea..bf32dc798 100644 --- a/fineract-branch/src/main/resources/jpa/branch/persistence.xml +++ b/fineract-branch/src/main/resources/jpa/branch/persistence.xml @@ -48,6 +48,7 @@ org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.rate.domain.Rate org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java index f1a055199..a65f2d44b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.client.domain; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -25,6 +26,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import jakarta.persistence.Transient; @@ -220,6 +222,9 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { @Column(name = "proposed_transfer_date") private LocalDate proposedTransferDate; + @OneToMany(cascade = CascadeType.ALL, mappedBy = "client", orphanRemoval = true, fetch = FetchType.LAZY) + protected Set identifiers = new HashSet<>(); + public static Client instance(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup, final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname, final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId, final String mobileNo, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifier.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifier.java similarity index 100% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifier.java rename to fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifier.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierRepository.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierRepository.java similarity index 100% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierRepository.java rename to fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierRepository.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierStatus.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierStatus.java similarity index 100% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierStatus.java rename to fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientIdentifierStatus.java diff --git a/fineract-document/src/main/resources/jpa/document/persistence.xml b/fineract-document/src/main/resources/jpa/document/persistence.xml index bf9980fa8..7849844df 100644 --- a/fineract-document/src/main/resources/jpa/document/persistence.xml +++ b/fineract-document/src/main/resources/jpa/document/persistence.xml @@ -48,6 +48,7 @@ org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.charge.domain.Charge org.apache.fineract.portfolio.paymenttype.domain.PaymentType diff --git a/fineract-investor/src/main/resources/jpa/investor/persistence.xml b/fineract-investor/src/main/resources/jpa/investor/persistence.xml index 2b5752f6c..885d58faa 100644 --- a/fineract-investor/src/main/resources/jpa/investor/persistence.xml +++ b/fineract-investor/src/main/resources/jpa/investor/persistence.xml @@ -47,6 +47,7 @@ org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.rate.domain.Rate org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket diff --git a/fineract-loan/src/main/resources/jpa/loan/persistence.xml b/fineract-loan/src/main/resources/jpa/loan/persistence.xml index 49d7498ea..bf32dc798 100644 --- a/fineract-loan/src/main/resources/jpa/loan/persistence.xml +++ b/fineract-loan/src/main/resources/jpa/loan/persistence.xml @@ -48,6 +48,7 @@ org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.rate.domain.Rate org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientIdentifiersApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientIdentifiersApiResourceSwagger.java index fb69d6f2f..0f380a0b4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientIdentifiersApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientIdentifiersApiResourceSwagger.java @@ -85,6 +85,8 @@ final class ClientIdentifiersApiResourceSwagger { public String documentKey; @Schema(example = "Document has been verified") public String description; + @Schema(example = "Active") + public String status; } @Schema(description = "PutClientsClientIdIdentifiersIdentifierIdRequest") @@ -98,6 +100,8 @@ final class ClientIdentifiersApiResourceSwagger { public String documentKey; @Schema(example = "Document has been updated") public String description; + @Schema(example = "Active") + public String status; } @Schema(description = "PutClientsClientIdIdentifiersIdentifierIdResponse") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/search/SearchingClientRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/search/SearchingClientRepositoryImpl.java index 835ded075..f038ce7c5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/search/SearchingClientRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/search/SearchingClientRepositoryImpl.java @@ -22,6 +22,8 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Join; +import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Order; import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; @@ -32,6 +34,7 @@ import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.jpa.CriteriaQueryFactory; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.portfolio.client.domain.Client; +import org.apache.fineract.portfolio.client.domain.ClientIdentifier; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; @@ -62,13 +65,15 @@ public class SearchingClientRepositoryImpl implements SearchingClientRepository Specification spec = (r, q, builder) -> { Path o = r.get("office"); + Join identity = r.join("identifiers", JoinType.LEFT); List predicates = new ArrayList<>(); predicates.add(cb.like(o.get("hierarchy"), hierarchyLikeValue)); String searchLikeValue = "%" + searchText + "%"; predicates.add(cb.or(cb.like(r.get("accountNumber"), searchLikeValue), cb.like(r.get("displayName"), searchLikeValue), - cb.like(r.get("externalId"), searchLikeValue), cb.like(r.get("mobileNo"), searchLikeValue))); + cb.like(r.get("externalId"), searchLikeValue), cb.like(r.get("mobileNo"), searchLikeValue), + cb.like(identity.get("documentKey"), searchLikeValue))); return cb.and(predicates.toArray(new Predicate[0])); }; diff --git a/fineract-provider/src/main/resources/jpa/persistence.xml b/fineract-provider/src/main/resources/jpa/persistence.xml index b398f5f4d..0d7a3654e 100644 --- a/fineract-provider/src/main/resources/jpa/persistence.xml +++ b/fineract-provider/src/main/resources/jpa/persistence.xml @@ -48,6 +48,7 @@ org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.rate.domain.Rate org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket diff --git a/fineract-rates/src/main/resources/jpa/rates/persistence.xml b/fineract-rates/src/main/resources/jpa/rates/persistence.xml index 49d7498ea..bf32dc798 100644 --- a/fineract-rates/src/main/resources/jpa/rates/persistence.xml +++ b/fineract-rates/src/main/resources/jpa/rates/persistence.xml @@ -48,6 +48,7 @@ org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.rate.domain.Rate org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket diff --git a/fineract-savings/src/main/resources/jpa/savings/persistence.xml b/fineract-savings/src/main/resources/jpa/savings/persistence.xml index bf9980fa8..7849844df 100644 --- a/fineract-savings/src/main/resources/jpa/savings/persistence.xml +++ b/fineract-savings/src/main/resources/jpa/savings/persistence.xml @@ -48,6 +48,7 @@ org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.charge.domain.Charge org.apache.fineract.portfolio.paymenttype.domain.PaymentType diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/ClientSearchTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/ClientSearchTest.java index 5d26ed4cb..537863f9f 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/ClientSearchTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/ClientSearchTest.java @@ -27,6 +27,8 @@ import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import org.apache.fineract.client.models.GetClientsClientIdResponse; import org.apache.fineract.client.models.PageClientSearchData; +import org.apache.fineract.client.models.PostClientsClientIdIdentifiersRequest; +import org.apache.fineract.client.models.PostClientsClientIdIdentifiersResponse; import org.apache.fineract.client.models.PostClientsRequest; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.SortOrder; @@ -242,4 +244,29 @@ public class ClientSearchTest { assertThat(result.getTotalElements()).isEqualTo(0); assertThat(result.getContent()).isEmpty(); } + + @Test + public void testClientSearchWorks_ByClientIdentifier() { + // given + PostClientsRequest request1 = ClientHelper.defaultClientCreationRequest(); + request1.setMobileNo(Utils.randomNumberGenerator(8).toString()); + PostClientsResponse clientResponse = clientHelper.createClient(request1); + final Long documentType = 1L; + PostClientsClientIdIdentifiersRequest identifierRequest = ClientHelper.createClientIdentifer(documentType); + final String documentKey = identifierRequest.getDocumentKey(); + PostClientsClientIdIdentifiersResponse clientIdentifierResponse = clientHelper.createClientIdentifer(clientResponse.getClientId(), + identifierRequest); + + PostClientsRequest request2 = ClientHelper.defaultClientCreationRequest(); + clientHelper.createClient(request2); + + PostClientsRequest request3 = ClientHelper.defaultClientCreationRequest(); + clientHelper.createClient(request3); + // when + PageClientSearchData result = clientHelper.searchClients(documentKey); + // then + assertThat(result.getTotalElements()).isEqualTo(1); + assertThat(result.getContent().get(0).getMobileNo()).isEqualTo(request1.getMobileNo()); + } + } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java index cfd9d50ee..82c8f54f8 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java @@ -52,6 +52,8 @@ import org.apache.fineract.client.models.PageClientSearchData; import org.apache.fineract.client.models.PagedRequestClientTextSearch; import org.apache.fineract.client.models.PostClientClientIdAddressesRequest; import org.apache.fineract.client.models.PostClientClientIdAddressesResponse; +import org.apache.fineract.client.models.PostClientsClientIdIdentifiersRequest; +import org.apache.fineract.client.models.PostClientsClientIdIdentifiersResponse; import org.apache.fineract.client.models.PostClientsClientIdResponse; import org.apache.fineract.client.models.PostClientsClientIdTransactionsTransactionIdResponse; import org.apache.fineract.client.models.PostClientsRequest; @@ -105,6 +107,11 @@ public class ClientHelper extends IntegrationTest { return ok(fineract().clients.create6(request)); } + public PostClientsClientIdIdentifiersResponse createClientIdentifer(final Long clientId, + final PostClientsClientIdIdentifiersRequest request) { + return ok(fineract().clientIdentifiers.createClientIdentifier(clientId, request)); + } + public PageClientSearchData searchClients(String text) { ClientTextSearch clientTextSearch = new ClientTextSearch(); clientTextSearch.setText(text); @@ -875,4 +882,10 @@ public class ClientHelper extends IntegrationTest { public GetLoanAccountLockResponse retrieveLockedAccounts(int page, int limit) { return ok(fineract().loanAccountLockApi.retrieveLockedAccounts(page, limit)); } + + public static PostClientsClientIdIdentifiersRequest createClientIdentifer(final Long documentType) { + return new PostClientsClientIdIdentifiersRequest().documentTypeId(documentType).documentKey(Utils.randomStringGenerator("ID_", 10)) + .description(Utils.randomStringGenerator("Desc_", 50)).status("Active"); + } + }