This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 4a2aeff35 FINERACT-1926: Asset Externalization on Fineract
4a2aeff35 is described below
commit 4a2aeff350dda04b4643f7e69748b295718e1ddc
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Thu Jul 27 21:31:18 2023 -0600
FINERACT-1926: Asset Externalization on Fineract
---
.../HttpMessageNotReadableErrorController.java | 54 +++
.../api/ExternalAssetOwnersApiResource.java | 15 +
.../api/ExternalAssetOwnersApiResourceSwagger.java | 69 ++--
.../search/ExternalAssetOwnersSearchApi.java} | 20 +-
.../ExternalAssetOwnersSearchApiDelegate.java | 40 ++
.../investor/data/ExternalTransferDataDetails.java | 4 +
.../domain/search/SearchedExternalAssetOwner.java | 55 +++
.../SearchingExternalAssetOwnerRepository.java} | 19 +-
.../SearchingExternalAssetOwnerRepositoryImpl.java | 106 ++++++
.../search/ExternalAssetOwnerSearchService.java | 53 +++
.../domain/ExternalAssetOwnerSearchRequest.java} | 18 +-
.../mapper/ExternalAssetOwnerSearchDataMapper.java | 77 ++++
.../common/ExternalAssetOwnerHelper.java | 42 +++
.../fineract/integrationtests/common/Utils.java | 4 +
.../ExternalAssetOwnerTransferTest.java | 410 +++++++++++++++++++++
.../SearchExternalAssetOwnerTransferTest.java | 208 +++++++++++
16 files changed, 1126 insertions(+), 68 deletions(-)
diff --git
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/HttpMessageNotReadableErrorController.java
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/HttpMessageNotReadableErrorController.java
new file mode 100644
index 000000000..2449ad4ca
--- /dev/null
+++
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/HttpMessageNotReadableErrorController.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.core.exception;
+
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ExceptionMapper;
+import jakarta.ws.rs.ext.Provider;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import
org.apache.fineract.infrastructure.core.exceptionmapper.FineractExceptionMapper;
+import org.springframework.context.annotation.Scope;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.stereotype.Component;
+
+@Provider
+@Component
+@Scope("singleton")
+@Slf4j
+public class HttpMessageNotReadableErrorController implements
ExceptionMapper<HttpMessageNotReadableException>, FineractExceptionMapper {
+
+ @Override
+ public Response toResponse(HttpMessageNotReadableException exception) {
+ final String globalisationMessageCode = "error.msg.invalid.json.data";
+ final String defaultUserMessage = "The referenced JSON data is
invalid, validate date format as yyyy-MM-dd or other cases like String instead
of Number";
+ log.warn("Exception: {}, Message: {}", exception.getClass().getName(),
defaultUserMessage);
+
+ final ApiParameterError error =
ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage);
+
+ return
Response.status(Response.Status.BAD_REQUEST).entity(error).type(MediaType.APPLICATION_JSON).build();
+ }
+
+ @Override
+ public int errorCode() {
+ return 4001;
+ }
+
+}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java
index 2a773e939..3f92519b0 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java
@@ -45,13 +45,16 @@ import
org.apache.fineract.infrastructure.core.domain.ExternalId;
import
org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
import
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.CommandParameterUtil;
+import org.apache.fineract.infrastructure.core.service.PagedRequest;
import
org.apache.fineract.infrastructure.security.service.PlatformUserRightsContext;
+import
org.apache.fineract.investor.api.search.ExternalAssetOwnersSearchApiDelegate;
import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition;
import org.apache.fineract.investor.data.ExternalOwnerJournalEntryData;
import org.apache.fineract.investor.data.ExternalOwnerTransferJournalEntryData;
import org.apache.fineract.investor.data.ExternalTransferData;
import org.apache.fineract.investor.data.ExternalTransferResponseData;
import org.apache.fineract.investor.service.ExternalAssetOwnersReadService;
+import
org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest;
import
org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformServiceCommon;
import org.springframework.context.annotation.Conditional;
import org.springframework.data.domain.Page;
@@ -69,6 +72,7 @@ public class ExternalAssetOwnersApiResource {
private final DefaultToApiJsonSerializer<ExternalTransferResponseData>
postApiJsonSerializerService;
private final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService;
private final LoanReadPlatformServiceCommon loanReadPlatformService;
+ private final ExternalAssetOwnersSearchApiDelegate delegate;
@POST
@Path("/transfers/loans/{loanId}")
@@ -190,6 +194,17 @@ public class ExternalAssetOwnersApiResource {
}
+ @POST
+ @Path("/search")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Search External Asset Owner Transfers by text or
date ranges to settlement or effective dates")
+ public Page<ExternalTransferData> searchInvestorData(@Parameter
PagedRequest<ExternalAssetOwnerSearchRequest> request) {
+ platformUserRightsContext.isAuthenticated();
+ return delegate.searchInvestorData(request);
+
+ }
+
private String getResultByTransferId(Long id, String command) {
final CommandWrapperBuilder builder = new CommandWrapperBuilder();
CommandWrapper commandRequest;
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java
index 6648770ba..e8c032d1c 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java
@@ -28,59 +28,59 @@ final class ExternalAssetOwnersApiResourceSwagger {
private ExternalAssetOwnersApiResourceSwagger() {}
- @Schema(description = "ExternalTransferResponse")
- public static final class GetExternalTransferResponse {
+ static final class GetExternalTransferPageItems {
- private GetExternalTransferResponse() {}
+ private GetExternalTransferPageItems() {}
- static final class GetExternalTransferPageItems {
+ static final class GetExternalTransferOwner {
- private GetExternalTransferPageItems() {}
+ private GetExternalTransferOwner() {}
- static final class GetExternalTransferOwner {
+ @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
+ public String externalId;
+ }
- private GetExternalTransferOwner() {}
+ static final class GetExternalTransferLoan {
- @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
- public String externalId;
- }
+ private GetExternalTransferLoan() {}
- static final class GetExternalTransferLoan {
+ @Schema(example = "1")
+ public Long loanId;
- private GetExternalTransferLoan() {}
+ @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
+ public String externalId;
+ }
- @Schema(example = "1")
- public Long loanId;
+ @Schema(example = "1")
+ public Long transferId;
- @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
- public String externalId;
- }
+ public GetExternalTransferOwner owner;
- @Schema(example = "1")
- public Long transferId;
+ public GetExternalTransferLoan loan;
- public GetExternalTransferOwner owner;
+ @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
+ public String transferExternalId;
- public GetExternalTransferLoan loan;
+ @Schema(example = "1")
+ public String purchasePriceRatio;
- @Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
- public String transferExternalId;
+ @Schema(example = "[2023, 5, 23]")
+ public LocalDate settlementDate;
- @Schema(example = "1")
- public String purchasePriceRatio;
+ @Schema(example = "PENDING")
+ public ExternalTransferStatus status;
- @Schema(example = "[2023, 5, 23]")
- public LocalDate settlementDate;
+ @Schema(example = "[2023, 5, 1]")
+ public LocalDate effectiveFrom;
- @Schema(example = "PENDING")
- public ExternalTransferStatus status;
+ @Schema(example = "[2023, 5, 23]")
+ public LocalDate effectiveTo;
+ }
- @Schema(example = "[2023, 5, 1]")
- public LocalDate effectiveFrom;
+ @Schema(description = "ExternalTransferResponse")
+ public static final class GetExternalTransferResponse {
- @Schema(example = "[2023, 5, 23]")
- public LocalDate effectiveTo;
- }
+ private GetExternalTransferResponse() {}
@Schema(example = "20")
public Integer totalFilteredRecords;
@@ -152,4 +152,5 @@ final class ExternalAssetOwnersApiResourceSwagger {
public String purchasePriceRatio;
}
}
+
}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/search/ExternalAssetOwnersSearchApi.java
similarity index 63%
copy from
fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
copy to
fineract-investor/src/main/java/org/apache/fineract/investor/api/search/ExternalAssetOwnersSearchApi.java
index 4dd5d551c..dde0dc564 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/search/ExternalAssetOwnersSearchApi.java
@@ -16,19 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.investor.data;
+package org.apache.fineract.investor.api.search;
-import java.math.BigDecimal;
-import lombok.Data;
+import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import org.apache.fineract.investor.data.ExternalTransferData;
+import
org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest;
+import org.springframework.data.domain.Page;
-@Data
-public class ExternalTransferDataDetails {
+public interface ExternalAssetOwnersSearchApi {
+
+ Page<ExternalTransferData>
searchInvestorData(PagedRequest<ExternalAssetOwnerSearchRequest> request);
- private Long detailsId;
- private BigDecimal totalOutstanding;
- private BigDecimal totalPrincipalOutstanding;
- private BigDecimal totalInterestOutstanding;
- private BigDecimal totalFeeChargesOutstanding;
- private BigDecimal totalPenaltyChargesOutstanding;
- private BigDecimal totalOverpaid;
}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/api/search/ExternalAssetOwnersSearchApiDelegate.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/search/ExternalAssetOwnersSearchApiDelegate.java
new file mode 100644
index 000000000..861404dc1
--- /dev/null
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/api/search/ExternalAssetOwnersSearchApiDelegate.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.investor.api.search;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import org.apache.fineract.investor.data.ExternalTransferData;
+import
org.apache.fineract.investor.service.search.ExternalAssetOwnerSearchService;
+import
org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class ExternalAssetOwnersSearchApiDelegate implements
ExternalAssetOwnersSearchApi {
+
+ private final ExternalAssetOwnerSearchService
externalAssetOwnerSearchService;
+
+ @Override
+ public Page<ExternalTransferData>
searchInvestorData(PagedRequest<ExternalAssetOwnerSearchRequest> request) {
+ return externalAssetOwnerSearchService.searchInvestorData(request);
+ }
+
+}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
index 4dd5d551c..2e8d509da 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
@@ -19,9 +19,13 @@
package org.apache.fineract.investor.data;
import java.math.BigDecimal;
+import lombok.AllArgsConstructor;
import lombok.Data;
+import lombok.NoArgsConstructor;
@Data
+@AllArgsConstructor
+@NoArgsConstructor
public class ExternalTransferDataDetails {
private Long detailsId;
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchedExternalAssetOwner.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchedExternalAssetOwner.java
new file mode 100644
index 000000000..47ac27321
--- /dev/null
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchedExternalAssetOwner.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.investor.domain.search;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
+import org.apache.fineract.investor.data.ExternalTransferStatus;
+import org.apache.fineract.investor.data.ExternalTransferSubStatus;
+
+@Getter
+@RequiredArgsConstructor
+public class SearchedExternalAssetOwner {
+
+ private final Long transferId;
+ private final Long loanId;
+ private final ExternalId externalLoanId;
+
+ private final ExternalId owner;
+ private final ExternalId transferExternalId;
+
+ private final ExternalTransferStatus status;
+ private final ExternalTransferSubStatus subStatus;
+
+ private final String purchasePriceRatio;
+ private final LocalDate settlementDate;
+ private final LocalDate effectiveFrom;
+ private final LocalDate effectiveTo;
+
+ private final Long detailsId;
+ private final BigDecimal totalOutstanding;
+ private final BigDecimal principalOutstanding;
+ private final BigDecimal interestOutstanding;
+ private final BigDecimal feeOutstanding;
+ private final BigDecimal penaltyOutstanding;
+ private final BigDecimal totalOverpaid;
+}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepository.java
similarity index 64%
copy from
fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
copy to
fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepository.java
index 4dd5d551c..44683acb6 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepository.java
@@ -16,19 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.investor.data;
+package org.apache.fineract.investor.domain.search;
-import java.math.BigDecimal;
-import lombok.Data;
+import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import
org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest;
+import org.springframework.data.domain.Page;
-@Data
-public class ExternalTransferDataDetails {
+public interface SearchingExternalAssetOwnerRepository {
+
+ Page<SearchedExternalAssetOwner>
searchInvestorData(PagedRequest<ExternalAssetOwnerSearchRequest> searchRequest);
- private Long detailsId;
- private BigDecimal totalOutstanding;
- private BigDecimal totalPrincipalOutstanding;
- private BigDecimal totalInterestOutstanding;
- private BigDecimal totalFeeChargesOutstanding;
- private BigDecimal totalPenaltyChargesOutstanding;
- private BigDecimal totalOverpaid;
}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepositoryImpl.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepositoryImpl.java
new file mode 100644
index 000000000..25566052f
--- /dev/null
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepositoryImpl.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.investor.domain.search;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.TypedQuery;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.JoinType;
+import jakarta.persistence.criteria.Order;
+import jakarta.persistence.criteria.Path;
+import jakarta.persistence.criteria.Predicate;
+import jakarta.persistence.criteria.Root;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.infrastructure.core.jpa.CriteriaQueryFactory;
+import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import org.apache.fineract.investor.domain.ExternalAssetOwner;
+import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
+import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferDetails;
+import
org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Repository;
+
+@Repository
+@RequiredArgsConstructor
+public class SearchingExternalAssetOwnerRepositoryImpl implements
SearchingExternalAssetOwnerRepository {
+
+ private final EntityManager entityManager;
+ private final CriteriaQueryFactory criteriaQueryFactory;
+
+ @Override
+ public Page<SearchedExternalAssetOwner>
searchInvestorData(PagedRequest<ExternalAssetOwnerSearchRequest> searchRequest)
{
+ final ExternalAssetOwnerSearchRequest request =
searchRequest.getRequest().get();
+ final Pageable pageable = searchRequest.toPageable();
+
+ CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+ CriteriaQuery<SearchedExternalAssetOwner> query =
cb.createQuery(SearchedExternalAssetOwner.class);
+
+ Root<ExternalAssetOwnerTransfer> root =
query.from(ExternalAssetOwnerTransfer.class);
+ Path<ExternalAssetOwnerTransferDetails> details =
root.join("externalAssetOwnerTransferDetails", JoinType.LEFT);
+ Path<ExternalAssetOwner> owner = root.get("owner");
+
+ Specification<ExternalAssetOwnerTransfer> spec = (r, q, builder) -> {
+ Path<ExternalAssetOwner> o = r.get("owner");
+
+ List<Predicate> predicates = new ArrayList<>();
+
+ if (StringUtils.isNotBlank(request.getText())) {
+ String searchLikeValue = "%" + request.getText() + "%";
+ predicates.add(cb.or(cb.like(r.get("externalId"),
searchLikeValue), cb.like(o.get("externalId"), searchLikeValue),
+ cb.like(r.get("externalLoanId"), searchLikeValue)));
+ }
+
+ if (request.getSubmittedFromDate() != null) {
+
predicates.add(cb.greaterThanOrEqualTo(r.get("settlementDate"),
request.getSubmittedFromDate()));
+ }
+ if (request.getSubmittedToDate() != null) {
+ predicates.add(cb.lessThanOrEqualTo(r.get("settlementDate"),
request.getSubmittedToDate()));
+ }
+
+ if (request.getEffectiveFromDate() != null) {
+
predicates.add(cb.greaterThanOrEqualTo(r.get("effectiveDateFrom"),
request.getEffectiveFromDate()));
+ }
+ if (request.getEffectiveToDate() != null) {
+ predicates.add(cb.lessThanOrEqualTo(r.get("effectiveDateTo"),
request.getEffectiveToDate()));
+ }
+
+ return cb.and(predicates.toArray(new Predicate[0]));
+ };
+ criteriaQueryFactory.applySpecificationToCriteria(root, spec, query);
+
+ List<Order> orders = criteriaQueryFactory.ordersFromPageable(pageable,
cb, root, () -> cb.desc(root.get("settlementDate")));
+ query.orderBy(orders);
+
+ query.select(cb.construct(SearchedExternalAssetOwner.class,
root.get("id"), root.get("loanId"), root.get("externalLoanId"),
+ owner.get("externalId"), root.get("externalId"),
root.get("status"), root.get("subStatus"), root.get("purchasePriceRatio"),
+ root.get("settlementDate"), root.get("effectiveDateFrom"),
root.get("effectiveDateTo"), details.get("id"),
+ details.get("totalOutstanding"),
details.get("totalPrincipalOutstanding"),
details.get("totalInterestOutstanding"),
+ details.get("totalFeeChargesOutstanding"),
details.get("totalPenaltyChargesOutstanding"), details.get("totalOverpaid")));
+
+ TypedQuery<SearchedExternalAssetOwner> queryToExecute =
entityManager.createQuery(query);
+ return criteriaQueryFactory.readPage(queryToExecute,
ExternalAssetOwnerTransfer.class, pageable, spec);
+ }
+
+}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/ExternalAssetOwnerSearchService.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/ExternalAssetOwnerSearchService.java
new file mode 100644
index 000000000..10f92e065
--- /dev/null
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/ExternalAssetOwnerSearchService.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.investor.service.search;
+
+import java.util.Objects;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.service.PagedRequest;
+import org.apache.fineract.investor.data.ExternalTransferData;
+import
org.apache.fineract.investor.domain.search.SearchingExternalAssetOwnerRepository;
+import
org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest;
+import
org.apache.fineract.investor.service.search.mapper.ExternalAssetOwnerSearchDataMapper;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@Transactional(readOnly = true)
+@RequiredArgsConstructor
+public class ExternalAssetOwnerSearchService {
+
+ private final SearchingExternalAssetOwnerRepository
externalAssetOwnerRepository;
+ private final ExternalAssetOwnerSearchDataMapper
externalAssetOwnerSearchDataMapper;
+
+ public Page<ExternalTransferData>
searchInvestorData(PagedRequest<ExternalAssetOwnerSearchRequest> searchRequest)
{
+ validateTextSearchRequest(searchRequest);
+ return executeSearch(searchRequest);
+ }
+
+ private void
validateTextSearchRequest(PagedRequest<ExternalAssetOwnerSearchRequest>
searchRequest) {
+ Objects.requireNonNull(searchRequest, "searchRequest must not be
null");
+ }
+
+ private Page<ExternalTransferData>
executeSearch(PagedRequest<ExternalAssetOwnerSearchRequest> searchRequest) {
+ return
externalAssetOwnerRepository.searchInvestorData(searchRequest).map(externalAssetOwnerSearchDataMapper::map);
+ }
+
+}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/domain/ExternalAssetOwnerSearchRequest.java
similarity index 66%
copy from
fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
copy to
fineract-investor/src/main/java/org/apache/fineract/investor/service/search/domain/ExternalAssetOwnerSearchRequest.java
index 4dd5d551c..07acd793e 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferDataDetails.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/domain/ExternalAssetOwnerSearchRequest.java
@@ -16,19 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.investor.data;
+package org.apache.fineract.investor.service.search.domain;
-import java.math.BigDecimal;
+import java.time.LocalDate;
import lombok.Data;
@Data
-public class ExternalTransferDataDetails {
+public class ExternalAssetOwnerSearchRequest {
- private Long detailsId;
- private BigDecimal totalOutstanding;
- private BigDecimal totalPrincipalOutstanding;
- private BigDecimal totalInterestOutstanding;
- private BigDecimal totalFeeChargesOutstanding;
- private BigDecimal totalPenaltyChargesOutstanding;
- private BigDecimal totalOverpaid;
+ private String text;
+ private LocalDate submittedFromDate;
+ private LocalDate submittedToDate;
+ private LocalDate effectiveFromDate;
+ private LocalDate effectiveToDate;
}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/mapper/ExternalAssetOwnerSearchDataMapper.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/mapper/ExternalAssetOwnerSearchDataMapper.java
new file mode 100644
index 000000000..1a171b4ef
--- /dev/null
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/search/mapper/ExternalAssetOwnerSearchDataMapper.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.investor.service.search.mapper;
+
+import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
+import org.apache.fineract.investor.data.ExternalTransferData;
+import org.apache.fineract.investor.data.ExternalTransferDataDetails;
+import org.apache.fineract.investor.data.ExternalTransferLoanData;
+import org.apache.fineract.investor.data.ExternalTransferOwnerData;
+import org.apache.fineract.investor.data.ExternalTransferStatus;
+import org.apache.fineract.investor.data.ExternalTransferSubStatus;
+import org.apache.fineract.investor.domain.search.SearchedExternalAssetOwner;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Named;
+
+@Mapper(config = MapstructMapperConfig.class)
+public interface ExternalAssetOwnerSearchDataMapper {
+
+ @Mapping(target = "owner", source = "source", qualifiedByName = "toOwner")
+ @Mapping(target = "loan", source = "source", qualifiedByName =
"toLoanExternalId")
+ @Mapping(target = "transferExternalId", source = "source", qualifiedByName
= "toTransferExternalId")
+ @Mapping(target = "status", source = "source", qualifiedByName =
"toStatus")
+ @Mapping(target = "subStatus", source = "source", qualifiedByName =
"toSubStatus")
+ @Mapping(target = "details", source = "source", qualifiedByName =
"toDetails")
+ ExternalTransferData map(SearchedExternalAssetOwner source);
+
+ @Named("toTransferExternalId")
+ default String toTransferExternalId(SearchedExternalAssetOwner source) {
+ return source.getTransferExternalId().getValue();
+ }
+
+ @Named("toLoanExternalId")
+ default ExternalTransferLoanData
toLoanExternalId(SearchedExternalAssetOwner source) {
+ return new ExternalTransferLoanData(source.getLoanId(),
source.getExternalLoanId().getValue());
+ }
+
+ @Named("toOwner")
+ default ExternalTransferOwnerData toOwner(SearchedExternalAssetOwner
source) {
+ return new ExternalTransferOwnerData(source.getOwner().getValue());
+ }
+
+ @Named("toStatus")
+ default ExternalTransferStatus toStatus(SearchedExternalAssetOwner source)
{
+ return source.getStatus();
+ }
+
+ @Named("toSubStatus")
+ default ExternalTransferSubStatus toSubStatus(SearchedExternalAssetOwner
source) {
+ return source.getSubStatus();
+ }
+
+ @Named("toDetails")
+ default ExternalTransferDataDetails toDetails(SearchedExternalAssetOwner
source) {
+ if (source.getDetailsId() == null) {
+ return null;
+ }
+ return new ExternalTransferDataDetails(source.getDetailsId(),
source.getTotalOutstanding(), source.getPrincipalOutstanding(),
+ source.getInterestOutstanding(), source.getFeeOutstanding(),
source.getPenaltyOutstanding(), source.getTotalOverpaid());
+ }
+}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java
index ea7831136..2edba122e 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java
@@ -18,14 +18,24 @@
*/
package org.apache.fineract.integrationtests.common;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.fineract.accounting.common.AccountingConstants;
+import org.apache.fineract.client.models.ExternalAssetOwnerSearchRequest;
import org.apache.fineract.client.models.ExternalOwnerJournalEntryData;
import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryData;
import org.apache.fineract.client.models.ExternalTransferData;
+import org.apache.fineract.client.models.GetFinancialActivityAccountsResponse;
import org.apache.fineract.client.models.PageExternalTransferData;
+import
org.apache.fineract.client.models.PagedRequestExternalAssetOwnerSearchRequest;
+import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest;
import org.apache.fineract.client.models.PostInitiateTransferRequest;
import org.apache.fineract.client.models.PostInitiateTransferResponse;
import org.apache.fineract.client.util.Calls;
import org.apache.fineract.integrationtests.client.IntegrationTest;
+import org.apache.fineract.integrationtests.common.accounting.Account;
+import
org.apache.fineract.integrationtests.common.accounting.FinancialActivityAccountHelper;
import retrofit2.Response;
public class ExternalAssetOwnerHelper extends IntegrationTest {
@@ -82,4 +92,36 @@ public class ExternalAssetOwnerHelper extends
IntegrationTest {
return
ok(fineract().externalAssetOwners.getJournalEntriesOfOwner(ownerExternalId, 0,
100));
}
+ public PageExternalTransferData
searchExternalAssetOwnerTransfer(PagedRequestExternalAssetOwnerSearchRequest
request) {
+ return ok(fineract().externalAssetOwners.searchInvestorData(request));
+ }
+
+ public PagedRequestExternalAssetOwnerSearchRequest
buildExternalAssetOwnerSearchRequest(String text, String attribute,
+ LocalDate fromDate, LocalDate toDate, Integer page, Integer size) {
+ final Integer DEFAULT_PAGE_SIZE = 50;
+ PagedRequestExternalAssetOwnerSearchRequest pagedRequest = new
PagedRequestExternalAssetOwnerSearchRequest();
+ ExternalAssetOwnerSearchRequest searchRequest = new
ExternalAssetOwnerSearchRequest();
+ searchRequest.text(text);
+ if (attribute.equals("effective")) {
+ searchRequest.setEffectiveFromDate(fromDate);
+ searchRequest.setEffectiveToDate(toDate);
+ } else if (attribute.equals("settlement")) {
+ searchRequest.setSubmittedFromDate(fromDate);
+ searchRequest.setSubmittedToDate(toDate);
+ }
+ pagedRequest.setRequest(searchRequest);
+ pagedRequest.setSorts(new ArrayList<>());
+ pagedRequest.setPage(page != null ? page : 0);
+ pagedRequest.setSize(size != null ? size : DEFAULT_PAGE_SIZE);
+ return pagedRequest;
+ }
+
+ public void setProperFinancialActivity(FinancialActivityAccountHelper
financialActivityAccountHelper, Account transferAccount) {
+ List<GetFinancialActivityAccountsResponse> financialMappings =
financialActivityAccountHelper.getAllFinancialActivityAccounts();
+ financialMappings.forEach(mapping ->
financialActivityAccountHelper.deleteFinancialActivityAccount(mapping.getId()));
+ financialActivityAccountHelper.createFinancialActivityAccount(new
PostFinancialActivityAccountsRequest()
+ .financialActivityId((long)
AccountingConstants.FinancialActivity.ASSET_TRANSFER.getValue())
+ .glAccountId((long) transferAccount.getAccountID()));
+ }
+
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
index 778575c21..3a52a10ab 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java
@@ -491,6 +491,10 @@ public final class Utils {
return new Gson().toJson(map);
}
+ public static String convertToJson(Object o) {
+ return gson.toJson(o);
+ }
+
public static LocalDate getDateAsLocalDate(String dateAsString) {
return LocalDate.parse(dateAsString, dateFormatter);
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferTest.java
new file mode 100644
index 000000000..132f28cb7
--- /dev/null
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferTest.java
@@ -0,0 +1,410 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests.investor.externalassetowner;
+
+import static
org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType.BUSINESS_DATE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.builder.ResponseSpecBuilder;
+import io.restassured.http.ContentType;
+import io.restassured.path.json.JsonPath;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.UUID;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.client.models.ExternalOwnerJournalEntryData;
+import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryData;
+import org.apache.fineract.client.models.ExternalTransferData;
+import org.apache.fineract.client.models.PageExternalTransferData;
+import org.apache.fineract.client.models.PostInitiateTransferRequest;
+import org.apache.fineract.client.models.PostInitiateTransferResponse;
+import org.apache.fineract.integrationtests.common.BusinessDateHelper;
+import org.apache.fineract.integrationtests.common.BusinessStepHelper;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
+import org.apache.fineract.integrationtests.common.ExternalAssetOwnerHelper;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.accounting.Account;
+import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
+import
org.apache.fineract.integrationtests.common.accounting.FinancialActivityAccountHelper;
+import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
+import
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
+import
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
+import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+
+@Slf4j
+public class ExternalAssetOwnerTransferTest {
+
+ protected static ResponseSpecification RESPONSE_SPEC;
+ protected static RequestSpecification REQUEST_SPEC;
+ protected static Account ASSET_ACCOUNT;
+ protected static Account FEE_PENALTY_ACCOUNT;
+ protected static Account TRANSFER_ACCOUNT;
+ protected static Account EXPENSE_ACCOUNT;
+ protected static Account INCOME_ACCOUNT;
+ protected static Account OVERPAYMENT_ACCOUNT;
+ protected static FinancialActivityAccountHelper
FINANCIAL_ACTIVITY_ACCOUNT_HELPER;
+ protected static ExternalAssetOwnerHelper EXTERNAL_ASSET_OWNER_HELPER;
+ protected static LoanTransactionHelper LOAN_TRANSACTION_HELPER;
+ protected static SchedulerJobHelper SCHEDULER_JOB_HELPER;
+ protected static LocalDate TODAYS_DATE;
+ public String ownerExternalId;
+ protected DateTimeFormatter dateFormatter = new
DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
+
+ @BeforeAll
+ public static void setupInvestorBusinessStep() {
+ Utils.initializeRESTAssured();
+ REQUEST_SPEC = new
RequestSpecBuilder().setContentType(ContentType.JSON).build();
+ REQUEST_SPEC.header("Authorization", "Basic " +
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+ RESPONSE_SPEC = new
ResponseSpecBuilder().expectStatusCode(200).build();
+ AccountHelper accountHelper = new AccountHelper(REQUEST_SPEC,
RESPONSE_SPEC);
+ EXTERNAL_ASSET_OWNER_HELPER = new ExternalAssetOwnerHelper();
+ SCHEDULER_JOB_HELPER = new SchedulerJobHelper(REQUEST_SPEC);
+ FINANCIAL_ACTIVITY_ACCOUNT_HELPER = new
FinancialActivityAccountHelper(REQUEST_SPEC);
+ LOAN_TRANSACTION_HELPER = new LoanTransactionHelper(REQUEST_SPEC,
RESPONSE_SPEC);
+
+ TODAYS_DATE = Utils.getLocalDateOfTenant();
+ new BusinessStepHelper().updateSteps("LOAN_CLOSE_OF_BUSINESS",
"APPLY_CHARGE_TO_OVERDUE_LOANS", "LOAN_DELINQUENCY_CLASSIFICATION",
+ "CHECK_LOAN_REPAYMENT_DUE", "CHECK_LOAN_REPAYMENT_OVERDUE",
"UPDATE_LOAN_ARREARS_AGING", "ADD_PERIODIC_ACCRUAL_ENTRIES",
+ "EXTERNAL_ASSET_OWNER_TRANSFER");
+
+ ASSET_ACCOUNT = accountHelper.createAssetAccount();
+ FEE_PENALTY_ACCOUNT = accountHelper.createAssetAccount();
+ TRANSFER_ACCOUNT = accountHelper.createAssetAccount();
+ EXPENSE_ACCOUNT = accountHelper.createExpenseAccount();
+ INCOME_ACCOUNT = accountHelper.createIncomeAccount();
+ OVERPAYMENT_ACCOUNT = accountHelper.createLiabilityAccount();
+
+
EXTERNAL_ASSET_OWNER_HELPER.setProperFinancialActivity(FINANCIAL_ACTIVITY_ACCOUNT_HELPER,
TRANSFER_ACCOUNT);
+ }
+
+ protected void updateBusinessDateAndExecuteCOBJob(String date) {
+ BusinessDateHelper.updateBusinessDate(REQUEST_SPEC, RESPONSE_SPEC,
BUSINESS_DATE, LocalDate.parse(date));
+ SCHEDULER_JOB_HELPER.executeAndAwaitJob("Loan COB");
+ }
+
+ protected PostInitiateTransferResponse createSaleTransfer(Integer loanID,
String settlementDate) {
+ String transferExternalId = UUID.randomUUID().toString();
+ ownerExternalId = UUID.randomUUID().toString();
+ return createSaleTransfer(loanID, settlementDate, transferExternalId,
ownerExternalId, "1.0");
+ }
+
+ protected PostInitiateTransferResponse createSaleTransfer(Integer loanID,
String settlementDate, String transferExternalId,
+ String ownerExternalId, String purchasePriceRatio) {
+ PostInitiateTransferResponse saleResponse =
EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "sale",
+ new
PostInitiateTransferRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en")
+
.transferExternalId(transferExternalId).ownerExternalId(ownerExternalId).purchasePriceRatio(purchasePriceRatio));
+ assertEquals(transferExternalId, saleResponse.getResourceExternalId());
+ return saleResponse;
+ }
+
+ protected PostInitiateTransferResponse createBuybackTransfer(Integer
loanID, String settlementDate) {
+ String transferExternalId = UUID.randomUUID().toString();
+ return createBuybackTransfer(loanID, settlementDate,
transferExternalId);
+ }
+
+ protected PostInitiateTransferResponse createBuybackTransfer(Integer
loanID, String settlementDate, String transferExternalId) {
+ PostInitiateTransferResponse saleResponse =
EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(),
"buyback",
+ new
PostInitiateTransferRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en")
+ .transferExternalId(transferExternalId));
+ assertEquals(transferExternalId, saleResponse.getResourceExternalId());
+ return saleResponse;
+ }
+
+ protected void addPenaltyForLoan(Integer loanID, String amount) {
+ // Add Charge Penalty
+ Integer penalty = ChargesHelper.createCharges(REQUEST_SPEC,
RESPONSE_SPEC,
+
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
amount, true));
+ Integer penalty1LoanChargeId =
LOAN_TRANSACTION_HELPER.addChargesForLoan(loanID,
+
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty),
"02 March 2020", amount));
+ assertNotNull(penalty1LoanChargeId);
+ }
+
+ protected void setInitialBusinessDate(String date) {
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(REQUEST_SPEC,
RESPONSE_SPEC, Boolean.TRUE);
+ BusinessDateHelper.updateBusinessDate(REQUEST_SPEC, RESPONSE_SPEC,
BUSINESS_DATE, LocalDate.parse(date));
+
GlobalConfigurationHelper.updateValueForGlobalConfiguration(REQUEST_SPEC,
RESPONSE_SPEC, "10", "0");
+ }
+
+ protected void cleanUpAndRestoreBusinessDate() {
+ REQUEST_SPEC = new
RequestSpecBuilder().setContentType(ContentType.JSON).build();
+ REQUEST_SPEC.header("Authorization", "Basic " +
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+ REQUEST_SPEC.header("Fineract-Platform-TenantId", "default");
+ RESPONSE_SPEC = new
ResponseSpecBuilder().expectStatusCode(200).build();
+ BusinessDateHelper.updateBusinessDate(REQUEST_SPEC, RESPONSE_SPEC,
BUSINESS_DATE, TODAYS_DATE);
+ GlobalConfigurationHelper.updateIsBusinessDateEnabled(REQUEST_SPEC,
RESPONSE_SPEC, Boolean.FALSE);
+ GlobalConfigurationHelper.manageConfigurations(REQUEST_SPEC,
RESPONSE_SPEC,
+ GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID,
false);
+ }
+
+ @NotNull
+ protected Integer createClient() {
+ final Integer clientID = ClientHelper.createClient(REQUEST_SPEC,
RESPONSE_SPEC);
+ Assertions.assertNotNull(clientID);
+ return clientID;
+ }
+
+ @NotNull
+ protected Integer createLoanForClient(Integer clientID, String
transactionDate) {
+ Integer overdueFeeChargeId = ChargesHelper.createCharges(REQUEST_SPEC,
RESPONSE_SPEC,
+
ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("1"));
+ Assertions.assertNotNull(overdueFeeChargeId);
+
+ Integer loanProductID =
createLoanProduct(overdueFeeChargeId.toString());
+ Assertions.assertNotNull(loanProductID);
+ HashMap loanStatusHashMap;
+
+ Integer loanID = applyForLoanApplication(clientID.toString(),
loanProductID.toString(), transactionDate);
+
+ Assertions.assertNotNull(loanID);
+
+ loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(REQUEST_SPEC,
RESPONSE_SPEC, loanID);
+ LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+ loanStatusHashMap =
LOAN_TRANSACTION_HELPER.approveLoan(transactionDate, loanID);
+ LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+
+ String loanDetails =
LOAN_TRANSACTION_HELPER.getLoanDetails(REQUEST_SPEC, RESPONSE_SPEC, loanID);
+ loanStatusHashMap =
LOAN_TRANSACTION_HELPER.disburseLoanWithNetDisbursalAmount(transactionDate,
loanID,
+
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
+ LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+ return loanID;
+ }
+
+ protected Integer createLoanProduct(final String chargeId) {
+
+ final String loanProductJSON = new
LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4")
+
.withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1")
+ .withAccountingRulePeriodicAccrual(new Account[] {
ASSET_ACCOUNT, EXPENSE_ACCOUNT, INCOME_ACCOUNT, OVERPAYMENT_ACCOUNT })
+
.withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance()
+
.withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT).build(chargeId);
+ return LOAN_TRANSACTION_HELPER.getLoanProductId(loanProductJSON);
+ }
+
+ protected Integer applyForLoanApplication(final String clientID, final
String loanProductID, final String date) {
+ List<HashMap> collaterals = new ArrayList<>();
+ Integer collateralId =
CollateralManagementHelper.createCollateralProduct(REQUEST_SPEC, RESPONSE_SPEC);
+ Assertions.assertNotNull(collateralId);
+ Integer clientCollateralId =
CollateralManagementHelper.createClientCollateral(REQUEST_SPEC, RESPONSE_SPEC,
clientID, collateralId);
+ Assertions.assertNotNull(clientCollateralId);
+ addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1));
+
+ String loanApplicationJSON = new
LoanApplicationTestBuilder().withPrincipal("15,000.00").withLoanTermFrequency("4")
+
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("4").withRepaymentEveryAfter("1")
+
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withAmortizationTypeAsEqualInstallments()
+
.withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
+
.withExpectedDisbursementDate(date).withSubmittedOnDate(date).withCollaterals(collaterals)
+ .build(clientID, loanProductID, null);
+ return LOAN_TRANSACTION_HELPER.getLoanId(loanApplicationJSON);
+ }
+
+ protected void addCollaterals(List<HashMap> collaterals, Integer
collateralId, BigDecimal quantity) {
+ collaterals.add(collaterals(collateralId, quantity));
+ }
+
+ protected HashMap<String, String> collaterals(Integer collateralId,
BigDecimal quantity) {
+ HashMap<String, String> collateral = new HashMap<>(2);
+ collateral.put("clientCollateralId", collateralId.toString());
+ collateral.put("quantity", quantity.toString());
+ return collateral;
+ }
+
+ protected void getAndValidateExternalAssetOwnerTransferByLoan(Integer
loanID, ExpectedExternalTransferData... expectedItems) {
+ PageExternalTransferData retrieveResponse =
EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue());
+ assertEquals(expectedItems.length,
retrieveResponse.getNumberOfElements());
+ validateExternalAssetOwnerTransfer(retrieveResponse, expectedItems);
+ }
+
+ protected void validateExternalAssetOwnerTransfer(PageExternalTransferData
response, ExpectedExternalTransferData... expectedItems) {
+ for (ExpectedExternalTransferData expected : expectedItems) {
+ assertNotNull(response.getContent());
+ Optional<ExternalTransferData> first =
response.getContent().stream()
+ .filter(e -> Objects.equals(e.getTransferExternalId(),
expected.transferExternalId)
+ && Objects.equals(e.getStatus(), expected.status))
+ .findFirst();
+ assertTrue(first.isPresent());
+ ExternalTransferData etd = first.get();
+ assertEquals(expected.transferExternalId,
etd.getTransferExternalId());
+ assertEquals(expected.status, etd.getStatus());
+ assertEquals(LocalDate.parse(expected.settlementDate),
etd.getSettlementDate());
+ assertEquals(LocalDate.parse(expected.effectiveFrom),
etd.getEffectiveFrom());
+ assertEquals(LocalDate.parse(expected.effectiveTo),
etd.getEffectiveTo());
+ if (!expected.detailsExpected) {
+ assertNull(etd.getDetails());
+ } else {
+ assertNotNull(etd.getDetails());
+ assertEquals(expected.totalOutstanding,
etd.getDetails().getTotalOutstanding());
+ assertEquals(expected.totalPrincipalOutstanding,
etd.getDetails().getTotalPrincipalOutstanding());
+ assertEquals(expected.totalInterestOutstanding,
etd.getDetails().getTotalInterestOutstanding());
+ assertEquals(expected.totalPenaltyOutstanding,
etd.getDetails().getTotalPenaltyChargesOutstanding());
+ assertEquals(expected.totalFeeOutstanding,
etd.getDetails().getTotalFeeChargesOutstanding());
+ assertEquals(expected.totalOverpaid,
etd.getDetails().getTotalOverpaid());
+ }
+ if (expected.subStatus != null) {
+ assertEquals(expected.subStatus, etd.getSubStatus());
+ }
+ }
+ }
+
+ protected void getAndValidateThereIsActiveMapping(Integer loanID) {
+ ExternalTransferData activeTransfer =
EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId((long) loanID);
+ assertNotNull(activeTransfer);
+ ExternalTransferData retrieveResponse =
EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()).getContent()
+ .stream().filter(transfer ->
ExternalTransferData.StatusEnum.ACTIVE.equals(transfer.getStatus())).findFirst().get();
+ assertEquals(retrieveResponse.getTransferId(),
activeTransfer.getTransferId());
+ }
+
+ protected void getAndValidateThereIsNoActiveMapping(Long loanId) {
+ ExternalTransferData activeTransfer =
EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanId);
+ assertNull(activeTransfer);
+ }
+
+ protected void getAndValidateThereIsNoActiveMapping(String
transferExternalId) {
+ ExternalTransferData activeTransfer =
EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByTransferExternalId(transferExternalId);
+ assertNull(activeTransfer);
+ }
+
+ protected void validateResponse(PostInitiateTransferResponse
transferResponse, Integer loanID) {
+ assertNotNull(transferResponse);
+ assertNotNull(transferResponse.getResourceId());
+ assertNotNull(transferResponse.getResourceExternalId());
+ assertNotNull(transferResponse.getSubResourceId());
+ assertEquals((long) loanID, transferResponse.getSubResourceId());
+ assertNotNull(transferResponse.getSubResourceExternalId());
+ assertNull(transferResponse.getChanges());
+ }
+
+ protected void getAndValidateOwnerJournalEntries(String ownerExternalId,
ExpectedJournalEntryData... expectedItems) {
+ ExternalOwnerJournalEntryData result =
EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfOwner(ownerExternalId);
+ assertNotNull(result);
+ assertEquals(expectedItems.length,
result.getJournalEntryData().getTotalElements());
+ int i = 0;
+ assertEquals(ownerExternalId, result.getOwnerData().getExternalId());
+ for (ExpectedJournalEntryData expectedJournalEntryData :
expectedItems) {
+
assertTrue(expectedJournalEntryData.amount.compareTo(result.getJournalEntryData().getContent().get(i).getAmount())
== 0);
+ assertEquals(expectedJournalEntryData.entryTypeId,
result.getJournalEntryData().getContent().get(i).getEntryType().getId());
+ assertEquals(expectedJournalEntryData.glAccountId,
result.getJournalEntryData().getContent().get(i).getGlAccountId());
+ assertEquals(expectedJournalEntryData.transactionDate,
result.getJournalEntryData().getContent().get(i).getTransactionDate());
+ assertEquals(expectedJournalEntryData.submittedOnDate,
result.getJournalEntryData().getContent().get(i).getSubmittedOnDate());
+ i++;
+ }
+ }
+
+ protected void getAndValidateThereIsJournalEntriesForTransfer(Long
transferId, ExpectedJournalEntryData... expectedItems) {
+ ExternalOwnerTransferJournalEntryData result =
EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId);
+ assertNotNull(result);
+ long totalElements = result.getJournalEntryData().getTotalElements();
+ assertEquals(expectedItems.length, totalElements);
+ int i = 0;
+ assertEquals(transferId, result.getTransferData().getTransferId());
+ for (ExpectedJournalEntryData expectedJournalEntryData :
expectedItems) {
+
assertTrue(expectedJournalEntryData.amount.compareTo(result.getJournalEntryData().getContent().get(i).getAmount())
== 0);
+ assertEquals(expectedJournalEntryData.entryTypeId,
result.getJournalEntryData().getContent().get(i).getEntryType().getId());
+ assertEquals(expectedJournalEntryData.glAccountId,
result.getJournalEntryData().getContent().get(i).getGlAccountId());
+ assertEquals(expectedJournalEntryData.transactionDate,
result.getJournalEntryData().getContent().get(i).getTransactionDate());
+ assertEquals(expectedJournalEntryData.submittedOnDate,
result.getJournalEntryData().getContent().get(i).getSubmittedOnDate());
+ i++;
+ }
+ }
+
+ protected void getAndValidateThereIsNoJournalEntriesForTransfer(Long
transferId) {
+ ExternalOwnerTransferJournalEntryData result =
EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId);
+ assertNull(result.getJournalEntryData());
+ }
+
+ @RequiredArgsConstructor()
+ public static class ExpectedExternalTransferData {
+
+ private final ExternalTransferData.StatusEnum status;
+
+ private final String transferExternalId;
+
+ private final String settlementDate;
+
+ private final String effectiveFrom;
+ private final String effectiveTo;
+ private final ExternalTransferData.SubStatusEnum subStatus;
+ private final boolean detailsExpected;
+ private final BigDecimal totalOutstanding;
+ private final BigDecimal totalPrincipalOutstanding;
+ private final BigDecimal totalInterestOutstanding;
+ private final BigDecimal totalPenaltyOutstanding;
+ private final BigDecimal totalFeeOutstanding;
+ private final BigDecimal totalOverpaid;
+
+ static ExpectedExternalTransferData
expected(ExternalTransferData.StatusEnum status, String transferExternalId,
+ String settlementDate, String effectiveFrom, String
effectiveTo, boolean detailsExpected, BigDecimal totalOutstanding,
+ BigDecimal totalPrincipalOutstanding, BigDecimal
totalInterestOutstanding, BigDecimal totalPenaltyOutstanding,
+ BigDecimal totalFeeOutstanding, BigDecimal totalOverpaid) {
+ return new ExpectedExternalTransferData(status,
transferExternalId, settlementDate, effectiveFrom, effectiveTo, null,
+ detailsExpected, totalOutstanding,
totalPrincipalOutstanding, totalInterestOutstanding, totalPenaltyOutstanding,
+ totalFeeOutstanding, totalOverpaid);
+ }
+
+ static ExpectedExternalTransferData
expected(ExternalTransferData.StatusEnum status, String transferExternalId,
+ String settlementDate, String effectiveFrom, String
effectiveTo) {
+ return new ExpectedExternalTransferData(status,
transferExternalId, settlementDate, effectiveFrom, effectiveTo, null, false,
+ null, null, null, null, null, null);
+ }
+
+ static ExpectedExternalTransferData
expected(ExternalTransferData.StatusEnum status, String transferExternalId,
+ String settlementDate, String effectiveFrom, String
effectiveTo, ExternalTransferData.SubStatusEnum subStatus) {
+ return new ExpectedExternalTransferData(status,
transferExternalId, settlementDate, effectiveFrom, effectiveTo, subStatus,
+ false, null, null, null, null, null, null);
+ }
+ }
+
+ @RequiredArgsConstructor()
+ public static class ExpectedJournalEntryData {
+
+ private final Long glAccountId;
+
+ private final Long entryTypeId;
+
+ private final BigDecimal amount;
+ private final LocalDate transactionDate;
+ private final LocalDate submittedOnDate;
+
+ static ExpectedJournalEntryData expected(Long glAccountId, Long
entryTypeId, BigDecimal amount, LocalDate transactionDate,
+ LocalDate submittedOnDate) {
+ return new ExpectedJournalEntryData(glAccountId, entryTypeId,
amount, transactionDate, submittedOnDate);
+ }
+
+ }
+}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/SearchExternalAssetOwnerTransferTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/SearchExternalAssetOwnerTransferTest.java
new file mode 100644
index 000000000..13a0c2a40
--- /dev/null
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/SearchExternalAssetOwnerTransferTest.java
@@ -0,0 +1,208 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests.investor.externalassetowner;
+
+import static
org.apache.fineract.client.models.ExternalTransferData.StatusEnum.CANCELLED;
+import static
org.apache.fineract.client.models.ExternalTransferData.StatusEnum.PENDING;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.UUID;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.client.models.PageExternalTransferData;
+import
org.apache.fineract.client.models.PagedRequestExternalAssetOwnerSearchRequest;
+import org.apache.fineract.client.models.PostInitiateTransferResponse;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import
org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@Slf4j
+@ExtendWith(LoanTestLifecycleExtension.class)
+public class SearchExternalAssetOwnerTransferTest extends
ExternalAssetOwnerTransferTest {
+
+ @Test
+ public void saleActiveLoanToExternalAssetOwnerWithSearching() {
+ final String baseDate = "2020-02-29";
+ LocalDate baseLocalDate = Utils.getDateAsLocalDate("29 February 2020");
+
+ try {
+ GlobalConfigurationHelper.manageConfigurations(REQUEST_SPEC,
RESPONSE_SPEC,
+
GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true);
+ setInitialBusinessDate("2020-02-29");
+ Integer clientID = createClient();
+ Integer loanID = createLoanForClient(clientID, "29 February 2020");
+ addPenaltyForLoan(loanID, "10");
+
+ PostInitiateTransferResponse saleTransferResponse =
createSaleTransfer(loanID, baseDate);
+ validateResponse(saleTransferResponse, loanID);
+
+ // LookUp by ExternalId
+ String externalId = saleTransferResponse.getResourceExternalId();
+ PagedRequestExternalAssetOwnerSearchRequest searchRequest =
EXTERNAL_ASSET_OWNER_HELPER
+ .buildExternalAssetOwnerSearchRequest(externalId, "",
null, null, null, null);
+ PageExternalTransferData response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+
+ validateExternalAssetOwnerTransfer(response,
+ ExpectedExternalTransferData.expected(PENDING,
saleTransferResponse.getResourceExternalId(), baseDate, baseDate,
+ "9999-12-31", false, new
BigDecimal("15767.420000"), new BigDecimal("15000.000000"),
+ new BigDecimal("757.420000"), new
BigDecimal("10.000000"), new BigDecimal("0.000000"),
+ new BigDecimal("0.000000")));
+ // LookUp by Effective Date
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest("",
"settlement", baseLocalDate, null, null,
+ null);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+
+ validateExternalAssetOwnerTransfer(response,
+ ExpectedExternalTransferData.expected(PENDING,
saleTransferResponse.getResourceExternalId(), baseDate, baseDate,
+ "9999-12-31", false, new
BigDecimal("15767.420000"), new BigDecimal("15000.000000"),
+ new BigDecimal("757.420000"), new
BigDecimal("10.000000"), new BigDecimal("0.000000"),
+ new BigDecimal("0.000000")));
+
+ // Cancel the External Asset Transfer
+
EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalId(saleTransferResponse.getResourceExternalId());
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(externalId,
"", null, null, null, null);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+
+ validateExternalAssetOwnerTransfer(response,
+ ExpectedExternalTransferData.expected(PENDING,
saleTransferResponse.getResourceExternalId(), baseDate, baseDate,
+ baseDate, false, new BigDecimal("15767.420000"),
new BigDecimal("15000.000000"), new BigDecimal("757.420000"),
+ new BigDecimal("10.000000"), new
BigDecimal("0.000000"), new BigDecimal("0.000000")),
+ ExpectedExternalTransferData.expected(CANCELLED,
saleTransferResponse.getResourceExternalId(), baseDate, baseDate,
+ baseDate, false, new BigDecimal("15767.420000"),
new BigDecimal("15000.000000"), new BigDecimal("757.420000"),
+ new BigDecimal("10.000000"), new
BigDecimal("0.000000"), new BigDecimal("0.000000")));
+
+ // LookUp by Effective Date
+ // LookUp by Effective Date
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest("",
"effective", baseLocalDate, baseLocalDate,
+ null, null);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+
+ validateExternalAssetOwnerTransfer(response,
+ ExpectedExternalTransferData.expected(PENDING,
saleTransferResponse.getResourceExternalId(), baseDate, baseDate,
+ baseDate, false, new BigDecimal("15767.420000"),
new BigDecimal("15000.000000"), new BigDecimal("757.420000"),
+ new BigDecimal("10.000000"), new
BigDecimal("0.000000"), new BigDecimal("0.000000")),
+ ExpectedExternalTransferData.expected(CANCELLED,
saleTransferResponse.getResourceExternalId(), baseDate, baseDate,
+ baseDate, false, new BigDecimal("15767.420000"),
new BigDecimal("15000.000000"), new BigDecimal("757.420000"),
+ new BigDecimal("10.000000"), new
BigDecimal("0.000000"), new BigDecimal("0.000000")));
+
+ } finally {
+ cleanUpAndRestoreBusinessDate();
+ }
+ }
+
+ @Test
+ public void initialSearchExternalAssetOwnerTransferUsingTextTest() {
+ String textToSearch = UUID.randomUUID().toString();
+ PagedRequestExternalAssetOwnerSearchRequest searchRequest =
EXTERNAL_ASSET_OWNER_HELPER
+ .buildExternalAssetOwnerSearchRequest(textToSearch, "", null,
null, 0, 10);
+ PageExternalTransferData response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ assertNotNull(response);
+ assertEquals("Expecting none result", 0, response.getContent().size());
+
+ // Search over the current Asset Transfers and get just the first five
+ textToSearch = "";
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(textToSearch,
"", null, null, 0, 5);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ assertNotNull(response);
+ assertEquals("Expecting first five results", 5,
response.getContent().size());
+
+ textToSearch =
response.getContent().iterator().next().getOwner().getExternalId();
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(textToSearch,
"", null, null, 0, 5);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ assertNotNull(response);
+ assertTrue("Expecting only two results", response.getContent().size()
>= 2);
+ assertEquals("External Id is different", textToSearch,
response.getContent().iterator().next().getOwner().getExternalId());
+ }
+
+ @Test
+ public void
initialSearchExternalAssetOwnerTransferUsingEffectiveDateTest() {
+ final String attribute = "effective";
+ LocalDate fromDate = Utils.getDateAsLocalDate("01 March 2023");
+ LocalDate toDate = fromDate.plusMonths(3);
+ PagedRequestExternalAssetOwnerSearchRequest searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(null,
+ attribute, fromDate, toDate, 0, null);
+ PageExternalTransferData response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ validateResponse(response, 0);
+
+ fromDate = Utils.getDateAsLocalDate("01 January 2020");
+ toDate = fromDate.plusMonths(6);
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(null,
attribute, fromDate, toDate, 0, null);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ validateResponse(response, 1);
+ assertTrue("Transfers were not found", response.getContent().size() >
0);
+ }
+
+ @Test
+ public void
initialSearchExternalAssetOwnerTransferUsingSubmittedDateTest() {
+ final String attribute = "settlement";
+ LocalDate fromDate = Utils.getDateAsLocalDate("01 March 2023");
+ LocalDate toDate = fromDate.plusMonths(3);
+ PagedRequestExternalAssetOwnerSearchRequest searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(null,
+ attribute, fromDate, toDate, 0, null);
+ PageExternalTransferData response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ validateResponse(response, 0);
+
+ fromDate = Utils.getDateAsLocalDate("01 February 2020");
+ toDate = fromDate.plusMonths(3);
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(null,
attribute, fromDate, toDate, 0, null);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ validateResponse(response, 1);
+ assertTrue("Transfers were not found", response.getContent().size() >
0);
+ }
+
+ @Test
+ public void initialSearchExternalAssetOwnerTransferUsingTextAndDatesTest()
{
+ final String textToSearch = UUID.randomUUID().toString();
+ final String attribute = "settlement";
+ LocalDate fromDate = Utils.getDateAsLocalDate("01 March 2023");
+ LocalDate toDate = fromDate.plusMonths(3);
+ PagedRequestExternalAssetOwnerSearchRequest searchRequest =
EXTERNAL_ASSET_OWNER_HELPER
+ .buildExternalAssetOwnerSearchRequest(textToSearch, attribute,
fromDate, toDate, 0, null);
+ PageExternalTransferData response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ validateResponse(response, 0);
+
+ fromDate = Utils.getDateAsLocalDate("01 February 2020");
+ toDate = fromDate.plusMonths(3);
+ searchRequest =
EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(textToSearch,
attribute, fromDate, toDate, 0,
+ null);
+ response =
EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
+ validateResponse(response, 0);
+ }
+
+ private void validateResponse(PageExternalTransferData response, final
Integer size) {
+ assertNotNull(response);
+ final boolean isEmpty = (size == 0);
+ assertEquals(isEmpty, response.getEmpty());
+ assertEquals(true, response.getFirst());
+ if (isEmpty) {
+ assertTrue("Transfers size difference",
response.getContent().size() == size);
+ assertTrue("Total pages difference", response.getTotalPages() ==
0);
+ } else {
+ assertTrue("Total pages difference", response.getTotalPages() > 0);
+ assertTrue("Total number of elements difference",
response.getNumberOfElements() > 0);
+ }
+ assertEquals(true, response.getFirst());
+ }
+
+}