FINERACT-1926: Asset Externalization on Fineract
This commit is contained in:
committed by
Adam Saghy
parent
6a90ce3f10
commit
4a2aeff350
+54
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+15
@@ -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.exception.UnrecognizedQueryParamException;
|
||||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||||
import org.apache.fineract.infrastructure.core.service.CommandParameterUtil;
|
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.infrastructure.security.service.PlatformUserRightsContext;
|
||||||
|
import org.apache.fineract.investor.api.search.ExternalAssetOwnersSearchApiDelegate;
|
||||||
import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition;
|
import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition;
|
||||||
import org.apache.fineract.investor.data.ExternalOwnerJournalEntryData;
|
import org.apache.fineract.investor.data.ExternalOwnerJournalEntryData;
|
||||||
import org.apache.fineract.investor.data.ExternalOwnerTransferJournalEntryData;
|
import org.apache.fineract.investor.data.ExternalOwnerTransferJournalEntryData;
|
||||||
import org.apache.fineract.investor.data.ExternalTransferData;
|
import org.apache.fineract.investor.data.ExternalTransferData;
|
||||||
import org.apache.fineract.investor.data.ExternalTransferResponseData;
|
import org.apache.fineract.investor.data.ExternalTransferResponseData;
|
||||||
import org.apache.fineract.investor.service.ExternalAssetOwnersReadService;
|
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.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformServiceCommon;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -69,6 +72,7 @@ public class ExternalAssetOwnersApiResource {
|
|||||||
private final DefaultToApiJsonSerializer<ExternalTransferResponseData> postApiJsonSerializerService;
|
private final DefaultToApiJsonSerializer<ExternalTransferResponseData> postApiJsonSerializerService;
|
||||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||||
private final LoanReadPlatformServiceCommon loanReadPlatformService;
|
private final LoanReadPlatformServiceCommon loanReadPlatformService;
|
||||||
|
private final ExternalAssetOwnersSearchApiDelegate delegate;
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("/transfers/loans/{loanId}")
|
@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) {
|
private String getResultByTransferId(Long id, String command) {
|
||||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder();
|
final CommandWrapperBuilder builder = new CommandWrapperBuilder();
|
||||||
CommandWrapper commandRequest;
|
CommandWrapper commandRequest;
|
||||||
|
|||||||
+50
-49
@@ -28,60 +28,60 @@ final class ExternalAssetOwnersApiResourceSwagger {
|
|||||||
|
|
||||||
private ExternalAssetOwnersApiResourceSwagger() {}
|
private ExternalAssetOwnersApiResourceSwagger() {}
|
||||||
|
|
||||||
|
static final class GetExternalTransferPageItems {
|
||||||
|
|
||||||
|
private GetExternalTransferPageItems() {}
|
||||||
|
|
||||||
|
static final class GetExternalTransferOwner {
|
||||||
|
|
||||||
|
private GetExternalTransferOwner() {}
|
||||||
|
|
||||||
|
@Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
|
||||||
|
public String externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class GetExternalTransferLoan {
|
||||||
|
|
||||||
|
private GetExternalTransferLoan() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long loanId;
|
||||||
|
|
||||||
|
@Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
|
||||||
|
public String externalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long transferId;
|
||||||
|
|
||||||
|
public GetExternalTransferOwner owner;
|
||||||
|
|
||||||
|
public GetExternalTransferLoan loan;
|
||||||
|
|
||||||
|
@Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
|
||||||
|
public String transferExternalId;
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public String purchasePriceRatio;
|
||||||
|
|
||||||
|
@Schema(example = "[2023, 5, 23]")
|
||||||
|
public LocalDate settlementDate;
|
||||||
|
|
||||||
|
@Schema(example = "PENDING")
|
||||||
|
public ExternalTransferStatus status;
|
||||||
|
|
||||||
|
@Schema(example = "[2023, 5, 1]")
|
||||||
|
public LocalDate effectiveFrom;
|
||||||
|
|
||||||
|
@Schema(example = "[2023, 5, 23]")
|
||||||
|
public LocalDate effectiveTo;
|
||||||
|
}
|
||||||
|
|
||||||
@Schema(description = "ExternalTransferResponse")
|
@Schema(description = "ExternalTransferResponse")
|
||||||
public static final class GetExternalTransferResponse {
|
public static final class GetExternalTransferResponse {
|
||||||
|
|
||||||
private GetExternalTransferResponse() {}
|
private GetExternalTransferResponse() {}
|
||||||
|
|
||||||
static final class GetExternalTransferPageItems {
|
|
||||||
|
|
||||||
private GetExternalTransferPageItems() {}
|
|
||||||
|
|
||||||
static final class GetExternalTransferOwner {
|
|
||||||
|
|
||||||
private GetExternalTransferOwner() {}
|
|
||||||
|
|
||||||
@Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
|
|
||||||
public String externalId;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class GetExternalTransferLoan {
|
|
||||||
|
|
||||||
private GetExternalTransferLoan() {}
|
|
||||||
|
|
||||||
@Schema(example = "1")
|
|
||||||
public Long loanId;
|
|
||||||
|
|
||||||
@Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
|
|
||||||
public String externalId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Schema(example = "1")
|
|
||||||
public Long transferId;
|
|
||||||
|
|
||||||
public GetExternalTransferOwner owner;
|
|
||||||
|
|
||||||
public GetExternalTransferLoan loan;
|
|
||||||
|
|
||||||
@Schema(example = "e1156fbe-38bb-42f8-b491-fca02075f40e")
|
|
||||||
public String transferExternalId;
|
|
||||||
|
|
||||||
@Schema(example = "1")
|
|
||||||
public String purchasePriceRatio;
|
|
||||||
|
|
||||||
@Schema(example = "[2023, 5, 23]")
|
|
||||||
public LocalDate settlementDate;
|
|
||||||
|
|
||||||
@Schema(example = "PENDING")
|
|
||||||
public ExternalTransferStatus status;
|
|
||||||
|
|
||||||
@Schema(example = "[2023, 5, 1]")
|
|
||||||
public LocalDate effectiveFrom;
|
|
||||||
|
|
||||||
@Schema(example = "[2023, 5, 23]")
|
|
||||||
public LocalDate effectiveTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Schema(example = "20")
|
@Schema(example = "20")
|
||||||
public Integer totalFilteredRecords;
|
public Integer totalFilteredRecords;
|
||||||
public Set<GetExternalTransferPageItems> pageItems;
|
public Set<GetExternalTransferPageItems> pageItems;
|
||||||
@@ -152,4 +152,5 @@ final class ExternalAssetOwnersApiResourceSwagger {
|
|||||||
public String purchasePriceRatio;
|
public String purchasePriceRatio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* 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 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;
|
||||||
|
|
||||||
|
public interface ExternalAssetOwnersSearchApi {
|
||||||
|
|
||||||
|
Page<ExternalTransferData> searchInvestorData(PagedRequest<ExternalAssetOwnerSearchRequest> request);
|
||||||
|
|
||||||
|
}
|
||||||
+40
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+4
@@ -19,9 +19,13 @@
|
|||||||
package org.apache.fineract.investor.data;
|
package org.apache.fineract.investor.data;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class ExternalTransferDataDetails {
|
public class ExternalTransferDataDetails {
|
||||||
|
|
||||||
private Long detailsId;
|
private Long detailsId;
|
||||||
|
|||||||
+55
@@ -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;
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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 org.apache.fineract.infrastructure.core.service.PagedRequest;
|
||||||
|
import org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
|
||||||
|
public interface SearchingExternalAssetOwnerRepository {
|
||||||
|
|
||||||
|
Page<SearchedExternalAssetOwner> searchInvestorData(PagedRequest<ExternalAssetOwnerSearchRequest> searchRequest);
|
||||||
|
|
||||||
|
}
|
||||||
+106
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+53
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 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.domain;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ExternalAssetOwnerSearchRequest {
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
private LocalDate submittedFromDate;
|
||||||
|
private LocalDate submittedToDate;
|
||||||
|
private LocalDate effectiveFromDate;
|
||||||
|
private LocalDate effectiveToDate;
|
||||||
|
}
|
||||||
+77
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -18,14 +18,24 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.integrationtests.common;
|
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.ExternalOwnerJournalEntryData;
|
||||||
import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryData;
|
import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryData;
|
||||||
import org.apache.fineract.client.models.ExternalTransferData;
|
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.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.PostInitiateTransferRequest;
|
||||||
import org.apache.fineract.client.models.PostInitiateTransferResponse;
|
import org.apache.fineract.client.models.PostInitiateTransferResponse;
|
||||||
import org.apache.fineract.client.util.Calls;
|
import org.apache.fineract.client.util.Calls;
|
||||||
import org.apache.fineract.integrationtests.client.IntegrationTest;
|
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;
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class ExternalAssetOwnerHelper extends IntegrationTest {
|
public class ExternalAssetOwnerHelper extends IntegrationTest {
|
||||||
@@ -82,4 +92,36 @@ public class ExternalAssetOwnerHelper extends IntegrationTest {
|
|||||||
return ok(fineract().externalAssetOwners.getJournalEntriesOfOwner(ownerExternalId, 0, 100));
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -491,6 +491,10 @@ public final class Utils {
|
|||||||
return new Gson().toJson(map);
|
return new Gson().toJson(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String convertToJson(Object o) {
|
||||||
|
return gson.toJson(o);
|
||||||
|
}
|
||||||
|
|
||||||
public static LocalDate getDateAsLocalDate(String dateAsString) {
|
public static LocalDate getDateAsLocalDate(String dateAsString) {
|
||||||
return LocalDate.parse(dateAsString, dateFormatter);
|
return LocalDate.parse(dateAsString, dateFormatter);
|
||||||
}
|
}
|
||||||
|
|||||||
+410
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+208
@@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user