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 8ee6d264f..a56fca359 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 @@ -78,10 +78,14 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW @Override @Transactional public CommandProcessingResult saleLoanByLoanId(JsonCommand command) { + final JsonElement json = fromApiJsonHelper.parse(command.json()); + validateSaleRequestBody(command.json()); + ExternalId externalId = getTransferExternalIdFromJson(json); + validateExternalId(externalId); Long loanId = command.getLoanId(); LoanIdAndExternalIdAndStatus loanIdAndExternalIdAndStatus = fetchLoanDetails(loanId); validateLoanStatus(loanIdAndExternalIdAndStatus); - ExternalAssetOwnerTransfer externalAssetOwnerTransfer = createSaleTransfer(loanId, command.json(), + ExternalAssetOwnerTransfer externalAssetOwnerTransfer = createSaleTransfer(loanId, json, loanIdAndExternalIdAndStatus.getExternalId()); validateSale(externalAssetOwnerTransfer); externalAssetOwnerTransferRepository.saveAndFlush(externalAssetOwnerTransfer); @@ -98,12 +102,22 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW LocalDate settlementDate = getSettlementDateFromJson(json); ExternalId externalId = getTransferExternalIdFromJson(json); validateSettlementDate(settlementDate); + validateExternalId(externalId); ExternalAssetOwnerTransfer effectiveTransfer = fetchAndValidateEffectiveTransferForBuyback(loanId, settlementDate); ExternalAssetOwnerTransfer externalAssetOwnerTransfer = createBuybackTransfer(effectiveTransfer, settlementDate, externalId); externalAssetOwnerTransferRepository.saveAndFlush(externalAssetOwnerTransfer); return buildResponseData(externalAssetOwnerTransfer); } + private void validateExternalId(ExternalId externalId) { + boolean alreadyExists = externalAssetOwnerTransferRepository + .exists((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("externalId"), externalId)); + if (alreadyExists) { + throw new ExternalAssetOwnerInitiateTransferException( + String.format("Already existing an asset transfer with the provided transfer external id: %s", externalId.getValue())); + } + } + private void validateLoan(Long loanId) { if (!loanRepository.existsById(loanId)) { throw new LoanNotFoundException(loanId); @@ -247,11 +261,9 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW } } - private ExternalAssetOwnerTransfer createSaleTransfer(Long loanId, String apiRequestBodyAsJson, ExternalId externalLoanId) { + private ExternalAssetOwnerTransfer createSaleTransfer(Long loanId, JsonElement json, ExternalId externalLoanId) { ExternalAssetOwnerTransfer externalAssetOwnerTransfer = new ExternalAssetOwnerTransfer(); LocalDate effectiveFrom = ThreadLocalContextUtil.getBusinessDate(); - validateSaleRequestBody(apiRequestBodyAsJson); - final JsonElement json = fromApiJsonHelper.parse(apiRequestBodyAsJson); ExternalAssetOwner owner = getOwner(json); externalAssetOwnerTransfer.setOwner(owner); 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 cd5166e28..ca520088e 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 @@ -615,6 +615,16 @@ public class InitiateExternalAssetOwnerTransferTest { CallFailedRuntimeException exception5 = assertThrows(CallFailedRuntimeException.class, () -> createBuybackTransfer(-1, "2020-03-03")); assertTrue(exception5.getMessage().contains("Loan with identifier -1 does not exist")); + + String externalId = UUID.randomUUID().toString(); + CallFailedRuntimeException exception6 = assertThrows(CallFailedRuntimeException.class, () -> { + Integer clientID = createClient(); + Integer loanID = createLoanForClient(clientID); + createSaleTransfer(loanID, "2020-03-03", externalId, "1", "1.0"); + createBuybackTransfer(loanID, "2020-03-02", externalId); + }); + assertTrue(exception6.getMessage() + .contains(String.format("Already existing an asset transfer with the provided transfer external id: %s", externalId))); } finally { cleanUpAndRestoreBusinessDate(); } @@ -657,6 +667,14 @@ public class InitiateExternalAssetOwnerTransferTest { createSaleTransfer(loanID2, "2020-03-05"); }); assertTrue(exception6.getMessage().contains("This loan cannot be sold, because it is owned by an external asset owner")); + String externalId = UUID.randomUUID().toString(); + CallFailedRuntimeException exception7 = assertThrows(CallFailedRuntimeException.class, () -> { + Integer loanID2 = createLoanForClient(clientID); + createSaleTransfer(loanID2, "2020-03-05", externalId, "1", "1.0"); + createSaleTransfer(loanID2, "2020-03-05", externalId, "1", "1.0"); + }); + assertTrue(exception7.getMessage() + .contains(String.format("Already existing an asset transfer with the provided transfer external id: %s", externalId))); } finally { cleanUpAndRestoreBusinessDate(); } @@ -684,6 +702,10 @@ public class InitiateExternalAssetOwnerTransferTest { private PostInitiateTransferResponse createBuybackTransfer(Integer loanID, String settlementDate) { String transferExternalId = UUID.randomUUID().toString(); + return createBuybackTransfer(loanID, settlementDate, transferExternalId); + } + + private 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));