FINERACT-1926: Fineract Asset Externalization - Cancel
- [x] Cancel API - [x] Event raised on cancel - [x] Integration test for cancel
This commit is contained in:
+8
@@ -3638,4 +3638,12 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/external-asset-owners/transfers/loans/" + loanId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder cancelTransactionByIdToExternalAssetOwner(final Long id) {
|
||||
this.actionName = "CANCEL";
|
||||
this.entityName = "ASSET_OWNER_TRANSACTION";
|
||||
this.entityId = id;
|
||||
this.href = "/external-asset-owners/transfers/" + id;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+42
@@ -41,6 +41,7 @@ import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
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;
|
||||
@@ -101,6 +102,35 @@ public class ExternalAssetOwnersApiResource {
|
||||
return getResult(loanId, apiRequestBodyAsJson, commandParam);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/transfers/{id}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnersApiResourceSwagger.PostInitiateTransferResponse.class))),
|
||||
@ApiResponse(responseCode = "403", description = "Transfer cannot be initiated") })
|
||||
public String transferRequestWithId(@PathParam("id") final Long id,
|
||||
@QueryParam("command") @Parameter(description = "command") final String commandParam,
|
||||
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
platformUserRightsContext.isAuthenticated();
|
||||
return getResultByTransferId(id, commandParam);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/transfers/external-id/{externalId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnersApiResourceSwagger.PostInitiateTransferResponse.class))),
|
||||
@ApiResponse(responseCode = "403", description = "Transfer cannot be initiated") })
|
||||
public String transferRequestWithId(@PathParam("externalId") final String externalId,
|
||||
@QueryParam("command") @Parameter(description = "command") final String commandParam,
|
||||
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
platformUserRightsContext.isAuthenticated();
|
||||
Long id = externalAssetOwnersReadService.retrieveLastTransferIdByExternalId(new ExternalId(externalId));
|
||||
return getResultByTransferId(id, commandParam);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/transfers")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@@ -160,6 +190,18 @@ public class ExternalAssetOwnersApiResource {
|
||||
|
||||
}
|
||||
|
||||
private String getResultByTransferId(Long id, String command) {
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder();
|
||||
CommandWrapper commandRequest;
|
||||
if (CommandParameterUtil.is(command, "cancel")) {
|
||||
commandRequest = builder.cancelTransactionByIdToExternalAssetOwner(id).build();
|
||||
} else {
|
||||
throw new UnrecognizedQueryParamException("command", command);
|
||||
}
|
||||
CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
return postApiJsonSerializerService.serialize(result);
|
||||
}
|
||||
|
||||
private String getResult(Long loanId, String apiRequestBodyAsJson, String commandParam) {
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
CommandWrapper commandRequest = null;
|
||||
|
||||
+6
-2
@@ -47,8 +47,12 @@ public interface ExternalAssetOwnerTransferRepository
|
||||
@Query("select m.ownerTransfer.owner from ExternalAssetOwnerTransferLoanMapping m where m.loanId = :loanId")
|
||||
Optional<ExternalAssetOwner> findActiveOwnerByLoanId(@Param("loanId") Long loanId);
|
||||
|
||||
@Query("SELECT t FROM ExternalAssetOwnerTransfer t WHERE t.loanId = :loanId AND t.effectiveDateTo > :effectiveDate")
|
||||
List<ExternalAssetOwnerTransfer> findEffectiveTransfers(@Param("loanId") Long loanId, @Param("effectiveDate") LocalDate effectiveDate);
|
||||
@Query("SELECT t FROM ExternalAssetOwnerTransfer t WHERE t.loanId = :loanId AND t.effectiveDateTo > :effectiveDate order by t.id desc")
|
||||
List<ExternalAssetOwnerTransfer> findEffectiveTransfersOrderByIdDesc(@Param("loanId") Long loanId,
|
||||
@Param("effectiveDate") LocalDate effectiveDate);
|
||||
|
||||
Optional<ExternalAssetOwnerTransfer> findFirstByExternalIdOrderByIdAsc(ExternalId externalTransferId);
|
||||
|
||||
@Query("select e.id from ExternalAssetOwnerTransfer e where e.externalId = :externalTransferId")
|
||||
Optional<Long> findLastByExternalIdOrderByIdDesc(@Param("externalTransferId") ExternalId externalTransferId);
|
||||
}
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@CommandType(entity = "ASSET_OWNER_TRANSACTION", action = "CANCEL")
|
||||
public class CancelLoanFromExternalAssetOwnerHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(JsonCommand command) {
|
||||
return externalAssetOwnersWriteService.cancelTransactionById(command);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@CommandType(entity = "LOAN", action = "CANCEL")
|
||||
public class CancelTransactionFromExternalAssetOwnerHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService;
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(JsonCommand command) {
|
||||
return externalAssetOwnersWriteService.cancelTransactionById(command);
|
||||
}
|
||||
}
|
||||
+2
@@ -38,4 +38,6 @@ public interface ExternalAssetOwnersReadService {
|
||||
ExternalOwnerJournalEntryData retrieveJournalEntriesOfOwner(String ownerExternalId, Integer offset, Integer limit);
|
||||
|
||||
ExternalTransferData retrieveFirstTransferByExternalId(ExternalId externalTransferId);
|
||||
|
||||
Long retrieveLastTransferIdByExternalId(ExternalId externalTransferId);
|
||||
}
|
||||
|
||||
+6
@@ -120,6 +120,12 @@ public class ExternalAssetOwnersReadServiceImpl implements ExternalAssetOwnersRe
|
||||
.orElseThrow(() -> new ExternalAssetOwnerTransferNotFoundException(externalTransferId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long retrieveLastTransferIdByExternalId(ExternalId externalTransferId) {
|
||||
return externalAssetOwnerTransferRepository.findLastByExternalIdOrderByIdDesc(externalTransferId)
|
||||
.orElseThrow(() -> new ExternalAssetOwnerTransferNotFoundException(externalTransferId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransferData retrieveTransferData(Long transferId) {
|
||||
return externalAssetOwnerTransferRepository.findById(transferId).map(mapper::mapTransfer)
|
||||
|
||||
+2
@@ -27,4 +27,6 @@ public interface ExternalAssetOwnersWriteService {
|
||||
|
||||
CommandProcessingResult buybackLoanByLoanId(JsonCommand command);
|
||||
|
||||
CommandProcessingResult cancelTransactionById(JsonCommand command);
|
||||
|
||||
}
|
||||
|
||||
+59
-3
@@ -45,13 +45,18 @@ import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAccountSnapshotBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.investor.data.ExternalTransferRequestParameters;
|
||||
import org.apache.fineract.investor.data.ExternalTransferStatus;
|
||||
import org.apache.fineract.investor.data.ExternalTransferSubStatus;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwner;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerRepository;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
|
||||
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
|
||||
import org.apache.fineract.investor.domain.LoanOwnershipTransferBusinessEvent;
|
||||
import org.apache.fineract.investor.exception.ExternalAssetOwnerInitiateTransferException;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
@@ -71,6 +76,7 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
|
||||
private final ExternalAssetOwnerRepository externalAssetOwnerRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final LoanRepository loanRepository;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@@ -107,9 +113,23 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult cancelTransactionById(JsonCommand command) {
|
||||
ExternalAssetOwnerTransfer externalAssetOwnerTransfer = fetchAndValidateEffectiveTransferForCancel(command.entityId());
|
||||
externalAssetOwnerTransfer.setEffectiveDateTo(DateUtils.getBusinessLocalDate());
|
||||
ExternalAssetOwnerTransfer cancelTransfer = createCancelTransfer(externalAssetOwnerTransfer);
|
||||
externalAssetOwnerTransferRepository.save(cancelTransfer);
|
||||
externalAssetOwnerTransferRepository.save(externalAssetOwnerTransfer);
|
||||
Loan loan = loanRepository.findById(externalAssetOwnerTransfer.getLoanId())
|
||||
.orElseThrow(() -> new LoanNotFoundException(externalAssetOwnerTransfer.getLoanId()));
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanOwnershipTransferBusinessEvent(cancelTransfer, loan));
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccountSnapshotBusinessEvent(loan));
|
||||
return buildResponseData(cancelTransfer);
|
||||
}
|
||||
|
||||
private void validateEffectiveTransferForSale(final ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
|
||||
List<ExternalAssetOwnerTransfer> effectiveTransfers = externalAssetOwnerTransferRepository
|
||||
.findEffectiveTransfers(externalAssetOwnerTransfer.getLoanId(), externalAssetOwnerTransfer.getSettlementDate());
|
||||
.findEffectiveTransfersOrderByIdDesc(externalAssetOwnerTransfer.getLoanId(), DateUtils.getBusinessLocalDate());
|
||||
|
||||
if (effectiveTransfers.size() == 2) {
|
||||
throw new ExternalAssetOwnerInitiateTransferException("This loan cannot be sold, there is already an in progress transfer");
|
||||
@@ -128,8 +148,8 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
|
||||
}
|
||||
|
||||
private ExternalAssetOwnerTransfer fetchAndValidateEffectiveTransferForBuyback(final Long loanId, final LocalDate settlementDate) {
|
||||
List<ExternalAssetOwnerTransfer> effectiveTransfers = externalAssetOwnerTransferRepository.findEffectiveTransfers(loanId,
|
||||
settlementDate);
|
||||
List<ExternalAssetOwnerTransfer> effectiveTransfers = externalAssetOwnerTransferRepository
|
||||
.findEffectiveTransfersOrderByIdDesc(loanId, DateUtils.getBusinessLocalDate());
|
||||
|
||||
if (effectiveTransfers.size() == 0) {
|
||||
throw new ExternalAssetOwnerInitiateTransferException(
|
||||
@@ -150,6 +170,27 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
|
||||
return effectiveTransfers.get(0);
|
||||
}
|
||||
|
||||
private ExternalAssetOwnerTransfer fetchAndValidateEffectiveTransferForCancel(final Long transferId) {
|
||||
ExternalAssetOwnerTransfer selectedTransfer = externalAssetOwnerTransferRepository.findById(transferId)
|
||||
.orElseThrow(() -> new ExternalAssetOwnerInitiateTransferException(
|
||||
String.format("This loan cannot be cancelled, transfer with id %s does not exist", transferId)));
|
||||
|
||||
List<ExternalAssetOwnerTransfer> effective = externalAssetOwnerTransferRepository
|
||||
.findEffectiveTransfersOrderByIdDesc(selectedTransfer.getLoanId(), DateUtils.getBusinessLocalDate());
|
||||
if (effective.isEmpty()) {
|
||||
throw new ExternalAssetOwnerInitiateTransferException(
|
||||
String.format("This loan cannot be cancelled, there is no effective transfer for this loan"));
|
||||
} else if (!Objects.equals(effective.get(0).getId(), selectedTransfer.getId())) {
|
||||
throw new ExternalAssetOwnerInitiateTransferException(
|
||||
String.format("This loan cannot be cancelled, selected transfer is not the latest"));
|
||||
} else if (selectedTransfer.getStatus() != ExternalTransferStatus.PENDING
|
||||
&& selectedTransfer.getStatus() != ExternalTransferStatus.BUYBACK) {
|
||||
throw new ExternalAssetOwnerInitiateTransferException(
|
||||
"This loan cannot be cancelled, the selected transfer status is not pending or buyback");
|
||||
}
|
||||
return selectedTransfer;
|
||||
}
|
||||
|
||||
private ExternalAssetOwnerTransfer createBuybackTransfer(ExternalAssetOwnerTransfer effectiveTransfer, LocalDate settlementDate,
|
||||
ExternalId externalId) {
|
||||
LocalDate effectiveDateFrom = DateUtils.getBusinessLocalDate();
|
||||
@@ -168,6 +209,21 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
|
||||
return externalAssetOwnerTransfer;
|
||||
}
|
||||
|
||||
private ExternalAssetOwnerTransfer createCancelTransfer(ExternalAssetOwnerTransfer effectiveTransfer) {
|
||||
ExternalAssetOwnerTransfer externalAssetOwnerTransfer = new ExternalAssetOwnerTransfer();
|
||||
externalAssetOwnerTransfer.setExternalId(effectiveTransfer.getExternalId());
|
||||
externalAssetOwnerTransfer.setStatus(ExternalTransferStatus.CANCELLED);
|
||||
externalAssetOwnerTransfer.setSubStatus(ExternalTransferSubStatus.USER_REQUESTED);
|
||||
externalAssetOwnerTransfer.setLoanId(effectiveTransfer.getLoanId());
|
||||
externalAssetOwnerTransfer.setExternalLoanId(effectiveTransfer.getExternalLoanId());
|
||||
externalAssetOwnerTransfer.setOwner(effectiveTransfer.getOwner());
|
||||
externalAssetOwnerTransfer.setSettlementDate(effectiveTransfer.getSettlementDate());
|
||||
externalAssetOwnerTransfer.setEffectiveDateFrom(effectiveTransfer.getEffectiveDateFrom());
|
||||
externalAssetOwnerTransfer.setEffectiveDateTo(effectiveTransfer.getEffectiveDateTo());
|
||||
externalAssetOwnerTransfer.setPurchasePriceRatio(effectiveTransfer.getPurchasePriceRatio());
|
||||
return externalAssetOwnerTransfer;
|
||||
}
|
||||
|
||||
private CommandProcessingResult buildResponseData(ExternalAssetOwnerTransfer savedExternalAssetOwnerTransfer) {
|
||||
return new CommandProcessingResultBuilder().withEntityId(savedExternalAssetOwnerTransfer.getId())
|
||||
.withEntityExternalId(savedExternalAssetOwnerTransfer.getExternalId())
|
||||
|
||||
+12
@@ -24,7 +24,9 @@ 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.client.util.Calls;
|
||||
import org.apache.fineract.integrationtests.client.IntegrationTest;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class ExternalAssetOwnerHelper extends IntegrationTest {
|
||||
|
||||
@@ -34,6 +36,16 @@ public class ExternalAssetOwnerHelper extends IntegrationTest {
|
||||
return ok(fineract().externalAssetOwners.transferRequestWithLoanId(loanId, request, command));
|
||||
}
|
||||
|
||||
public void cancelTransferByTransferExternalId(String transferExternalId) {
|
||||
ok(fineract().externalAssetOwners.transferRequestWithId1(transferExternalId, "cancel"));
|
||||
}
|
||||
|
||||
public void cancelTransferByTransferExternalIdError(String transferExternalId) {
|
||||
Response<PostInitiateTransferResponse> response = Calls
|
||||
.executeU(fineract().externalAssetOwners.transferRequestWithId1(transferExternalId, "cancel"));
|
||||
assertThat(response.code()).isEqualTo(403);
|
||||
}
|
||||
|
||||
public PageExternalTransferData retrieveTransferByTransferExternalId(String transferExternalId) {
|
||||
return ok(fineract().externalAssetOwners.getTransfers(transferExternalId, null, null, 0, 100));
|
||||
}
|
||||
|
||||
+461
@@ -0,0 +1,461 @@
|
||||
/**
|
||||
* 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.BUYBACK;
|
||||
import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.CANCELLED;
|
||||
import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.PENDING;
|
||||
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 org.apache.fineract.accounting.common.AccountingConstants;
|
||||
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.PostFinancialActivityAccountsRequest;
|
||||
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.LoanTestLifecycleExtension;
|
||||
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;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@ExtendWith(LoanTestLifecycleExtension.class)
|
||||
public class ExternalAssetOwnerTransferCancelTest {
|
||||
|
||||
public String ownerExternalId;
|
||||
private static ResponseSpecification RESPONSE_SPEC;
|
||||
private static RequestSpecification REQUEST_SPEC;
|
||||
private static Account ASSET_ACCOUNT;
|
||||
private static Account FEE_PENALTY_ACCOUNT;
|
||||
private static Account TRANSFER_ACCOUNT;
|
||||
private static Account EXPENSE_ACCOUNT;
|
||||
private static Account INCOME_ACCOUNT;
|
||||
private static Account OVERPAYMENT_ACCOUNT;
|
||||
private static FinancialActivityAccountHelper FINANCIAL_ACTIVITY_ACCOUNT_HELPER;
|
||||
private static ExternalAssetOwnerHelper EXTERNAL_ASSET_OWNER_HELPER;
|
||||
private static LoanTransactionHelper LOAN_TRANSACTION_HELPER;
|
||||
private static SchedulerJobHelper SCHEDULER_JOB_HELPER;
|
||||
private static LocalDate TODAYS_DATE;
|
||||
private 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();
|
||||
|
||||
setProperFinancialActivity(TRANSFER_ACCOUNT);
|
||||
}
|
||||
|
||||
private static void setProperFinancialActivity(Account transferAccount) {
|
||||
List<GetFinancialActivityAccountsResponse> financialMappings = FINANCIAL_ACTIVITY_ACCOUNT_HELPER.getAllFinancialActivityAccounts();
|
||||
financialMappings.forEach(mapping -> FINANCIAL_ACTIVITY_ACCOUNT_HELPER.deleteFinancialActivityAccount(mapping.getId()));
|
||||
FINANCIAL_ACTIVITY_ACCOUNT_HELPER.createFinancialActivityAccount(new PostFinancialActivityAccountsRequest()
|
||||
.financialActivityId((long) AccountingConstants.FinancialActivity.ASSET_TRANSFER.getValue())
|
||||
.glAccountId((long) transferAccount.getAccountID()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successCancelSale() {
|
||||
try {
|
||||
GlobalConfigurationHelper.manageConfigurations(REQUEST_SPEC, RESPONSE_SPEC,
|
||||
GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true);
|
||||
setInitialBusinessDate("2020-03-02");
|
||||
Integer clientID = createClient();
|
||||
Integer loanID = createLoanForClient(clientID);
|
||||
addPenaltyForLoan(loanID, "10");
|
||||
|
||||
PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02");
|
||||
validateResponse(saleTransferResponse, loanID);
|
||||
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
|
||||
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02",
|
||||
"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")));
|
||||
|
||||
PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue());
|
||||
retrieveResponse.getContent().forEach(transfer -> getAndValidateThereIsNoJournalEntriesForTransfer(transfer.getTransferId()));
|
||||
|
||||
EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalId(saleTransferResponse.getResourceExternalId());
|
||||
|
||||
// updateBusinessDateAndExecuteCOBJob("2020-03-03");
|
||||
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
|
||||
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02",
|
||||
"2020-03-02", 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(), "2020-03-02",
|
||||
"2020-03-02", "2020-03-02", 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();
|
||||
}
|
||||
}
|
||||
|
||||
private void getAndValidateThereIsNoJournalEntriesForTransfer(Long transferId) {
|
||||
ExternalOwnerTransferJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId);
|
||||
assertNull(result.getJournalEntryData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saleAndBuybackOnTheSameDay() {
|
||||
try {
|
||||
GlobalConfigurationHelper.manageConfigurations(REQUEST_SPEC, RESPONSE_SPEC,
|
||||
GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true);
|
||||
setInitialBusinessDate("2020-03-02");
|
||||
Integer clientID = createClient();
|
||||
Integer loanID = createLoanForClient(clientID);
|
||||
|
||||
PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02");
|
||||
validateResponse(saleTransferResponse, loanID);
|
||||
PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-02");
|
||||
validateResponse(buybackTransferResponse, loanID);
|
||||
|
||||
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
|
||||
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02",
|
||||
"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")),
|
||||
ExpectedExternalTransferData.expected(BUYBACK, buybackTransferResponse.getResourceExternalId(), "2020-03-02",
|
||||
"2020-03-02", "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")));
|
||||
getAndValidateThereIsNoActiveMapping(saleTransferResponse.getResourceExternalId());
|
||||
getAndValidateThereIsNoActiveMapping(buybackTransferResponse.getResourceExternalId());
|
||||
|
||||
EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalIdError(saleTransferResponse.getResourceExternalId());
|
||||
|
||||
EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalId(buybackTransferResponse.getResourceExternalId());
|
||||
|
||||
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
|
||||
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02",
|
||||
"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")),
|
||||
ExpectedExternalTransferData.expected(BUYBACK, buybackTransferResponse.getResourceExternalId(), "2020-03-02",
|
||||
"2020-03-02", "2020-03-02", 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, buybackTransferResponse.getResourceExternalId(), "2020-03-02",
|
||||
"2020-03-02", "2020-03-02", 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")));
|
||||
|
||||
EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalId(saleTransferResponse.getResourceExternalId());
|
||||
|
||||
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
|
||||
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02",
|
||||
"2020-03-02", 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(BUYBACK, buybackTransferResponse.getResourceExternalId(), "2020-03-02",
|
||||
"2020-03-02", "2020-03-02", 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, buybackTransferResponse.getResourceExternalId(), "2020-03-02",
|
||||
"2020-03-02", "2020-03-02", 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(), "2020-03-02",
|
||||
"2020-03-02", "2020-03-02", 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")));
|
||||
getAndValidateThereIsNoActiveMapping((long) loanID);
|
||||
} finally {
|
||||
cleanUpAndRestoreBusinessDate();
|
||||
}
|
||||
}
|
||||
|
||||
private PostInitiateTransferResponse createSaleTransfer(Integer loanID, String settlementDate) {
|
||||
String transferExternalId = UUID.randomUUID().toString();
|
||||
ownerExternalId = UUID.randomUUID().toString();
|
||||
return createSaleTransfer(loanID, settlementDate, transferExternalId, ownerExternalId, "1.0");
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private PostInitiateTransferResponse createBuybackTransfer(Integer loanID, String settlementDate) {
|
||||
String transferExternalId = UUID.randomUUID().toString();
|
||||
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;
|
||||
}
|
||||
|
||||
private 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 = this.LOAN_TRANSACTION_HELPER.addChargesForLoan(loanID,
|
||||
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), "02 March 2020", amount));
|
||||
assertNotNull(penalty1LoanChargeId);
|
||||
}
|
||||
|
||||
private 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");
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Integer createClient() {
|
||||
final Integer clientID = ClientHelper.createClient(REQUEST_SPEC, RESPONSE_SPEC);
|
||||
Assertions.assertNotNull(clientID);
|
||||
return clientID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Integer createLoanForClient(Integer clientID) {
|
||||
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(), "10 January 2020");
|
||||
|
||||
Assertions.assertNotNull(loanID);
|
||||
|
||||
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(REQUEST_SPEC, RESPONSE_SPEC, loanID);
|
||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||
|
||||
loanStatusHashMap = LOAN_TRANSACTION_HELPER.approveLoan("01 March 2020", loanID);
|
||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||
|
||||
String loanDetails = LOAN_TRANSACTION_HELPER.getLoanDetails(REQUEST_SPEC, RESPONSE_SPEC, loanID);
|
||||
loanStatusHashMap = LOAN_TRANSACTION_HELPER.disburseLoanWithNetDisbursalAmount("02 March 2020", loanID,
|
||||
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||
return loanID;
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
private void addCollaterals(List<HashMap> collaterals, Integer collateralId, BigDecimal quantity) {
|
||||
collaterals.add(collaterals(collateralId, quantity));
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private void getAndValidateExternalAssetOwnerTransferByLoan(Integer loanID, ExpectedExternalTransferData... expectedItems) {
|
||||
PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue());
|
||||
assertEquals(expectedItems.length, retrieveResponse.getNumberOfElements());
|
||||
|
||||
for (ExpectedExternalTransferData expected : expectedItems) {
|
||||
assertNotNull(retrieveResponse.getContent());
|
||||
Optional<ExternalTransferData> first = retrieveResponse.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getAndValidateThereIsNoActiveMapping(Long loanId) {
|
||||
ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanId);
|
||||
assertNull(activeTransfer);
|
||||
}
|
||||
|
||||
private void getAndValidateThereIsNoActiveMapping(String transferExternalId) {
|
||||
ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByTransferExternalId(transferExternalId);
|
||||
assertNull(activeTransfer);
|
||||
}
|
||||
|
||||
private 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());
|
||||
}
|
||||
|
||||
@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 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, detailsExpected,
|
||||
totalOutstanding, totalPrincipalOutstanding, totalInterestOutstanding, totalPenaltyOutstanding, totalFeeOutstanding,
|
||||
totalOverpaid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user