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 <[email protected]>
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;
}