You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2023/06/16 18:58:43 UTC
[fineract] branch develop updated: FINERACT-1926: Fix request validation
This is an automated email from the ASF dual-hosted git repository.
arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new d5686ed45 FINERACT-1926: Fix request validation
d5686ed45 is described below
commit d5686ed45ad202e29b687486c91b34772bd82dc4
Author: Adam Saghy <ad...@gmail.com>
AuthorDate: Fri Jun 16 18:57:59 2023 +0200
FINERACT-1926: Fix request validation
---
.../ExternalAssetOwnersWriteServiceImpl.java | 34 ++++++
.../InitiateExternalAssetOwnerTransferTest.java | 126 ++++++++++++++++++---
2 files changed, 143 insertions(+), 17 deletions(-)
diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java
index 1a026023b..d3db1547e 100644
--- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java
+++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceImpl.java
@@ -89,7 +89,9 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
@Transactional
public CommandProcessingResult buybackLoanByLoanId(JsonCommand command) {
final JsonElement json = fromApiJsonHelper.parse(command.json());
+ validateBuybackRequestBody(command.json());
Long loanId = command.getLoanId();
+ validateLoan(loanId);
LocalDate settlementDate = getSettlementDateFromJson(json);
ExternalId externalId = getTransferExternalIdFromJson(json);
validateSettlementDate(settlementDate);
@@ -99,6 +101,12 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
return buildResponseData(externalAssetOwnerTransfer);
}
+ private void validateLoan(Long loanId) {
+ if (!loanRepository.existsById(loanId)) {
+ throw new LoanNotFoundException(loanId);
+ }
+ }
+
private void validateEffectiveTransferForSale(final ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
List<ExternalAssetOwnerTransfer> effectiveTransfers = externalAssetOwnerTransferRepository
.findEffectiveTransfers(externalAssetOwnerTransfer.getLoanId(), externalAssetOwnerTransfer.getSettlementDate());
@@ -244,6 +252,32 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
}
}
+ private void validateBuybackRequestBody(String apiRequestBodyAsJson) {
+ final Set<String> requestParameters = new HashSet<>(
+ Arrays.asList(ExternalTransferRequestParameters.SETTLEMENT_DATE, ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID,
+ ExternalTransferRequestParameters.DATEFORMAT, ExternalTransferRequestParameters.LOCALE));
+ final Type typeOfMap = new TypeToken<Map<String, Object>>() {
+
+ }.getType();
+ fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, apiRequestBodyAsJson, requestParameters);
+
+ final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+ final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loantransfer");
+ final JsonElement json = fromApiJsonHelper.parse(apiRequestBodyAsJson);
+
+ String transferExternalId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, json);
+ baseDataValidator.reset().parameter(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID).value(transferExternalId).ignoreIfNull()
+ .notExceedingLengthOf(100);
+
+ LocalDate settlementDate = fromApiJsonHelper.extractLocalDateNamed(ExternalTransferRequestParameters.SETTLEMENT_DATE, json);
+ baseDataValidator.reset().parameter(ExternalTransferRequestParameters.SETTLEMENT_DATE).value(settlementDate).notNull();
+
+ if (!dataValidationErrors.isEmpty()) {
+ throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
+ dataValidationErrors);
+ }
+ }
+
private LocalDate getSettlementDateFromJson(JsonElement json) {
String dateFormat = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.DATEFORMAT, json);
String locale = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.LOCALE, json);
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
index 45d3fcb45..c662a73c0 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/InitiateExternalAssetOwnerTransferTest.java
@@ -146,7 +146,7 @@ public class InitiateExternalAssetOwnerTransferTest {
Integer loanID = createLoanForClient(clientID);
addPenaltyForLoan(loanID, "10");
- PostInitiateTransferResponse saleTransferResponse = createExternalAssetOwnerTransfer(loanID, "sale", "2020-03-02");
+ PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02");
validateResponse(saleTransferResponse, loanID);
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02",
@@ -184,7 +184,7 @@ public class InitiateExternalAssetOwnerTransferTest {
ExpectedJournalEntryData.expected((long) TRANSFER_ACCOUNT.getAccountID(), (long) JournalEntryType.CREDIT.getValue(),
BigDecimal.valueOf(15767.420000), expectedDate, expectedDate));
- PostInitiateTransferResponse buybackTransferResponse = createExternalAssetOwnerTransfer(loanID, "buyback", "2020-03-03");
+ PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03");
validateResponse(buybackTransferResponse, loanID);
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02",
@@ -278,10 +278,10 @@ public class InitiateExternalAssetOwnerTransferTest {
Integer clientID = createClient();
Integer loanID = createLoanForClient(clientID);
- createExternalAssetOwnerTransfer(loanID, "sale", "2020-03-02");
+ createSaleTransfer(loanID, "2020-03-02");
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
- () -> createExternalAssetOwnerTransfer(loanID, "sale", "2020-03-02"));
+ () -> createSaleTransfer(loanID, "2020-03-02"));
assertTrue(exception.getMessage().contains("External asset owner transfer is already in PENDING state for this loan"));
} finally {
cleanUpAndRestoreBusinessDate();
@@ -302,7 +302,7 @@ public class InitiateExternalAssetOwnerTransferTest {
LOAN_TRANSACTION_HELPER.makeRepayment("04 March 2020", 16000.0f, loanID);
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
- () -> createExternalAssetOwnerTransfer(loanID, "sale", "2020-03-02"));
+ () -> createSaleTransfer(loanID, "2020-03-02"));
assertTrue(exception.getMessage().contains("Loan is not in active status"));
} finally {
cleanUpAndRestoreBusinessDate();
@@ -318,9 +318,9 @@ public class InitiateExternalAssetOwnerTransferTest {
Integer clientID = createClient();
Integer loanID = createLoanForClient(clientID);
- PostInitiateTransferResponse saleTransferResponse = createExternalAssetOwnerTransfer(loanID, "sale", "2020-03-02");
+ PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02");
validateResponse(saleTransferResponse, loanID);
- PostInitiateTransferResponse buybackTransferResponse = createExternalAssetOwnerTransfer(loanID, "buyback", "2020-03-02");
+ PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-02");
validateResponse(buybackTransferResponse, loanID);
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
@@ -369,8 +369,8 @@ public class InitiateExternalAssetOwnerTransferTest {
Integer clientID = createClient();
Integer loanID = createLoanForClient(clientID);
- PostInitiateTransferResponse saleTransferResponse = createExternalAssetOwnerTransfer(loanID, "sale", "2020-03-04");
- PostInitiateTransferResponse buybackTransferResponse = createExternalAssetOwnerTransfer(loanID, "buyback", "2020-03-04");
+ PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-04");
+ PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-04");
getAndValidateExternalAssetOwnerTransferByLoan(loanID,
ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-04", "2020-03-02",
@@ -383,11 +383,11 @@ public class InitiateExternalAssetOwnerTransferTest {
new BigDecimal("0.000000")));
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
- () -> createExternalAssetOwnerTransfer(loanID, "sale", "2020-03-04"));
+ () -> createSaleTransfer(loanID, "2020-03-04"));
assertTrue(exception.getMessage().contains("This loan cannot be sold, there is already an in progress transfer"));
CallFailedRuntimeException exception2 = assertThrows(CallFailedRuntimeException.class,
- () -> createExternalAssetOwnerTransfer(loanID, "buyback", "2020-03-04"));
+ () -> createBuybackTransfer(loanID, "2020-03-04"));
assertTrue(exception2.getMessage()
.contains("This loan cannot be bought back, external asset owner buyback transfer is already in progress"));
} finally {
@@ -395,19 +395,111 @@ public class InitiateExternalAssetOwnerTransferTest {
}
}
+ @Test
+ public void buybackExceptionHandling() {
+ try {
+ GlobalConfigurationHelper.manageConfigurations(REQUEST_SPEC, RESPONSE_SPEC,
+ GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true);
+ setInitialBusinessDate("2020-03-02");
+
+ CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> createBuybackTransfer(1, null));
+ assertTrue(exception.getMessage().contains("The parameter `settlementDate` is mandatory."));
+
+ CallFailedRuntimeException exception2 = assertThrows(CallFailedRuntimeException.class,
+ () -> createBuybackTransfer(1, "1970-01-01"));
+ assertTrue(exception2.getMessage().contains("Settlement date cannot be in the past"));
+
+ CallFailedRuntimeException exception3 = assertThrows(CallFailedRuntimeException.class, () -> {
+ Integer clientID = createClient();
+ Integer loanID = createLoanForClient(clientID);
+ createSaleTransfer(loanID, "2020-03-03");
+ createBuybackTransfer(loanID, "2020-03-02");
+ });
+ assertTrue(exception3.getMessage().contains(
+ "This loan cannot be bought back, settlement date is earlier than effective transfer settlement date: 2020-03-03"));
+
+ CallFailedRuntimeException exception4 = assertThrows(CallFailedRuntimeException.class, () -> {
+ Integer clientID = createClient();
+ Integer loanID = createLoanForClient(clientID);
+ createBuybackTransfer(loanID, "2020-03-03");
+ });
+ assertTrue(exception4.getMessage().contains("This loan cannot be bought back, it is not owned by an external asset owner"));
+
+ CallFailedRuntimeException exception5 = assertThrows(CallFailedRuntimeException.class,
+ () -> createBuybackTransfer(-1, "2020-03-03"));
+ assertTrue(exception5.getMessage().contains("Loan with identifier -1 does not exist"));
+ } finally {
+ cleanUpAndRestoreBusinessDate();
+ }
+ }
+
+ @Test
+ public void saleExceptionHandling() {
+ try {
+ GlobalConfigurationHelper.manageConfigurations(REQUEST_SPEC, RESPONSE_SPEC,
+ GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true);
+ setInitialBusinessDate("2020-03-02");
+ Integer clientID = createClient();
+ Integer loanID = createLoanForClient(clientID);
+
+ CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> createSaleTransfer(loanID, null));
+ assertTrue(exception.getMessage().contains("The parameter `settlementDate` is mandatory."));
+
+ CallFailedRuntimeException exception2 = assertThrows(CallFailedRuntimeException.class,
+ () -> createSaleTransfer(loanID, "2020-03-02", UUID.randomUUID().toString(), null, "1.0"));
+ assertTrue(exception2.getMessage().contains("The parameter `ownerExternalId` is mandatory."));
+
+ CallFailedRuntimeException exception3 = assertThrows(CallFailedRuntimeException.class,
+ () -> createSaleTransfer(loanID, "2020-03-02", null, UUID.randomUUID().toString(), null));
+ assertTrue(exception3.getMessage().contains("The parameter `purchasePriceRatio` is mandatory."));
+
+ CallFailedRuntimeException exception4 = assertThrows(CallFailedRuntimeException.class,
+ () -> createSaleTransfer(loanID, "1970-01-01"));
+ assertTrue(exception4.getMessage().contains("Settlement date cannot be in the past"));
+
+ CallFailedRuntimeException exception5 = assertThrows(CallFailedRuntimeException.class, () -> {
+ createSaleTransfer(loanID, "2020-03-03");
+ createBuybackTransfer(loanID, "2020-03-04");
+ createSaleTransfer(loanID, "2020-03-05");
+ });
+ assertTrue(exception5.getMessage().contains("This loan cannot be sold, there is already an in progress transfer"));
+ CallFailedRuntimeException exception6 = assertThrows(CallFailedRuntimeException.class, () -> {
+ Integer loanID2 = createLoanForClient(clientID);
+ createSaleTransfer(loanID2, "2020-03-03");
+ updateBusinessDateAndExecuteCOBJob("2020-03-04");
+ createSaleTransfer(loanID2, "2020-03-05");
+ });
+ assertTrue(exception6.getMessage().contains("This loan cannot be sold, because it is owned by an external asset owner"));
+ } finally {
+ cleanUpAndRestoreBusinessDate();
+ }
+ }
+
private void updateBusinessDateAndExecuteCOBJob(String date) {
BusinessDateHelper.updateBusinessDate(REQUEST_SPEC, RESPONSE_SPEC, BUSINESS_DATE, LocalDate.parse(date));
SCHEDULER_JOB_HELPER.executeAndAwaitJob("Loan COB");
}
- private PostInitiateTransferResponse createExternalAssetOwnerTransfer(Integer loanID, String command, String settlementDate) {
+ private PostInitiateTransferResponse createSaleTransfer(Integer loanID, String settlementDate) {
String transferExternalId = UUID.randomUUID().toString();
- if (command.equals("sale")) {
- ownerExternalId = UUID.randomUUID().toString();
- }
- PostInitiateTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), command,
+ 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).ownerExternalId(ownerExternalId).purchasePriceRatio("1.0"));
+ .transferExternalId(transferExternalId));
assertEquals(transferExternalId, saleResponse.getResourceExternalId());
return saleResponse;
}