diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java index ba88693077f..e9f91a9197d 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java @@ -39,7 +39,7 @@ import org.apache.fineract.avro.loan.v1.LoanTransactionDataV1; import org.apache.fineract.avro.workingcapitalloan.v1.WorkingCapitalLoanTransactionDataV1; import org.apache.fineract.client.feign.FineractFeignClient; -import org.apache.fineract.client.models.ExternalTransferData; +import org.apache.fineract.client.models.ExternalTransferResponse; import org.apache.fineract.client.models.GetClientsClientIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdDelinquencyPausePeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; @@ -47,7 +47,7 @@ import org.apache.fineract.client.models.GetWorkingCapitalLoanTransactionIdResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoansLoanIdResponse; import org.apache.fineract.client.models.GlobalConfigurationPropertyData; -import org.apache.fineract.client.models.PageExternalTransferData; +import org.apache.fineract.client.models.PageExternalTransferResponse; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.PostLoansLoanIdResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; @@ -211,8 +211,10 @@ private void loanAccountDataV1Check(Class eventClaz Integer actualNoTermExpected = body.getActualNoTerm(); assertThat(idActual).isEqualTo(idExpected); - assertThat(statusIdActual).isEqualTo(statusIdExpected); - assertThat(statusCodeActual).isEqualTo(statusCodeExpected); + if (!LoanBalanceChangedEvent.class.equals(eventClazz)) { + assertThat(statusIdActual).isEqualTo(statusIdExpected); + assertThat(statusCodeActual).isEqualTo(statusCodeExpected); + } assertThat(clientIdActual).isEqualTo(clientIdExpected); assertThat(areBigDecimalValuesEqual(principalDisbursedActual, principalDisbursedExpected)).isTrue(); assertThat(actualDisbursementDateActual).isEqualTo(actualDisbursementDateExpected); @@ -399,11 +401,11 @@ public EventAssertion.EventAssertionBuilder transactionEv public void loanOwnershipTransferBusinessEventCheck(Long loanId, Long transferId) { waitForTransactionCommit(); - PageExternalTransferData response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); - List content = response.getContent(); + PageExternalTransferResponse response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); + List content = response.getContent(); - ExternalTransferData filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())).reduce((first, second) -> second) - .orElseThrow(() -> new IllegalStateException("No element found")); + ExternalTransferResponse filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())) + .reduce((first, second) -> second).orElseThrow(() -> new IllegalStateException("No element found")); BigDecimal totalOutstandingBalanceAmountExpected = zeroConversion(filtered.getDetails().getTotalOutstanding()); BigDecimal outstandingPrincipalPortionExpected = zeroConversion(filtered.getDetails().getTotalPrincipalOutstanding()); @@ -430,11 +432,11 @@ public void loanOwnershipTransferBusinessEventCheck(Long loanId, Long transferId public void loanOwnershipTransferBusinessEventWithStatusCheck(Long loanId, Long transferId, String transferStatus, String transferStatusReason) { - PageExternalTransferData response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); - List content = response.getContent(); + PageExternalTransferResponse response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); + List content = response.getContent(); - ExternalTransferData filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())).reduce((first, second) -> second) - .orElseThrow(() -> new IllegalStateException("No element found")); + ExternalTransferResponse filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())) + .reduce((first, second) -> second).orElseThrow(() -> new IllegalStateException("No element found")); BigDecimal totalOutstandingBalanceAmountExpected = filtered.getDetails() == null ? null : zeroConversion(filtered.getDetails().getTotalOutstanding()); @@ -474,15 +476,15 @@ public void loanOwnershipTransferBusinessEventWithStatusCheck(Long loanId, Long .isEqualTo(transferStatusReasonExpected); } - public void loanOwnershipTransferBusinessEventWithTypeCheck(Long loanId, ExternalTransferData transferData, String transferType, + public void loanOwnershipTransferBusinessEventWithTypeCheck(Long loanId, ExternalTransferResponse transferData, String transferType, String previousAssetOwner) { - PageExternalTransferData response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); - List content = response.getContent(); + PageExternalTransferResponse response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); + List content = response.getContent(); Long transferId = transferData.getTransferId(); String assetOwner = transferData.getOwner() == null ? null : transferData.getOwner().getExternalId(); - ExternalTransferData filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())).reduce((first, second) -> second) - .orElseThrow(() -> new IllegalStateException("No element found")); + ExternalTransferResponse filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())) + .reduce((first, second) -> second).orElseThrow(() -> new IllegalStateException("No element found")); BigDecimal totalOutstandingBalanceAmountExpected = filtered.getDetails() == null ? null : zeroConversion(filtered.getDetails().getTotalOutstanding()); @@ -517,11 +519,11 @@ public void loanOwnershipTransferBusinessEventWithTypeCheck(Long loanId, Externa public void loanAccountSnapshotBusinessEventCheck(Long loanId, Long transferId) { waitForTransactionCommit(); - PageExternalTransferData response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); - List content = response.getContent(); + PageExternalTransferResponse response = ok(() -> fineractClient.externalAssetOwners().getTransfers(Map.of("loanId", loanId))); + List content = response.getContent(); - ExternalTransferData filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())).reduce((first, second) -> second) - .orElseThrow(() -> new IllegalStateException("No element found")); + ExternalTransferResponse filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())) + .reduce((first, second) -> second).orElseThrow(() -> new IllegalStateException("No element found")); BigDecimal totalOutstandingBalanceAmountExpected = zeroConversion(filtered.getDetails().getTotalOutstanding()); BigDecimal outstandingInterestPortionExpected = zeroConversion(filtered.getDetails().getTotalInterestOutstanding()); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanAdjustTransactionBusinessEvent.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanAdjustTransactionBusinessEvent.java index 70841581cff..225affe1e66 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanAdjustTransactionBusinessEvent.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanAdjustTransactionBusinessEvent.java @@ -31,7 +31,7 @@ public Class getDataClass() { @Override public Function getIdExtractor() { - return loanTransactionAdjustmentDataV1 -> (Long) loanTransactionAdjustmentDataV1.getTransactionToAdjust().getId(); + return loanTransactionAdjustmentDataV1 -> loanTransactionAdjustmentDataV1.getTransactionToAdjust().getId(); } @Override diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java index ce72cb67c0b..d52e50b00a0 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java @@ -38,20 +38,20 @@ import org.apache.fineract.client.feign.services.ExternalAssetOwnersApi; import org.apache.fineract.client.feign.services.LoanProductsApi; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; -import org.apache.fineract.client.models.ExternalAssetOwnerRequest; -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.ExternalAssetOwnerCreateRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerCreateResponse; +import org.apache.fineract.client.models.ExternalAssetOwnerSaleRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.client.models.ExternalOwnerJournalEntryResponse; +import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryResponse; import org.apache.fineract.client.models.ExternalTransferLoanProductAttributesData; import org.apache.fineract.client.models.ExternalTransferOwnerData; +import org.apache.fineract.client.models.ExternalTransferResponse; import org.apache.fineract.client.models.GetLoanProductsResponse; import org.apache.fineract.client.models.JournalEntryData; -import org.apache.fineract.client.models.PageExternalTransferData; import org.apache.fineract.client.models.PageExternalTransferLoanProductAttributesData; +import org.apache.fineract.client.models.PageExternalTransferResponse; import org.apache.fineract.client.models.PostExternalAssetOwnerLoanProductAttributeRequest; -import org.apache.fineract.client.models.PostExternalAssetOwnerRequest; -import org.apache.fineract.client.models.PostExternalAssetOwnerResponse; -import org.apache.fineract.client.models.PostInitiateTransferResponse; import org.apache.fineract.client.models.PostLoansResponse; import org.apache.fineract.client.models.PutExternalAssetOwnerLoanProductAttributeRequest; import org.apache.fineract.test.data.AssetExternalizationErrorMessage; @@ -126,15 +126,15 @@ private void createAssetExternalizationRequestByLoanId(DataTable table, String t PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - ExternalAssetOwnerRequest request = new ExternalAssetOwnerRequest(); + ExternalAssetOwnerSaleRequest request = new ExternalAssetOwnerSaleRequest(); if (transferData.get(0).equals(TRANSACTION_TYPE_BUYBACK)) { request.settlementDate(transferData.get(1))// .transferExternalId(transferExternalId)// .dateFormat(DATE_FORMAT_ASSET_EXT)// .locale(DEFAULT_LOCALE);// - PostInitiateTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, - Map.of(COMMAND, transferData.get(0))); + ExternalAssetOwnerTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, + transferData.get(0)); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE, response); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE, response.getResourceExternalId()); @@ -159,8 +159,8 @@ private void createAssetExternalizationRequestByLoanId(DataTable table, String t .dateFormat(DATE_FORMAT_ASSET_EXT)// .locale(DEFAULT_LOCALE);// - PostInitiateTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, - Map.of(COMMAND, transferData.get(0))); + ExternalAssetOwnerTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, + transferData.get(0)); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE, response); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE, response.getResourceExternalId()); @@ -181,15 +181,15 @@ public void createAssetExternalizationBuybackRequestOwnerNullByLoanIdSystemGener PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - ExternalAssetOwnerRequest request = new ExternalAssetOwnerRequest()// + ExternalAssetOwnerSaleRequest request = new ExternalAssetOwnerSaleRequest()// .settlementDate(settlementDate)// .ownerExternalId(null)// .transferExternalId(testContext().get(TestContextKey.ASSET_EXTERNALIZATION_TRANSFER_EXTERNAL_ID_FROM_RESPONSE))// .dateFormat(DATE_FORMAT_ASSET_EXT)// .locale(DEFAULT_LOCALE);// - PostInitiateTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, - Map.of(COMMAND, TRANSACTION_TYPE_BUYBACK)); + ExternalAssetOwnerTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, + TRANSACTION_TYPE_BUYBACK); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE, response); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE, response.getResourceExternalId()); @@ -219,15 +219,15 @@ private void createAssetExternalizationRequestByLoanExternalId(DataTable table, PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); String loanExternalId = loanResponse.getResourceExternalId(); - ExternalAssetOwnerRequest request = new ExternalAssetOwnerRequest(); + ExternalAssetOwnerSaleRequest request = new ExternalAssetOwnerSaleRequest(); if (transferData.get(0).equals(TRANSACTION_TYPE_BUYBACK)) { request.settlementDate(transferData.get(1))// .transferExternalId(transferExternalId)// .dateFormat(DATE_FORMAT_ASSET_EXT)// .locale(DEFAULT_LOCALE);// - PostInitiateTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanExternalId(loanExternalId, request, - Map.of(COMMAND, transferData.get(0))); + ExternalAssetOwnerTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanExternalId(loanExternalId, + request, transferData.get(0)); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE, response); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE, response.getResourceExternalId()); @@ -241,8 +241,8 @@ private void createAssetExternalizationRequestByLoanExternalId(DataTable table, .dateFormat(DATE_FORMAT_ASSET_EXT)// .locale(DEFAULT_LOCALE);// - PostInitiateTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanExternalId(loanExternalId, request, - Map.of(COMMAND, transferData.get(0))); + ExternalAssetOwnerTransferResponse response = externalAssetOwnersApi().transferRequestWithLoanExternalId(loanExternalId, + request, transferData.get(0)); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE, response); testContext().set(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE, response.getResourceExternalId()); @@ -260,7 +260,7 @@ public void checkAssetExternalizationResponse() { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - PostInitiateTransferResponse response = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE); + ExternalAssetOwnerTransferResponse response = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE); Long loanIdActual = response.getSubResourceId(); String transferExternalIdActual = response.getResourceExternalId(); @@ -290,7 +290,7 @@ public void checkAssetExternalizationDetailsByLoanId(int numberOfElements, DataT PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - PageExternalTransferData response = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); + PageExternalTransferResponse response = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); checkExternalAssetDetails(loanId, null, response, numberOfElements, table); } @@ -300,7 +300,7 @@ public void checkAssetExternalizationDetailsByLoanExternalId(int numberOfElement PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); String loanExternalId = loanResponse.getResourceExternalId(); - PageExternalTransferData response = externalAssetOwnersApi().getTransfers(Map.of("loanExternalId", loanExternalId)); + PageExternalTransferResponse response = externalAssetOwnersApi().getTransfers(Map.of("loanExternalId", loanExternalId)); checkExternalAssetDetails(null, loanExternalId, response, numberOfElements, table); } @@ -308,7 +308,7 @@ public void checkAssetExternalizationDetailsByLoanExternalId(int numberOfElement public void checkAssetExternalizationDetailsByTransferExternalId(int numberOfElements, DataTable table) throws IOException { String transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); - PageExternalTransferData response = externalAssetOwnersApi().getTransfers(Map.of("transferExternalId", transferExternalId), + PageExternalTransferResponse response = externalAssetOwnersApi().getTransfers(Map.of("transferExternalId", transferExternalId), Map.of()); checkExternalAssetDetails(null, null, response, numberOfElements, table); } @@ -318,11 +318,11 @@ public void checkGeneratedTransferExternalId() throws IOException { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - PostInitiateTransferResponse assetExtResponse = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE); + ExternalAssetOwnerTransferResponse assetExtResponse = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE); String transferExternalIdExpected = assetExtResponse.getResourceExternalId(); - PageExternalTransferData response = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); - List content = response.getContent(); + PageExternalTransferResponse response = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); + List content = response.getContent(); content.forEach(e -> { assertThat(e.getTransferExternalId()).as(ErrorMessageHelper @@ -331,10 +331,10 @@ public void checkGeneratedTransferExternalId() throws IOException { }); } - private void checkExternalAssetDetails(Long loanId, String loanExternalId, PageExternalTransferData response, int numberOfElements, + private void checkExternalAssetDetails(Long loanId, String loanExternalId, PageExternalTransferResponse response, int numberOfElements, DataTable table) { Integer numberOfElementsActual = response.getNumberOfElements(); - List content = response.getContent(); + List content = response.getContent(); String transferExternalId; String ownerExternalIdStored = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID); @@ -352,7 +352,7 @@ private void checkExternalAssetDetails(Long loanId, String loanExternalId, PageE // in case transfer has no previous intermediarySale transfer if (intermediarySaleAssetOwner == null) { if (transactionType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK) - && status.equals(ExternalTransferData.StatusEnum.BUYBACK.getValue())) { + && status.equals(ExternalTransferResponse.StatusEnum.BUYBACK.getValue())) { previousAssetOwner = ownerExternalIdStored; ownerExternalId = ownerExternalIdStored; transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); @@ -363,21 +363,21 @@ private void checkExternalAssetDetails(Long loanId, String loanExternalId, PageE } } else { // in case transfer has previous intermediarySale or owner-to-owner transfer if (transactionType.equalsIgnoreCase(TRANSACTION_TYPE_SALE) - && (status.equals(ExternalTransferData.StatusEnum.ACTIVE.getValue()) - || status.equals(ExternalTransferData.StatusEnum.PENDING.getValue()))) { + && (status.equals(ExternalTransferResponse.StatusEnum.ACTIVE.getValue()) + || status.equals(ExternalTransferResponse.StatusEnum.PENDING.getValue()))) { ownerExternalId = ownerExternalIdStored; previousAssetOwner = intermediarySaleAssetOwner; transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); } else if (transactionType.equalsIgnoreCase(TRANSACTION_TYPE_SALE) - && (status.equals(ExternalTransferData.StatusEnum.DECLINED.getValue()) - || status.equals(ExternalTransferData.StatusEnum.CANCELLED.getValue()))) { + && (status.equals(ExternalTransferResponse.StatusEnum.DECLINED.getValue()) + || status.equals(ExternalTransferResponse.StatusEnum.CANCELLED.getValue()))) { // DECLINED and CANCELLED records have previousOwner = null in the API response ownerExternalId = ownerExternalIdStored; previousAssetOwner = null; transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); } else if (transactionType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK) - && (status.equals(ExternalTransferData.StatusEnum.BUYBACK.getValue()) - || status.equals(ExternalTransferData.StatusEnum.BUYBACK_INTERMEDIATE.getValue()))) { + && (status.equals(ExternalTransferResponse.StatusEnum.BUYBACK.getValue()) + || status.equals(ExternalTransferResponse.StatusEnum.BUYBACK_INTERMEDIATE.getValue()))) { ownerExternalId = ownerExternalIdStored; previousAssetOwner = ownerExternalIdStored; transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); @@ -461,20 +461,20 @@ public void buybackDateError(int errorCodeExpected, DataTable table) throws IOEx String transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); - PageExternalTransferData transfers = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); + PageExternalTransferResponse transfers = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); String settlementDateOriginal = FORMATTER.format(transfers.getContent().get(0).getSettlementDate()); String errorMessageExpected = String.format( "This loan cannot be bought back, settlement date is earlier than effective transfer settlement date: %s", settlementDateOriginal); - ExternalAssetOwnerRequest request = new ExternalAssetOwnerRequest()// + ExternalAssetOwnerSaleRequest request = new ExternalAssetOwnerSaleRequest()// .settlementDate(transferData.get(1))// .transferExternalId(transferExternalId)// .dateFormat(DATE_FORMAT_ASSET_EXT)// .locale(DEFAULT_LOCALE);// CallFailedRuntimeException exception = fail( - () -> externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, Map.of(COMMAND, transferData.get(0)))); + () -> externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, transferData.get(0))); int errorCodeActual = exception.getStatus(); String errorMessageActual = exception.getDeveloperMessage(); @@ -494,7 +494,7 @@ public void transactionError(int errorCodeExpected, String errorMessageType, Dat PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - ExternalAssetOwnerRequest request = new ExternalAssetOwnerRequest(); + ExternalAssetOwnerSaleRequest request = new ExternalAssetOwnerSaleRequest(); if (transferData.get(0).equals(TRANSACTION_TYPE_BUYBACK)) { request.settlementDate(transferData.get(1))// .transferExternalId(null)// @@ -519,7 +519,7 @@ public void transactionError(int errorCodeExpected, String errorMessageType, Dat String errorMessageExpected = errorMsgType.getValue(); CallFailedRuntimeException exception = fail( - () -> externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, Map.of(COMMAND, transferData.get(0)))); + () -> externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, transferData.get(0))); int errorCodeActual = exception.getStatus(); String errorMessageActual = exception.getDeveloperMessage(); @@ -544,7 +544,7 @@ public void transactionErrorSalesOwnerNull(int errorCodeExpected, String errorMe PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - ExternalAssetOwnerRequest request = new ExternalAssetOwnerRequest()// + ExternalAssetOwnerSaleRequest request = new ExternalAssetOwnerSaleRequest()// .settlementDate(transferData.get(0))// .ownerExternalId(null)// .transferExternalId(null)// @@ -556,7 +556,7 @@ public void transactionErrorSalesOwnerNull(int errorCodeExpected, String errorMe String errorMessageExpected = errorMsgType.getValue(); CallFailedRuntimeException exception = fail( - () -> externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, Map.of(COMMAND, TRANSACTION_TYPE_SALE))); + () -> externalAssetOwnersApi().transferRequestWithLoanId(loanId, request, TRANSACTION_TYPE_SALE)); int errorCodeActual = exception.getStatus(); String errorMessageActual = exception.getDeveloperMessage(); @@ -580,7 +580,7 @@ public void checkJournalEntriesTransaction(String status, DataTable table) throw Long lastTransferIdByStatus = getLastTransferIdByStatus(loanId, status); - ExternalOwnerTransferJournalEntryData journalEntriesOfTransfer = externalAssetOwnersApi() + ExternalOwnerTransferJournalEntryResponse journalEntriesOfTransfer = externalAssetOwnersApi() .getJournalEntriesOfTransfer(lastTransferIdByStatus, Map.of()); List content = journalEntriesOfTransfer.getJournalEntryData().getContent(); @@ -616,10 +616,10 @@ public void checkJournalEntriesTransaction(String status, DataTable table) throw } private Long getLastTransferIdByStatus(Long loanId, String status) throws IOException { - PageExternalTransferData transfersResponse = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); - List content = transfersResponse.getContent(); + PageExternalTransferResponse transfersResponse = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); + List content = transfersResponse.getContent(); - ExternalTransferData result = content.stream().filter(t -> status.equals(t.getStatus().getValue())) + ExternalTransferResponse result = content.stream().filter(t -> status.equals(t.getStatus().getValue())) .reduce((first, second) -> second) .orElseThrow(() -> new IllegalStateException(String.format("No Journal entry found with status: %s", status))); @@ -627,15 +627,15 @@ private Long getLastTransferIdByStatus(Long loanId, String status) throws IOExce } private Long getLastTransferId(Long loanId) throws IOException { - PageExternalTransferData transfersResponse = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); - List content = transfersResponse.getContent(); - ExternalTransferData result = content.stream().reduce((first, second) -> second) + PageExternalTransferResponse transfersResponse = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); + List content = transfersResponse.getContent(); + ExternalTransferResponse result = content.stream().reduce((first, second) -> second) .orElseThrow(() -> new IllegalStateException("transfersResponse.getContent() is empty")); return result.getTransferId(); } - private ExternalTransferData getLastTransferByTransferType(Long loanId, String transferType) throws IOException { + private ExternalTransferResponse getLastTransferByTransferType(Long loanId, String transferType) throws IOException { String transferExternalId; if (transferType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK)) { transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); @@ -648,8 +648,8 @@ private ExternalTransferData getLastTransferByTransferType(Long loanId, String t transferExternalId = null; } - PageExternalTransferData transfersResponse = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); - List content = transfersResponse.getContent(); + PageExternalTransferResponse transfersResponse = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); + List content = transfersResponse.getContent(); return content.stream().filter(bizEvent -> bizEvent.getTransferExternalId().equals(transferExternalId)).toList().stream() .reduce((first, second) -> second).orElseThrow(() -> new IllegalStateException("transfersResponse.getContent() is empty")); } @@ -658,7 +658,8 @@ private ExternalTransferData getLastTransferByTransferType(Long loanId, String t public void checkJournalEntriesOwner(DataTable table) throws IOException { String ownerExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID); - ExternalOwnerJournalEntryData journalEntriesOfOwner = externalAssetOwnersApi().getJournalEntriesOfOwner(ownerExternalId, Map.of()); + ExternalOwnerJournalEntryResponse journalEntriesOfOwner = externalAssetOwnersApi().getJournalEntriesOfOwner(ownerExternalId, + Map.of()); List content = journalEntriesOfOwner.getJournalEntryData().getContent(); List> data = table.asLists(); @@ -707,7 +708,7 @@ public void loanOwnershipTransferBusinessEventCheck(String transferStatus, Strin eventCheckHelper.loanOwnershipTransferBusinessEventWithStatusCheck(loanId, transferId, transferStatus, transferStatusReason); } - public String getPreviousAssetOwner(ExternalTransferData transferData, String transferType, boolean isIntermediarySaleTransfer) { + public String getPreviousAssetOwner(ExternalTransferResponse transferData, String transferType, boolean isIntermediarySaleTransfer) { String previousAssetOwner; String intermediarySaleAssetOwner = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_PREVIOUS_OWNER_EXTERNAL_ID); String assetOwner = transferData.getOwner() == null ? null : transferData.getOwner().getExternalId(); @@ -728,7 +729,7 @@ public String getPreviousAssetOwner(ExternalTransferData transferData, String tr public void loanOwnershipTransferBusinessEventCheck(String transferType) throws IOException { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - ExternalTransferData transferData = getLastTransferByTransferType(loanId, transferType); + ExternalTransferResponse transferData = getLastTransferByTransferType(loanId, transferType); String previousAssetOwner = getPreviousAssetOwner(transferData, transferType, false); eventCheckHelper.loanOwnershipTransferBusinessEventWithTypeCheck(loanId, transferData, transferType, previousAssetOwner); @@ -738,7 +739,7 @@ public void loanOwnershipTransferBusinessEventCheck(String transferType) throws public void loanOwnershipTransferBusinessEventCheckBasedOnIntermediarySale(String transferType) throws IOException { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - ExternalTransferData transferData = getLastTransferByTransferType(loanId, transferType); + ExternalTransferResponse transferData = getLastTransferByTransferType(loanId, transferType); String previousAssetOwner = getPreviousAssetOwner(transferData, transferType, true); eventCheckHelper.loanOwnershipTransferBusinessEventWithTypeCheck(loanId, transferData, transferType, previousAssetOwner); @@ -767,7 +768,7 @@ public void checkAssetExternalizationResponse(String type) { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - PostInitiateTransferResponse response = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE); + ExternalAssetOwnerTransferResponse response = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_RESPONSE); Long loanIdActual = response.getSubResourceId(); String transferExternalIdActual = response.getResourceExternalId(); @@ -802,7 +803,7 @@ public void adminTransactionCommandTheWithType(String command, String type) thro String transferExternalId = testContext() .get(TestContextKey.ASSET_EXTERNALIZATION_TRANSFER_EXTERNAL_ID_USER_GENERATED + "_" + type); - externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, Map.of(COMMAND, command)); + externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, command); } @When("Admin send {string} command to the transaction type {string} will throw error") @@ -811,7 +812,7 @@ public void adminTransactionCommandTheWithTypeThrowError(String command, String .get(TestContextKey.ASSET_EXTERNALIZATION_TRANSFER_EXTERNAL_ID_USER_GENERATED + "_" + type); CallFailedRuntimeException exception = fail( - () -> externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, Map.of(COMMAND, command))); + () -> externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, command)); assertThat(exception.getStatus()).as("Expected status code: 403").isEqualTo(403); } @@ -822,14 +823,14 @@ public void checkAssetExternalizationDetailsByLoanIdIgnoreTransactionExternalId( PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); - PageExternalTransferData response = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); + PageExternalTransferResponse response = externalAssetOwnersApi().getTransfers(Map.of("loanId", loanId)); checkExternalAssetDetailsIgnoreTransferExternalId(loanId, null, response, numberOfElements, table); } - private void checkExternalAssetDetailsIgnoreTransferExternalId(Long loanId, String loanExternalId, PageExternalTransferData response, - int numberOfElements, DataTable table) { + private void checkExternalAssetDetailsIgnoreTransferExternalId(Long loanId, String loanExternalId, + PageExternalTransferResponse response, int numberOfElements, DataTable table) { Integer numberOfElementsActual = response.getNumberOfElements(); - List content = response.getContent(); + List content = response.getContent(); String ownerExternalIdStored = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID); @@ -866,14 +867,14 @@ private void checkExternalAssetDetailsIgnoreTransferExternalId(Long loanId, Stri @When("Admin send {string} command on {string} transaction it will throw an error") public void adminSendCommandAndItWillThrowError(String command, String transactionType) throws IOException { String transferExternalId; - if (transactionType.equals(ExternalTransferData.StatusEnum.BUYBACK.getValue())) { + if (transactionType.equals(ExternalTransferResponse.StatusEnum.BUYBACK.getValue())) { transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); } else { transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); } CallFailedRuntimeException exception = fail( - () -> externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, Map.of(COMMAND, command))); + () -> externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, command)); assertThat(exception.getStatus()).as("Expected status code: 403").isEqualTo(403); } @@ -881,13 +882,13 @@ public void adminSendCommandAndItWillThrowError(String command, String transacti @When("Admin send {string} command on {string} transaction") public void adminSendCommand(String command, String transactionType) throws IOException { String transferExternalId; - if (transactionType.equals(ExternalTransferData.StatusEnum.BUYBACK.getValue())) { + if (transactionType.equals(ExternalTransferResponse.StatusEnum.BUYBACK.getValue())) { transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); } else { transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); } - externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, Map.of(COMMAND, command)); + externalAssetOwnersApi().transferRequestWithIdByExternalId(transferExternalId, command); } @When("Admin set external asset owner loan product attribute {string} value {string} for loan product {string}") @@ -935,8 +936,8 @@ public void createExternalAssetOwnerWithUniqueId() { String ownerExternalId = Utils.randomStringGenerator(OWNER_EXTERNAL_ID_PREFIX, 20); testContext().set(TestContextKey.EXTERNAL_ASSET_OWNER_EXTERNAL_ID, ownerExternalId); - PostExternalAssetOwnerRequest request = new PostExternalAssetOwnerRequest().ownerExternalId(ownerExternalId); - PostExternalAssetOwnerResponse response = ok(() -> externalAssetOwnersApi().createExternalAssetOwner(request)); + ExternalAssetOwnerCreateRequest request = new ExternalAssetOwnerCreateRequest().ownerExternalId(ownerExternalId); + ExternalAssetOwnerCreateResponse response = ok(() -> externalAssetOwnersApi().createExternalAssetOwner(request)); testContext().set(TestContextKey.EXTERNAL_ASSET_OWNER_CREATE_RESPONSE, response); log.debug("Created external asset owner with externalId: {}, resourceId: {}", ownerExternalId, response.getResourceId()); @@ -944,7 +945,7 @@ public void createExternalAssetOwnerWithUniqueId() { @Then("External asset owner creation response has a non-null resourceId") public void verifyCreateResponseHasResourceId() { - PostExternalAssetOwnerResponse response = testContext().get(TestContextKey.EXTERNAL_ASSET_OWNER_CREATE_RESPONSE); + ExternalAssetOwnerCreateResponse response = testContext().get(TestContextKey.EXTERNAL_ASSET_OWNER_CREATE_RESPONSE); assertThat(response).as("External asset owner create response should not be null").isNotNull(); assertThat(response.getResourceId()).as("resourceId should not be null").isNotNull(); } @@ -952,7 +953,7 @@ public void verifyCreateResponseHasResourceId() { @Then("External asset owner list contains the created owner") public void verifyOwnerExistsInList() { String ownerExternalId = testContext().get(TestContextKey.EXTERNAL_ASSET_OWNER_EXTERNAL_ID); - PostExternalAssetOwnerResponse createResponse = testContext().get(TestContextKey.EXTERNAL_ASSET_OWNER_CREATE_RESPONSE); + ExternalAssetOwnerCreateResponse createResponse = testContext().get(TestContextKey.EXTERNAL_ASSET_OWNER_CREATE_RESPONSE); List owners = ok(() -> externalAssetOwnersApi().retrieveExternalAssetOwners()); assertThat(owners).as("Owners list should not be empty").isNotEmpty(); @@ -965,7 +966,7 @@ public void verifyOwnerExistsInList() { @When("Admin tries to create an external asset owner with null ownerExternalId then it should fail with {int} status code") public void createExternalAssetOwnerWithNullIdFails(int expectedStatusCode) { - PostExternalAssetOwnerRequest request = new PostExternalAssetOwnerRequest().ownerExternalId(null); + ExternalAssetOwnerCreateRequest request = new ExternalAssetOwnerCreateRequest().ownerExternalId(null); CallFailedRuntimeException exception = fail(() -> externalAssetOwnersApi().createExternalAssetOwner(request)); @@ -978,7 +979,7 @@ public void createExternalAssetOwnerWithNullIdFails(int expectedStatusCode) { public void createExternalAssetOwnerWithDuplicateIdFails(int expectedStatusCode) { String ownerExternalId = testContext().get(TestContextKey.EXTERNAL_ASSET_OWNER_EXTERNAL_ID); - PostExternalAssetOwnerRequest request = new PostExternalAssetOwnerRequest().ownerExternalId(ownerExternalId); + ExternalAssetOwnerCreateRequest request = new ExternalAssetOwnerCreateRequest().ownerExternalId(ownerExternalId); CallFailedRuntimeException exception = fail(() -> externalAssetOwnersApi().createExternalAssetOwner(request)); @@ -990,7 +991,7 @@ public void createExternalAssetOwnerWithDuplicateIdFails(int expectedStatusCode) @When("Admin tries to create an external asset owner with empty JSON body then it should fail with {int} status code") public void createExternalAssetOwnerWithEmptyBodyFails(int expectedStatusCode) { - PostExternalAssetOwnerRequest request = new PostExternalAssetOwnerRequest(); + ExternalAssetOwnerCreateRequest request = new ExternalAssetOwnerCreateRequest(); CallFailedRuntimeException exception = fail(() -> externalAssetOwnersApi().createExternalAssetOwner(request)); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java index 3f966660f18..dfac5a9e9f4 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java @@ -113,7 +113,8 @@ public void makeLoanRepaymentAndCheckPreviousOwner(String repaymentType, String private void makeRepayment(String repaymentType, String transactionDate, double transactionAmount, String transferExternalOwnerId) throws IOException { - eventStore.reset(); + // Keep earlier step events available for later assertions in the same scenario, + // e.g. COB-generated amortization events verified after the repayment step. PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); @@ -137,7 +138,6 @@ private void makeRepayment(String repaymentType, String transactionDate, double @And("Created user makes {string} repayment on {string} with {double} EUR transaction amount") public void makeRepaymentWithGivenUser(String repaymentType, String transactionDate, double transactionAmount) throws IOException { - eventStore.reset(); PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); @@ -167,7 +167,6 @@ public void makeRepaymentWithGivenUser(String repaymentType, String transactionD @And("Customer makes externalID controlled {string} repayment on {string} with {double} EUR transaction amount") public void makeRepaymentByExternalId(String repaymentType, String transactionDate, double transactionAmount) throws IOException { - eventStore.reset(); PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); String resourceExternalId = loanResponse.getResourceExternalId(); @@ -192,7 +191,6 @@ public void makeRepaymentByExternalId(String repaymentType, String transactionDa @And("Created user makes externalID controlled {string} repayment on {string} with {double} EUR transaction amount") public void makeRepaymentWithGivenUserByExternalId(String repaymentType, String transactionDate, double transactionAmount) throws IOException { - eventStore.reset(); PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); String resourceExternalId = loanResponse.getResourceExternalId(); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java index 1e1a12ab595..c53e21e3bf7 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java @@ -21,7 +21,7 @@ import io.cucumber.java.Scenario; import java.io.IOException; import java.lang.reflect.Field; -import java.util.ArrayList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; @@ -124,7 +124,8 @@ private String createFailedComment(Scenario scenario) { Field fieldStepResults = objectScenario.getClass().getDeclaredField("stepResults"); fieldStepResults.setAccessible(true); - ArrayList results = (ArrayList) fieldStepResults.get(objectScenario); + @SuppressWarnings("unchecked") + List results = (List) fieldStepResults.get(objectScenario); for (Result result : results) { if (result.getFailures() != null) { return FAILED_COMMENT + "%n" + result.getFailures(); diff --git a/fineract-investor/dependencies.gradle b/fineract-investor/dependencies.gradle index e590c341c05..1b5147f6863 100644 --- a/fineract-investor/dependencies.gradle +++ b/fineract-investor/dependencies.gradle @@ -29,6 +29,7 @@ dependencies { implementation(project(path: ':fineract-accounting')) implementation(project(path: ':fineract-charge')) implementation(project(path: ':fineract-loan')) + implementation(project(path: ':fineract-command')) implementation('org.apache.avro:avro') implementation( project(path: ':fineract-avro-schemas') diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnerLoanProductAttributesApiResource.java b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnerLoanProductAttributesApiResource.java index 8f4946eecae..e3f9693ddbc 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnerLoanProductAttributesApiResource.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnerLoanProductAttributesApiResource.java @@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; @@ -35,15 +36,18 @@ import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.UriInfo; +import java.util.function.Supplier; import lombok.RequiredArgsConstructor; -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.command.core.CommandDispatcher; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.security.service.PlatformUserRightsContext; +import org.apache.fineract.investor.command.ExternalAssetOwnerLoanProductAttributeCreateCommand; +import org.apache.fineract.investor.command.ExternalAssetOwnerLoanProductAttributeUpdateCommand; import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition; +import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeResponse; import org.apache.fineract.investor.data.ExternalTransferLoanProductAttributesData; +import org.apache.fineract.investor.data.request.PostExternalAssetOwnerLoanProductAttributeRequest; +import org.apache.fineract.investor.data.request.PutExternalAssetOwnerLoanProductAttributeRequest; import org.apache.fineract.investor.service.ExternalAssetOwnerLoanProductAttributesReadService; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; @@ -56,7 +60,7 @@ public class ExternalAssetOwnerLoanProductAttributesApiResource { private final PlatformUserRightsContext platformUserRightsContext; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final CommandDispatcher commandDispatcher; private final ExternalAssetOwnerLoanProductAttributesReadService externalAssetOwnerLoanProductAttributesReadService; @POST @@ -64,15 +68,17 @@ public class ExternalAssetOwnerLoanProductAttributesApiResource { @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Create External Asset Owner Loan Product Attribute", operationId = "createExternalAssetOwnerLoanProductAttribute") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerLoanProductAttributesApiResourceSwagger.PostExternalAssetOwnerLoanProductAttributeRequest.class))) - public CommandProcessingResult postExternalAssetOwnerLoanProductAttribute( + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = PostExternalAssetOwnerLoanProductAttributeRequest.class))) + public ExternalAssetOwnerLoanProductAttributeResponse postExternalAssetOwnerLoanProductAttribute( @PathParam("loanProductId") @Parameter(description = "loanProductId") final Long loanProductId, - @Parameter(hidden = true) final String apiRequestBodyAsJson) { + @Valid final PostExternalAssetOwnerLoanProductAttributeRequest request) { platformUserRightsContext.isAuthenticated(); - final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); - CommandWrapper request = builder.createExternalAssetOwnerLoanProductAttribute(loanProductId).build(); + request.setLoanProductId(loanProductId); + final var command = new ExternalAssetOwnerLoanProductAttributeCreateCommand(); + command.setPayload(request); - return commandsSourceWritePlatformService.logCommandSource(request); + final Supplier response = commandDispatcher.dispatch(command); + return response.get(); } @GET @@ -95,20 +101,23 @@ public Page getExternalAssetOwnerLoan @Path("/{loanProductId}/attributes/{id}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerLoanProductAttributesApiResourceSwagger.PutExternalAssetOwnerLoanProductAttributeRequest.class))) + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = PutExternalAssetOwnerLoanProductAttributeRequest.class))) @Operation(tags = { "External Asset Owner Loan Product Attributes" }, summary = "Update a Loan Product Attribute", operationId = "updateExternalAssetOwnerLoanProductAttribute", description = "Updates a loan product attribute with a given loan product id and attribute id", parameters = { @Parameter(name = "loanProductId", description = "loanProductId"), @Parameter(name = "attributeId", description = "attributeId") }) - public CommandProcessingResult updateLoanProductAttribute( + public ExternalAssetOwnerLoanProductAttributeResponse updateLoanProductAttribute( @PathParam("loanProductId") @Parameter(description = "loanProductId") final Long loanProductId, @PathParam("id") @Parameter(description = "attributeId") final Long attributeId, - @Parameter(hidden = true) final String apiRequestBodyAsJson) { + @Valid final PutExternalAssetOwnerLoanProductAttributeRequest request) { platformUserRightsContext.isAuthenticated(); - final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); - CommandWrapper request = builder.updateExternalAssetOwnerLoanProductAttribute(loanProductId, attributeId).build(); + request.setLoanProductId(loanProductId); + request.setAttributeId(attributeId); + final var command = new ExternalAssetOwnerLoanProductAttributeUpdateCommand(); + command.setPayload(request); - return commandsSourceWritePlatformService.logCommandSource(request); + final Supplier response = commandDispatcher.dispatch(command); + return response.get(); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnerLoanProductAttributesApiResourceSwagger.java b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnerLoanProductAttributesApiResourceSwagger.java deleted file mode 100644 index a0db5f0b7f2..00000000000 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnerLoanProductAttributesApiResourceSwagger.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * 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; - -import io.swagger.v3.oas.annotations.media.Schema; - -@SuppressWarnings({ "MemberName" }) -final class ExternalAssetOwnerLoanProductAttributesApiResourceSwagger { - - private ExternalAssetOwnerLoanProductAttributesApiResourceSwagger() {} - - @Schema(description = "PostExternalAssetOwnerLoanProductAttributeRequest") - public static final class PostExternalAssetOwnerLoanProductAttributeRequest { - - private PostExternalAssetOwnerLoanProductAttributeRequest() {} - - @Schema(example = "SETTLEMENT_MODEL") - public String attributeKey; - - @Schema(example = "DELAYED_SETTLEMENT") - public String attributeValue; - } - - @Schema(description = "PutExternalAssetOwnerLoanProductAttributeRequest") - public static final class PutExternalAssetOwnerLoanProductAttributeRequest { - - private PutExternalAssetOwnerLoanProductAttributeRequest() {} - - @Schema(example = "SETTLEMENT_MODEL") - public String attributeKey; - - @Schema(example = "DELAYED_SETTLEMENT_DISABLED") - public String attributeValue; - } - -} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java index 9f0a91564a0..cf3124c4a97 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResource.java @@ -19,8 +19,6 @@ package org.apache.fineract.investor.api; import static org.apache.fineract.infrastructure.core.service.CommandParameterUtil.BUY_BACK_COMMAND_VALUE; -import static org.apache.fineract.infrastructure.core.service.CommandParameterUtil.CANCEL_COMMAND_VALUE; -import static org.apache.fineract.infrastructure.core.service.CommandParameterUtil.CREATE_COMMAND_VALUE; import static org.apache.fineract.infrastructure.core.service.CommandParameterUtil.INTERMEDIARY_SALE_COMMAND_VALUE; import static org.apache.fineract.infrastructure.core.service.CommandParameterUtil.SALE_COMMAND_VALUE; @@ -31,6 +29,7 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; @@ -40,25 +39,34 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import java.util.List; -import java.util.Map; import lombok.RequiredArgsConstructor; -import org.apache.fineract.batch.command.CommandHandlerRegistry; -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.commons.lang3.StringUtils; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandDispatcher; 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.PagedRequest; import org.apache.fineract.infrastructure.security.service.PlatformUserRightsContext; import org.apache.fineract.investor.api.search.ExternalAssetOwnersSearchApiDelegate; +import org.apache.fineract.investor.command.ExternalAssetOwnerBuybackCommand; +import org.apache.fineract.investor.command.ExternalAssetOwnerCancelCommand; +import org.apache.fineract.investor.command.ExternalAssetOwnerCreateCommand; +import org.apache.fineract.investor.command.ExternalAssetOwnerIntermediarySaleCommand; +import org.apache.fineract.investor.command.ExternalAssetOwnerSaleCommand; import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition; -import org.apache.fineract.investor.data.ExternalOwnerJournalEntryData; -import org.apache.fineract.investor.data.ExternalOwnerTransferJournalEntryData; +import org.apache.fineract.investor.data.ExternalAssetOwnerCreateResponse; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.investor.data.ExternalOwnerJournalEntryResponse; +import org.apache.fineract.investor.data.ExternalOwnerTransferJournalEntryResponse; import org.apache.fineract.investor.data.ExternalTransferData; import org.apache.fineract.investor.data.ExternalTransferOwnerData; -import org.apache.fineract.investor.data.request.ExternalAssetOwnerRequest; +import org.apache.fineract.investor.data.ExternalTransferResponse; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerBuybackRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCancelRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCreateRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerIntermediarySaleRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerSaleRequest; +import org.apache.fineract.investor.service.ExternalAssetOwnerReadMapper; import org.apache.fineract.investor.service.ExternalAssetOwnersReadService; import org.apache.fineract.investor.service.search.domain.ExternalAssetOwnerSearchRequest; import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformServiceCommon; @@ -73,58 +81,43 @@ @Conditional(InvestorModuleIsEnabledCondition.class) public class ExternalAssetOwnersApiResource { + private final ExternalAssetOwnerReadMapper externalAssetOwnerReadMapper; private final PlatformUserRightsContext platformUserRightsContext; private final ExternalAssetOwnersReadService externalAssetOwnersReadService; - private final DefaultToApiJsonSerializer postApiJsonSerializerService; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; - private final LoanReadPlatformServiceCommon loanReadPlatformService; private final ExternalAssetOwnersSearchApiDelegate delegate; + private final CommandDispatcher commandDispatcher; + private final LoanReadPlatformServiceCommon loanReadPlatformService; private static final String COMMAND_PARAM = "command"; - private static final CommandHandlerRegistry COMMAND_HANDLER_REGISTRY = new CommandHandlerRegistry<>( - Map.of(CANCEL_COMMAND_VALUE, (id, json) -> new CommandWrapperBuilder().cancelTransactionByIdToExternalAssetOwner(id).build(), - INTERMEDIARY_SALE_COMMAND_VALUE, - (id, json) -> new CommandWrapperBuilder().withJson(json).intermediarySaleLoanToExternalAssetOwner(id).build(), - SALE_COMMAND_VALUE, (id, json) -> new CommandWrapperBuilder().withJson(json).saleLoanToExternalAssetOwner(id).build(), - BUY_BACK_COMMAND_VALUE, - (id, json) -> new CommandWrapperBuilder().withJson(json).buybackLoanToExternalAssetOwner(id).build(), - CREATE_COMMAND_VALUE, (id, json) -> new CommandWrapperBuilder().withJson(json).createExternalAssetOwner().build())); - @POST @Path("/transfers/loans/{loanId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnersApiResourceSwagger.PostInitiateTransferResponse.class))) + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerSaleRequest.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnerTransferResponse.class))) @ApiResponse(responseCode = "403", description = "Transfer cannot be initiated") - public CommandProcessingResult transferRequestWithLoanId(@PathParam("loanId") final Long loanId, - @Parameter ExternalAssetOwnerRequest assetOwnerReq, - @QueryParam(COMMAND_PARAM) @Parameter(description = COMMAND_PARAM) final String commandParam) { + public ExternalAssetOwnerTransferResponse transferRequestWithLoanId(@PathParam("loanId") final Long loanId, + @QueryParam(COMMAND_PARAM) @Parameter(description = COMMAND_PARAM) final String commandParam, + final ExternalAssetOwnerSaleRequest request) { platformUserRightsContext.isAuthenticated(); - final String serializedAssetRequest = postApiJsonSerializerService.serialize(assetOwnerReq); - final CommandWrapper commandRequest = COMMAND_HANDLER_REGISTRY.execute(commandParam, loanId, serializedAssetRequest, - new UnrecognizedQueryParamException(COMMAND_PARAM, commandParam)); - return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + request.setLoanId(loanId); + return (ExternalAssetOwnerTransferResponse) commandDispatcher.dispatch(buildTransferCommand(commandParam, request)).get(); } @POST @Path("/transfers/loans/external-id/{loanExternalId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnersApiResourceSwagger.PostInitiateTransferResponse.class))) + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ExternalAssetOwnerSaleRequest.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnerTransferResponse.class))) @ApiResponse(responseCode = "403", description = "Transfer cannot be initiated") - public CommandProcessingResult transferRequestWithLoanExternalId(@PathParam("loanExternalId") final String externalLoanId, - @Parameter ExternalAssetOwnerRequest assetOwnerReq, - @QueryParam(COMMAND_PARAM) @Parameter(description = COMMAND_PARAM) final String commandParam) { + public ExternalAssetOwnerTransferResponse transferRequestWithLoanExternalId(@PathParam("loanExternalId") final String externalLoanId, + @QueryParam(COMMAND_PARAM) @Parameter(description = COMMAND_PARAM) final String commandParam, + final ExternalAssetOwnerSaleRequest request) { platformUserRightsContext.isAuthenticated(); - final Long loanId = loanReadPlatformService.getLoanIdByLoanExternalId(externalLoanId); - final String serializedAssetRequest = postApiJsonSerializerService.serialize(assetOwnerReq); - final CommandWrapper commandRequest = COMMAND_HANDLER_REGISTRY.execute(commandParam, loanId, serializedAssetRequest, - new UnrecognizedQueryParamException(COMMAND_PARAM, commandParam)); - return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - + request.setLoanId(loanReadPlatformService.getLoanIdByLoanExternalId(externalLoanId)); + return (ExternalAssetOwnerTransferResponse) commandDispatcher.dispatch(buildTransferCommand(commandParam, request)).get(); } @POST @@ -132,14 +125,15 @@ public CommandProcessingResult transferRequestWithLoanExternalId(@PathParam("loa @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Transfer external asset", operationId = "transferRequestWithId") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnersApiResourceSwagger.PostInitiateTransferResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnerTransferResponse.class))) @ApiResponse(responseCode = "403", description = "Transfer cannot be initiated") - public CommandProcessingResult transferRequestWithId(@PathParam("id") final Long id, + public ExternalAssetOwnerTransferResponse transferRequestWithId(@PathParam("id") final Long id, @QueryParam(COMMAND_PARAM) @Parameter(description = COMMAND_PARAM) final String commandParam) { platformUserRightsContext.isAuthenticated(); - final CommandWrapper commandRequest = COMMAND_HANDLER_REGISTRY.execute(commandParam, id, null, - new UnrecognizedQueryParamException(COMMAND_PARAM, commandParam)); - return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + final var request = ExternalAssetOwnerCancelRequest.builder().transferId(id).build(); + final var command = new ExternalAssetOwnerCancelCommand(); + command.setPayload(request); + return (ExternalAssetOwnerTransferResponse) commandDispatcher.dispatch(command).get(); } @POST @@ -147,15 +141,16 @@ public CommandProcessingResult transferRequestWithId(@PathParam("id") final Long @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Transfer external asset by external ID", operationId = "transferRequestWithIdByExternalId") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnersApiResourceSwagger.PostInitiateTransferResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ExternalAssetOwnerTransferResponse.class))) @ApiResponse(responseCode = "403", description = "Transfer cannot be initiated") - public CommandProcessingResult transferRequestWithId(@PathParam("externalId") final String externalId, + public ExternalAssetOwnerTransferResponse transferRequestWithId(@PathParam("externalId") final String externalId, @QueryParam(COMMAND_PARAM) @Parameter(description = COMMAND_PARAM) final String commandParam) { platformUserRightsContext.isAuthenticated(); final Long id = externalAssetOwnersReadService.retrieveLastTransferIdByExternalId(new ExternalId(externalId)); - final CommandWrapper commandRequest = COMMAND_HANDLER_REGISTRY.execute(commandParam, id, null, - new UnrecognizedQueryParamException(COMMAND_PARAM, commandParam)); - return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + final var request = ExternalAssetOwnerCancelRequest.builder().transferId(id).build(); + final var command = new ExternalAssetOwnerCancelCommand(); + command.setPayload(request); + return (ExternalAssetOwnerTransferResponse) commandDispatcher.dispatch(command).get(); } @GET @@ -163,14 +158,15 @@ public CommandProcessingResult transferRequestWithId(@PathParam("externalId") fi @Produces({ MediaType.APPLICATION_JSON }) @Operation(tags = { "External Asset Owners" }, summary = "Retrieve External Asset Owner Transfers", description = "Retrieve External Asset Owner Transfer items by transferExternalId, loanId or loanExternalId") - public Page getTransfers( + public Page getTransfers( @QueryParam("transferExternalId") @Parameter(description = "transferExternalId") final String transferExternalId, @QueryParam("loanId") @Parameter(description = "loanId") final Long loanId, @QueryParam("loanExternalId") @Parameter(description = "loanExternalId") final String loanExternalId, @QueryParam("offset") @Parameter(description = "offset") final Integer offset, @QueryParam("limit") @Parameter(description = "limit") final Integer limit) { platformUserRightsContext.isAuthenticated(); - return externalAssetOwnersReadService.retrieveTransferData(loanId, loanExternalId, transferExternalId, offset, limit); + return externalAssetOwnersReadService.retrieveTransferData(loanId, loanExternalId, transferExternalId, offset, limit) + .map(externalAssetOwnerReadMapper::toTransferResponse); } @GET @@ -178,12 +174,13 @@ public Page getTransfers( @Produces({ MediaType.APPLICATION_JSON }) @Operation(tags = { "External Asset Owners" }, summary = "Retrieve Active Asset Owner Transfer", description = "Retrieve Active External Asset Owner Transfer by transferExternalId, loanId or loanExternalId") - public ExternalTransferData getActiveTransfer( + public ExternalTransferResponse getActiveTransfer( @QueryParam("transferExternalId") @Parameter(description = "transferExternalId") final String transferExternalId, @QueryParam("loanId") @Parameter(description = "loanId") final Long loanId, @QueryParam("loanExternalId") @Parameter(description = "loanExternalId") final String loanExternalId) { platformUserRightsContext.isAuthenticated(); - return externalAssetOwnersReadService.retrieveActiveTransferData(loanId, loanExternalId, transferExternalId); + return externalAssetOwnerReadMapper + .toTransferResponse(externalAssetOwnersReadService.retrieveActiveTransferData(loanId, loanExternalId, transferExternalId)); } @GET @@ -191,12 +188,13 @@ public ExternalTransferData getActiveTransfer( @Produces({ MediaType.APPLICATION_JSON }) @Operation(tags = { "External Asset Owners" }, summary = "Retrieve Journal Entries of Transfer", description = "Retrieve Journal entries of transfer by transferId") - public ExternalOwnerTransferJournalEntryData getJournalEntriesOfTransfer( + public ExternalOwnerTransferJournalEntryResponse getJournalEntriesOfTransfer( @PathParam("transferId") @Parameter(description = "transferId") final Long transferId, @QueryParam("offset") @Parameter(description = "offset") final Integer offset, @QueryParam("limit") @Parameter(description = "limit") final Integer limit) { platformUserRightsContext.isAuthenticated(); - return externalAssetOwnersReadService.retrieveJournalEntriesOfTransfer(transferId, offset, limit); + return externalAssetOwnerReadMapper + .toTransferJournalEntryResponse(externalAssetOwnersReadService.retrieveJournalEntriesOfTransfer(transferId, offset, limit)); } @GET @@ -204,12 +202,13 @@ public ExternalOwnerTransferJournalEntryData getJournalEntriesOfTransfer( @Produces({ MediaType.APPLICATION_JSON }) @Operation(tags = { "External Asset Owners" }, summary = "Retrieve Journal Entries of Owner", description = "Retrieve Journal entries of owner by owner externalId") - public ExternalOwnerJournalEntryData getJournalEntriesOfOwner( + public ExternalOwnerJournalEntryResponse getJournalEntriesOfOwner( @PathParam("ownerExternalId") @Parameter(description = "ownerExternalId") final String ownerExternalId, @QueryParam("offset") @Parameter(description = "offset") final Integer offset, @QueryParam("limit") @Parameter(description = "limit") final Integer limit) { platformUserRightsContext.isAuthenticated(); - return externalAssetOwnersReadService.retrieveJournalEntriesOfOwner(ownerExternalId, offset, limit); + return externalAssetOwnerReadMapper + .toOwnerJournalEntryResponse(externalAssetOwnersReadService.retrieveJournalEntriesOfOwner(ownerExternalId, offset, limit)); } @POST @@ -226,14 +225,14 @@ public Page searchInvestorData(@Parameter PagedRequest retrieveExternalAssetOwners() { platformUserRightsContext.isAuthenticated(); return externalAssetOwnersReadService.retrieveAllExternalOwners(); } + + // Private helper to route by command param + private Command buildTransferCommand(String commandParam, ExternalAssetOwnerSaleRequest request) { + return switch (StringUtils.trimToEmpty(commandParam)) { + case SALE_COMMAND_VALUE -> { + final var cmd = new ExternalAssetOwnerSaleCommand(); + cmd.setPayload(request); + yield cmd; + } + case INTERMEDIARY_SALE_COMMAND_VALUE -> { + final var intermediaryRequest = ExternalAssetOwnerIntermediarySaleRequest.builder().loanId(request.getLoanId()) + .ownerExternalId(request.getOwnerExternalId()).purchasePriceRatio(request.getPurchasePriceRatio()) + .settlementDate(request.getSettlementDate()).transferExternalId(request.getTransferExternalId()) + .transferExternalGroupId(request.getTransferExternalGroupId()).dateFormat(request.getDateFormat()) + .locale(request.getLocale()).build(); + final var cmd = new ExternalAssetOwnerIntermediarySaleCommand(); + cmd.setPayload(intermediaryRequest); + yield cmd; + } + case BUY_BACK_COMMAND_VALUE -> { + final var buybackRequest = ExternalAssetOwnerBuybackRequest.builder().loanId(request.getLoanId()) + .settlementDate(request.getSettlementDate()).transferExternalId(request.getTransferExternalId()) + .dateFormat(request.getDateFormat()).locale(request.getLocale()).build(); + final var cmd = new ExternalAssetOwnerBuybackCommand(); + cmd.setPayload(buybackRequest); + yield cmd; + } + default -> throw new UnrecognizedQueryParamException(COMMAND_PARAM, commandParam); + }; + } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java b/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java deleted file mode 100644 index ea5a3f18307..00000000000 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/api/ExternalAssetOwnersApiResourceSwagger.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * 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; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.LocalDate; - -@SuppressWarnings({ "MemberName" }) -final class ExternalAssetOwnersApiResourceSwagger { - - private ExternalAssetOwnersApiResourceSwagger() {} - - @Schema(description = "PostInitiateTransferResponse") - public static final class PostInitiateTransferResponse { - - private PostInitiateTransferResponse() {} - - @Schema(example = "1", description = "transfer ID") - public Long resourceId; - - @Schema(example = "36efeb06-d835-48a1-99eb-09bd1d348c1e", description = "transfer external ID") - public String resourceExternalId; - - @Schema(example = "2", description = "loan ID") - public Long subResourceId; - - @Schema(example = "36efeb06-d835-48a1-99eb-09bd1d348c2e", description = "loan external ID") - public String subResourceExternalId; - - public ExternalAssetOwnerTransferChangesData changes; - - @Schema(example = "yyyy-MM-dd") - public String dateFormat; - - @Schema(example = "en") - public String locale; - - @Schema(description = "ExternalAssetOwnerTransferChangesData") - static final class ExternalAssetOwnerTransferChangesData { - - @Schema(example = "[2023, 5, 23]") - public LocalDate settlementDate; - - @Schema(example = "1234567890987654321abc") - public String ownerExternalId; - - @Schema(example = "36efeb06-d835-48a1-99eb-09bd1d348c1e") - public String transferExternalId; - - @Schema(example = "1.23456789") - public String purchasePriceRatio; - } - } - - @Schema(description = "PostExternalAssetOwnerRequest") - public static final class PostExternalAssetOwnerRequest { - - private PostExternalAssetOwnerRequest() {} - - @Schema(example = "36efeb06-d835-48a1-99eb-09bd1d348c1e", description = "External Asset Owner External Id") - public String ownerExternalId; - } - - @Schema(description = "PostExternalAssetOwnerResponse") - public static final class PostExternalAssetOwnerResponse { - - private PostExternalAssetOwnerResponse() {} - - @Schema(example = "1", description = "External Asset Owner Id") - public Long resourceId; - } - -} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerBuybackCommand.java b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerBuybackCommand.java new file mode 100644 index 00000000000..718f1bb9670 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerBuybackCommand.java @@ -0,0 +1,28 @@ +/** + * 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.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerBuybackRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ExternalAssetOwnerBuybackCommand extends Command {} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerCancelCommand.java b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerCancelCommand.java new file mode 100644 index 00000000000..e787cd162fb --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerCancelCommand.java @@ -0,0 +1,28 @@ +/** + * 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.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCancelRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ExternalAssetOwnerCancelCommand extends Command {} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerCreateCommand.java b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerCreateCommand.java new file mode 100644 index 00000000000..482280460ae --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerCreateCommand.java @@ -0,0 +1,28 @@ +/** + * 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.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCreateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ExternalAssetOwnerCreateCommand extends Command {} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerIntermediarySaleCommand.java b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerIntermediarySaleCommand.java new file mode 100644 index 00000000000..ef79ab2667d --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerIntermediarySaleCommand.java @@ -0,0 +1,28 @@ +/** + * 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.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerIntermediarySaleRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ExternalAssetOwnerIntermediarySaleCommand extends Command {} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerLoanProductAttributeCreateCommand.java b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerLoanProductAttributeCreateCommand.java new file mode 100644 index 00000000000..494181c2a26 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerLoanProductAttributeCreateCommand.java @@ -0,0 +1,28 @@ +/** + * 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.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.investor.data.request.PostExternalAssetOwnerLoanProductAttributeRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ExternalAssetOwnerLoanProductAttributeCreateCommand extends Command {} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerLoanProductAttributeUpdateCommand.java b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerLoanProductAttributeUpdateCommand.java new file mode 100644 index 00000000000..a5cf3ea0437 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerLoanProductAttributeUpdateCommand.java @@ -0,0 +1,28 @@ +/** + * 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.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.investor.data.request.PutExternalAssetOwnerLoanProductAttributeRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ExternalAssetOwnerLoanProductAttributeUpdateCommand extends Command {} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerSaleCommand.java b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerSaleCommand.java new file mode 100644 index 00000000000..9b5b6091bb8 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/command/ExternalAssetOwnerSaleCommand.java @@ -0,0 +1,28 @@ +/** + * 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.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerSaleRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ExternalAssetOwnerSaleCommand extends Command {} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerCreateResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerCreateResponse.java new file mode 100644 index 00000000000..ae0d7d8f29f --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerCreateResponse.java @@ -0,0 +1,38 @@ +/** + * 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.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExternalAssetOwnerCreateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerLoanProductAttributeResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerLoanProductAttributeResponse.java new file mode 100644 index 00000000000..910b4f997d3 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerLoanProductAttributeResponse.java @@ -0,0 +1,46 @@ +/** + * 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.data; + +import com.fasterxml.jackson.annotation.JsonInclude; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ExternalAssetOwnerLoanProductAttributeResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; + private Long subResourceId; + + private String locale; + private String dateFormat; + private String attributeKey; + private String attributeValue; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerTransferResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerTransferResponse.java new file mode 100644 index 00000000000..25627b974b6 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalAssetOwnerTransferResponse.java @@ -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.investor.data; + +import com.fasterxml.jackson.annotation.JsonInclude; +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ExternalAssetOwnerTransferResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; + private String resourceExternalId; + private Long subResourceId; + private String subResourceExternalId; + private Map changes; + + private String locale; + private String dateFormat; + private LocalDate settlementDate; + private String ownerExternalId; + private String purchasePriceRatio; + private String transferExternalId; + private String transferExternalGroupId; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalOwnerJournalEntryResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalOwnerJournalEntryResponse.java new file mode 100644 index 00000000000..425fea2a274 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalOwnerJournalEntryResponse.java @@ -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.data; + +import lombok.Data; +import org.apache.fineract.accounting.journalentry.data.JournalEntryData; +import org.springframework.data.domain.Page; + +@Data +public class ExternalOwnerJournalEntryResponse { + + private ExternalTransferOwnerData ownerData; + private Page journalEntryData; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalOwnerTransferJournalEntryResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalOwnerTransferJournalEntryResponse.java new file mode 100644 index 00000000000..2efc8601cd8 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalOwnerTransferJournalEntryResponse.java @@ -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.data; + +import lombok.Data; +import org.apache.fineract.accounting.journalentry.data.JournalEntryData; +import org.springframework.data.domain.Page; + +@Data +public class ExternalOwnerTransferJournalEntryResponse { + + private ExternalTransferResponse transferData; + private Page journalEntryData; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferResponse.java new file mode 100644 index 00000000000..37d34802e36 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/ExternalTransferResponse.java @@ -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.data; + +import java.time.LocalDate; +import lombok.Data; + +@Data +public class ExternalTransferResponse { + + private Long transferId; + private ExternalTransferOwnerData owner; + private ExternalTransferOwnerData previousOwner; + private ExternalTransferLoanData loan; + private ExternalTransferDataDetails details; + private String transferExternalId; + private String transferExternalGroupId; + private String purchasePriceRatio; + private LocalDate settlementDate; + private ExternalTransferStatus status; + private ExternalTransferSubStatus subStatus; + private LocalDate effectiveFrom; + private LocalDate effectiveTo; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/PostExternalAssetOwnerResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/PostExternalAssetOwnerResponse.java new file mode 100644 index 00000000000..56e34e964b0 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/PostExternalAssetOwnerResponse.java @@ -0,0 +1,38 @@ +/** + * 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.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PostExternalAssetOwnerResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/PostInitiateTransferResponse.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/PostInitiateTransferResponse.java new file mode 100644 index 00000000000..c4d4648e9b4 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/PostInitiateTransferResponse.java @@ -0,0 +1,44 @@ +/** + * 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.data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PostInitiateTransferResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; + private String resourceExternalId; + private Long subResourceId; + private String subResourceExternalId; + private Map changes; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerBuybackRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerBuybackRequest.java new file mode 100644 index 00000000000..c6a59776617 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerBuybackRequest.java @@ -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.investor.data.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExternalAssetOwnerBuybackRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long loanId; + + @NotBlank(message = "{org.apache.fineract.investor.transfer.settlement-date.not-null}") + private String settlementDate; + + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.transfer-external-id.size}") + private String transferExternalId; + + @Schema(example = "yyyy-MM-dd") + private String dateFormat; + + @Schema(example = "en") + private String locale; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerCancelRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerCancelRequest.java new file mode 100644 index 00000000000..dca6079927d --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerCancelRequest.java @@ -0,0 +1,41 @@ +/** + * 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.data.request; + +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExternalAssetOwnerCancelRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull(message = "{org.apache.fineract.investor.transfer.transfer-id.not-null}") + private Long transferId; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerCreateRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerCreateRequest.java new file mode 100644 index 00000000000..973e2d7a01b --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerCreateRequest.java @@ -0,0 +1,43 @@ +/** + * 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.data.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExternalAssetOwnerCreateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @jakarta.validation.constraints.NotBlank(message = "{validation.msg.externalAssetOwner.ownerExternalId.cannot.be.blank}") + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.owner-external-id.size}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, maxLength = Integer.MAX_VALUE) + private String ownerExternalId; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerIntermediarySaleRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerIntermediarySaleRequest.java new file mode 100644 index 00000000000..8d80caf4766 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerIntermediarySaleRequest.java @@ -0,0 +1,65 @@ +/** + * 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.data.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExternalAssetOwnerIntermediarySaleRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long loanId; + + @NotBlank(message = "{org.apache.fineract.investor.transfer.owner-external-id.not-blank}") + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.owner-external-id.size}") + private String ownerExternalId; + + @NotBlank(message = "{org.apache.fineract.investor.transfer.purchase-price-ratio.not-blank}") + @Size(max = 50, message = "{org.apache.fineract.investor.transfer.purchase-price-ratio.size}") + private String purchasePriceRatio; + + @NotBlank(message = "{org.apache.fineract.investor.transfer.settlement-date.not-null}") + private String settlementDate; + + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.transfer-external-id.size}") + private String transferExternalId; + + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.transfer-external-group-id.size}") + private String transferExternalGroupId; + + @Schema(example = "yyyy-MM-dd") + private String dateFormat; + + @Schema(example = "en") + private String locale; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerRequest.java index 7fda8deabf9..f214f3401ff 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerRequest.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerRequest.java @@ -30,6 +30,8 @@ public class ExternalAssetOwnerRequest implements Serializable { @Serial private static final long serialVersionUID = 1L; + private Long loanId; + private Long transferId; private String settlementDate; private String ownerExternalId; private String transferExternalId; diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerSaleRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerSaleRequest.java new file mode 100644 index 00000000000..0b7c45097a6 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/ExternalAssetOwnerSaleRequest.java @@ -0,0 +1,69 @@ +/** + * 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.data.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExternalAssetOwnerSaleRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long loanId; + + @NotBlank(message = "{org.apache.fineract.investor.transfer.settlement-date.not-null}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String settlementDate; + + @NotBlank(message = "{org.apache.fineract.investor.transfer.owner-external-id.not-blank}") + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.owner-external-id.size}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, maxLength = Integer.MAX_VALUE) + private String ownerExternalId; + + @NotBlank(message = "{org.apache.fineract.investor.transfer.purchase-price-ratio.not-blank}") + @Size(max = 50, message = "{org.apache.fineract.investor.transfer.purchase-price-ratio.size}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, maxLength = Integer.MAX_VALUE) + private String purchasePriceRatio; + + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.transfer-external-id.size}") + @Schema(maxLength = Integer.MAX_VALUE) + private String transferExternalId; + + @Size(max = 100, message = "{org.apache.fineract.investor.transfer.transfer-external-group-id.size}") + @Schema(maxLength = Integer.MAX_VALUE) + private String transferExternalGroupId; + + @Schema(example = "yyyy-MM-dd") + private String dateFormat; + + @Schema(example = "en") + private String locale; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/PostExternalAssetOwnerLoanProductAttributeRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/PostExternalAssetOwnerLoanProductAttributeRequest.java new file mode 100644 index 00000000000..15368d8b4e4 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/PostExternalAssetOwnerLoanProductAttributeRequest.java @@ -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.investor.data.request; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(name = "PostExternalAssetOwnerLoanProductAttributeRequest") +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PostExternalAssetOwnerLoanProductAttributeRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Hidden + private Long loanProductId; + + @NotBlank(message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeKey.cannot.be.blank}") + @Size(max = 255, message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeKey.max.length}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, maxLength = Integer.MAX_VALUE) + private String attributeKey; + + @NotBlank(message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeValue.cannot.be.blank}") + @Size(max = 255, message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeValue.max.length}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, maxLength = Integer.MAX_VALUE) + private String attributeValue; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/PutExternalAssetOwnerLoanProductAttributeRequest.java b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/PutExternalAssetOwnerLoanProductAttributeRequest.java new file mode 100644 index 00000000000..7475a555acc --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/data/request/PutExternalAssetOwnerLoanProductAttributeRequest.java @@ -0,0 +1,57 @@ +/** + * 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.data.request; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema(name = "PutExternalAssetOwnerLoanProductAttributeRequest") +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PutExternalAssetOwnerLoanProductAttributeRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Hidden + private Long loanProductId; + + @Hidden + private Long attributeId; + + @NotBlank(message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeKey.cannot.be.blank}") + @Size(max = 255, message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeKey.max.length}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, maxLength = Integer.MAX_VALUE) + private String attributeKey; + + @NotBlank(message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeValue.cannot.be.blank}") + @Size(max = 255, message = "{validation.msg.externalAssetOwnerLoanProductAttribute.attributeValue.max.length}") + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, maxLength = Integer.MAX_VALUE) + private String attributeValue; +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepositoryImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepositoryImpl.java index 7ebc5c7a2f4..c330b9c2ff4 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepositoryImpl.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/search/SearchingExternalAssetOwnerRepositoryImpl.java @@ -33,6 +33,7 @@ import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.jpa.CriteriaQueryFactory; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.core.service.PagedRequest; import org.apache.fineract.investor.domain.ExternalAssetOwner; import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer; @@ -64,15 +65,15 @@ public Page searchInvestorData(PagedRequest details = root.join("externalAssetOwnerTransferDetails", JoinType.LEFT); Path owner = root.get("owner"); - Specification spec = (r, q, builder) -> { + final Specification spec = (r, q, builder) -> { Path o = r.get("owner"); List 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))); + var externalId = ExternalIdFactory.produce(request.getText()); + predicates.add(cb.or(cb.equal(r.get("externalId"), externalId), cb.equal(o.get("externalId"), externalId), + cb.equal(r.get("externalLoanId"), externalId))); } if (request.getSubmittedFromDate() != null) { @@ -106,5 +107,4 @@ public Page searchInvestorData(PagedRequest queryToExecute = entityManager.createQuery(query); return criteriaQueryFactory.readPage(queryToExecute, ExternalAssetOwnerTransfer.class, pageable, spec); } - } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/serialization/ExternalAssetOwnerValidator.java b/fineract-investor/src/main/java/org/apache/fineract/investor/serialization/ExternalAssetOwnerValidator.java deleted file mode 100644 index 918d3352731..00000000000 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/serialization/ExternalAssetOwnerValidator.java +++ /dev/null @@ -1,51 +0,0 @@ - -/** - * 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.serialization; - -import com.google.gson.JsonElement; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.infrastructure.core.validator.ParseAndValidator; -import org.apache.fineract.investor.data.ExternalTransferRequestParameters; -import org.apache.fineract.portfolio.common.service.Validator; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class ExternalAssetOwnerValidator extends ParseAndValidator { - - private final FromJsonHelper fromApiJsonHelper; - - public void validateForCreate(JsonCommand command) { - final String json = command.json(); - validateRequestBody(json); - validateForSupportedParameters(json, List.of(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID), fromApiJsonHelper); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - Validator.validateOrThrow("externalAssetOwner", baseDataValidator -> { - final String ownerExternalId = this.fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID, - element); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID).value(ownerExternalId).notNull(); - }); - } - -} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/BuybackLoanFromExternalAssetOwnerHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/BuybackLoanFromExternalAssetOwnerHandler.java index 00977500cf9..0b49a91bb6e 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/BuybackLoanFromExternalAssetOwnerHandler.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/BuybackLoanFromExternalAssetOwnerHandler.java @@ -18,22 +18,35 @@ */ package org.apache.fineract.investor.service; +import io.github.resilience4j.retry.annotation.Retry; 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; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerBuybackRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +@Slf4j +@Component @RequiredArgsConstructor -@Service -@CommandType(entity = "LOAN", action = "BUYBACK") -public class BuybackLoanFromExternalAssetOwnerHandler implements NewCommandSourceHandler { +public class BuybackLoanFromExternalAssetOwnerHandler + implements CommandHandler { private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService; + private final InvestorCommandValidationService validationService; + @Retry(name = "commandExternalAssetOwnerBuyback", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return externalAssetOwnersWriteService.buybackLoanByLoanId(command); + @Transactional + public ExternalAssetOwnerTransferResponse handle(Command command) { + validationService.validate(command.getPayload()); + return externalAssetOwnersWriteService.buybackLoan(command.getPayload()); + } + + @Override + public ExternalAssetOwnerTransferResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CancelTransactionFromExternalAssetOwnerHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/CancelTransactionFromExternalAssetOwnerHandler.java index 8200734b97e..4a915b25aeb 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CancelTransactionFromExternalAssetOwnerHandler.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/CancelTransactionFromExternalAssetOwnerHandler.java @@ -18,22 +18,35 @@ */ package org.apache.fineract.investor.service; +import io.github.resilience4j.retry.annotation.Retry; 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; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCancelRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +@Slf4j +@Component @RequiredArgsConstructor -@Service -@CommandType(entity = "LOAN", action = "CANCEL") -public class CancelTransactionFromExternalAssetOwnerHandler implements NewCommandSourceHandler { +public class CancelTransactionFromExternalAssetOwnerHandler + implements CommandHandler { private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService; + private final InvestorCommandValidationService validationService; + @Retry(name = "commandExternalAssetOwnerCancel", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return externalAssetOwnersWriteService.cancelTransactionById(command); + @Transactional + public ExternalAssetOwnerTransferResponse handle(Command command) { + validationService.validate(command.getPayload()); + return externalAssetOwnersWriteService.cancelTransfer(command.getPayload()); + } + + @Override + public ExternalAssetOwnerTransferResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CreateExternalAssetOwnerHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/CreateExternalAssetOwnerHandler.java index e06ddfa580b..da63efc00d0 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CreateExternalAssetOwnerHandler.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/CreateExternalAssetOwnerHandler.java @@ -18,22 +18,34 @@ */ package org.apache.fineract.investor.service; +import io.github.resilience4j.retry.annotation.Retry; 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; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.investor.data.ExternalAssetOwnerCreateResponse; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCreateRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +@Slf4j +@Component @RequiredArgsConstructor -@Service -@CommandType(entity = "EXTERNAL_ASSET_OWNER", action = "CREATE") -public class CreateExternalAssetOwnerHandler implements NewCommandSourceHandler { +public class CreateExternalAssetOwnerHandler implements CommandHandler { private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService; + private final InvestorCommandValidationService validationService; + @Retry(name = "commandExternalAssetOwnerCreate", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return externalAssetOwnersWriteService.createExternalAssetOwner(command); + @Transactional + public ExternalAssetOwnerCreateResponse handle(Command command) { + validationService.validate(command.getPayload()); + return externalAssetOwnersWriteService.createOwner(command.getPayload()); + } + + @Override + public ExternalAssetOwnerCreateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CreateExternalAssetOwnerLoanProductAttributeHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/CreateExternalAssetOwnerLoanProductAttributeHandler.java deleted file mode 100644 index 2261a318a89..00000000000 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CreateExternalAssetOwnerLoanProductAttributeHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * 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 = "EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE", action = "CREATE") -public class CreateExternalAssetOwnerLoanProductAttributeHandler implements NewCommandSourceHandler { - - private final ExternalAssetOwnerLoanProductAttributesWriteService externalAssetOwnerLoanProductAttributesWriteService; - - @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return externalAssetOwnerLoanProductAttributesWriteService.createExternalAssetOwnerLoanProductAttribute(command); - } -} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributeCreateCommandHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributeCreateCommandHandler.java new file mode 100644 index 00000000000..e6bf19703c0 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributeCreateCommandHandler.java @@ -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; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeResponse; +import org.apache.fineract.investor.data.request.PostExternalAssetOwnerLoanProductAttributeRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ExternalAssetOwnerLoanProductAttributeCreateCommandHandler + implements CommandHandler { + + private final ExternalAssetOwnerLoanProductAttributesWriteService writeService; + private final InvestorCommandValidationService validationService; + + @Retry(name = "commandExternalAssetOwnerLoanProductAttributeCreate", fallbackMethod = "fallback") + @Override + @Transactional + public ExternalAssetOwnerLoanProductAttributeResponse handle(Command command) { + validationService.validate(command.getPayload()); + return writeService.createExternalAssetOwnerLoanProductAttribute(command.getPayload()); + } + + @Override + public ExternalAssetOwnerLoanProductAttributeResponse fallback(Command command, + Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributeUpdateCommandHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributeUpdateCommandHandler.java new file mode 100644 index 00000000000..6b6d3ca0e9c --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributeUpdateCommandHandler.java @@ -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; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeResponse; +import org.apache.fineract.investor.data.request.PutExternalAssetOwnerLoanProductAttributeRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ExternalAssetOwnerLoanProductAttributeUpdateCommandHandler + implements CommandHandler { + + private final ExternalAssetOwnerLoanProductAttributesWriteService writeService; + private final InvestorCommandValidationService validationService; + + @Retry(name = "commandExternalAssetOwnerLoanProductAttributeUpdate", fallbackMethod = "fallback") + @Override + @Transactional + public ExternalAssetOwnerLoanProductAttributeResponse handle(Command command) { + validationService.validate(command.getPayload()); + return writeService.updateExternalAssetOwnerLoanProductAttribute(command.getPayload()); + } + + @Override + public ExternalAssetOwnerLoanProductAttributeResponse fallback(Command command, + Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteService.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteService.java index 13aa8d746ed..935e75a5258 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteService.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteService.java @@ -18,13 +18,16 @@ */ package org.apache.fineract.investor.service; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeResponse; +import org.apache.fineract.investor.data.request.PostExternalAssetOwnerLoanProductAttributeRequest; +import org.apache.fineract.investor.data.request.PutExternalAssetOwnerLoanProductAttributeRequest; public interface ExternalAssetOwnerLoanProductAttributesWriteService { - CommandProcessingResult createExternalAssetOwnerLoanProductAttribute(JsonCommand command); + ExternalAssetOwnerLoanProductAttributeResponse createExternalAssetOwnerLoanProductAttribute( + PostExternalAssetOwnerLoanProductAttributeRequest request); - CommandProcessingResult updateExternalAssetOwnerLoanProductAttribute(JsonCommand command, String attributeKey, String attributeValue); + ExternalAssetOwnerLoanProductAttributeResponse updateExternalAssetOwnerLoanProductAttribute( + PutExternalAssetOwnerLoanProductAttributeRequest request); } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImpl.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImpl.java index 1e24c98d248..fa43bc3862b 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImpl.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImpl.java @@ -20,27 +20,14 @@ import static org.reflections.scanners.Scanners.SubTypes; -import com.google.gson.JsonElement; -import com.google.gson.reflect.TypeToken; import jakarta.transaction.Transactional; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import lombok.RequiredArgsConstructor; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; -import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeRequestParameters; +import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeResponse; import org.apache.fineract.investor.data.attribute.ExternalAssetOwnerLoanProductAttribute; +import org.apache.fineract.investor.data.request.PostExternalAssetOwnerLoanProductAttributeRequest; +import org.apache.fineract.investor.data.request.PutExternalAssetOwnerLoanProductAttributeRequest; import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes; import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributesRepository; import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeAlreadyExistsException; @@ -60,39 +47,36 @@ public class ExternalAssetOwnerLoanProductAttributesWriteServiceImpl implements private static final String INVESTOR_PATH = "org.apache.fineract.investor"; - private final FromJsonHelper fromApiJsonHelper; private final ExternalAssetOwnerLoanProductAttributesRepository externalAssetOwnerLoanProductAttributesRepository; private final LoanProductRepository loanProductRepository; private final Set> implementingClasses = new Reflections(INVESTOR_PATH) .get(SubTypes.of(ExternalAssetOwnerLoanProductAttribute.class).asClass()); @Override - public CommandProcessingResult createExternalAssetOwnerLoanProductAttribute(JsonCommand command) { - final JsonElement json = fromApiJsonHelper.parse(command.json()); - String attributeKey = fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY, - json); - String attributeValue = fromApiJsonHelper - .extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE, json); - Long loanProductId = command.getProductId(); - validateLoanProductAttributeRequest(command.json(), attributeKey, attributeValue); + public ExternalAssetOwnerLoanProductAttributeResponse createExternalAssetOwnerLoanProductAttribute( + PostExternalAssetOwnerLoanProductAttributeRequest request) { + final String attributeKey = request.getAttributeKey(); + final String attributeValue = request.getAttributeValue(); + final Long loanProductId = request.getLoanProductId(); validateExternalAssetOwnerLoanProductAttribute(attributeKey, attributeValue); validateLoanProductExistsAndAttributeDoesNotExist(loanProductId, attributeKey); - ExternalAssetOwnerLoanProductAttributes newAttribute = createExternalAssetOwnerLoanProductAttribute(loanProductId, attributeKey, - attributeValue); + final ExternalAssetOwnerLoanProductAttributes newAttribute = createExternalAssetOwnerLoanProductAttribute(loanProductId, + attributeKey, attributeValue); externalAssetOwnerLoanProductAttributesRepository.saveAndFlush(newAttribute); return buildResponseData(newAttribute); } @Override - @CacheEvict(cacheNames = "externalAssetOwnerLoanProductAttributes", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#command.getProductId().toString() + #attributeKey)") - public CommandProcessingResult updateExternalAssetOwnerLoanProductAttribute(JsonCommand command, String attributeKey, - String attributeValue) { - Long loanProductId = command.getProductId(); - Long attributeId = command.entityId(); - validateLoanProductAttributeRequest(command.json(), attributeKey, attributeValue); + @CacheEvict(cacheNames = "externalAssetOwnerLoanProductAttributes", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#request.loanProductId.toString() + #request.attributeKey)") + public ExternalAssetOwnerLoanProductAttributeResponse updateExternalAssetOwnerLoanProductAttribute( + PutExternalAssetOwnerLoanProductAttributeRequest request) { + final Long loanProductId = request.getLoanProductId(); + final Long attributeId = request.getAttributeId(); + final String attributeKey = request.getAttributeKey(); + final String attributeValue = request.getAttributeValue(); validateExternalAssetOwnerLoanProductAttribute(attributeKey, attributeValue); validateLoanProductExists(loanProductId); - ExternalAssetOwnerLoanProductAttributes attributeToUpdate = getLoanProductAttribute(attributeId); + final ExternalAssetOwnerLoanProductAttributes attributeToUpdate = getLoanProductAttribute(attributeId); validateLoanProductAttributeKeysMatch(attributeKey, attributeToUpdate.getAttributeKey()); if (!attributeToUpdate.getAttributeValue().equals(attributeValue)) { attributeToUpdate.setAttributeValue(attributeValue); @@ -101,28 +85,6 @@ public CommandProcessingResult updateExternalAssetOwnerLoanProductAttribute(Json return buildResponseData(attributeToUpdate); } - private void validateLoanProductAttributeRequest(String apiRequestBodyAsJson, String attributeKey, String attributeValue) { - final Set requestParameters = new HashSet<>( - Arrays.asList(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY, - ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE)); - final Type typeOfMap = new TypeToken>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, apiRequestBodyAsJson, requestParameters); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loanproductattribute"); - - baseDataValidator.reset().parameter(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY).value(attributeKey) - .notBlank().notExceedingLengthOf(255); - - baseDataValidator.reset().parameter(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE).value(attributeValue) - .notBlank().notExceedingLengthOf(255); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", - dataValidationErrors); - } - } - private void validateLoanProductExistsAndAttributeDoesNotExist(Long loanProductId, String attributeKey) { validateLoanProductExists(loanProductId); validateLoanProductAttributeDoesNotExist(loanProductId, attributeKey); @@ -182,9 +144,8 @@ private ExternalAssetOwnerLoanProductAttributes createExternalAssetOwnerLoanProd return attribute; } - private CommandProcessingResult buildResponseData(ExternalAssetOwnerLoanProductAttributes savedAttribute) { - return new CommandProcessingResultBuilder() // - .withEntityId(savedAttribute.getLoanProductId()) // - .build(); + private ExternalAssetOwnerLoanProductAttributeResponse buildResponseData(ExternalAssetOwnerLoanProductAttributes savedAttribute) { + return ExternalAssetOwnerLoanProductAttributeResponse.builder().resourceId(savedAttribute.getId()) + .subResourceId(savedAttribute.getLoanProductId()).build(); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerReadMapper.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerReadMapper.java new file mode 100644 index 00000000000..7120715c959 --- /dev/null +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerReadMapper.java @@ -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 org.apache.fineract.infrastructure.core.config.MapstructMapperConfig; +import org.apache.fineract.investor.data.ExternalOwnerJournalEntryData; +import org.apache.fineract.investor.data.ExternalOwnerJournalEntryResponse; +import org.apache.fineract.investor.data.ExternalOwnerTransferJournalEntryData; +import org.apache.fineract.investor.data.ExternalOwnerTransferJournalEntryResponse; +import org.apache.fineract.investor.data.ExternalTransferData; +import org.apache.fineract.investor.data.ExternalTransferResponse; +import org.mapstruct.Mapper; + +@Mapper(config = MapstructMapperConfig.class) +public interface ExternalAssetOwnerReadMapper { + + ExternalTransferResponse toTransferResponse(ExternalTransferData source); + + ExternalOwnerTransferJournalEntryResponse toTransferJournalEntryResponse(ExternalOwnerTransferJournalEntryData source); + + ExternalOwnerJournalEntryResponse toOwnerJournalEntryResponse(ExternalOwnerJournalEntryData source); + +} diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteService.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteService.java index 8b0dea4cc9d..5a84a4142c9 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteService.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteService.java @@ -18,18 +18,23 @@ */ package org.apache.fineract.investor.service; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.investor.data.ExternalAssetOwnerCreateResponse; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerBuybackRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCancelRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCreateRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerIntermediarySaleRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerSaleRequest; public interface ExternalAssetOwnersWriteService { - CommandProcessingResult intermediarySaleLoanByLoanId(JsonCommand jsonCommand); + ExternalAssetOwnerTransferResponse saleLoan(ExternalAssetOwnerSaleRequest request); - CommandProcessingResult saleLoanByLoanId(JsonCommand command); + ExternalAssetOwnerTransferResponse intermediarySaleLoan(ExternalAssetOwnerIntermediarySaleRequest request); - CommandProcessingResult buybackLoanByLoanId(JsonCommand command); + ExternalAssetOwnerTransferResponse buybackLoan(ExternalAssetOwnerBuybackRequest request); - CommandProcessingResult cancelTransactionById(JsonCommand command); + ExternalAssetOwnerTransferResponse cancelTransfer(ExternalAssetOwnerCancelRequest request); - CommandProcessingResult createExternalAssetOwner(JsonCommand command); + ExternalAssetOwnerCreateResponse createOwner(ExternalAssetOwnerCreateRequest request); } 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 20c6c03a916..aec6478e0d5 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 @@ -22,16 +22,9 @@ import static org.apache.fineract.investor.data.ExternalTransferStatus.PENDING; import static org.apache.fineract.investor.data.ExternalTransferStatus.PENDING_INTERMEDIATE; -import com.google.gson.JsonElement; -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Type; import java.sql.SQLException; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -40,29 +33,27 @@ import org.apache.commons.lang3.StringUtils; import org.apache.fineract.cob.data.LoanDataForExternalTransfer; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; -import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.domain.ExternalId; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; 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.investor.data.ExternalAssetOwnerCreateResponse; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; import org.apache.fineract.investor.data.ExternalTransferData; -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.data.request.ExternalAssetOwnerBuybackRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCancelRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerCreateRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerIntermediarySaleRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerSaleRequest; 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.exception.ExternalAssetOwnerDuplicateException; import org.apache.fineract.investor.exception.ExternalAssetOwnerInitiateTransferException; -import org.apache.fineract.investor.serialization.ExternalAssetOwnerValidator; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException; @@ -85,72 +76,12 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW private final ExternalAssetOwnerTransferRepository externalAssetOwnerTransferRepository; private final ExternalAssetOwnerRepository externalAssetOwnerRepository; - private final FromJsonHelper fromApiJsonHelper; private final LoanRepository loanRepository; private final DelayedSettlementAttributeService delayedSettlementAttributeService; private final ConfigurationDomainService configurationDomainService; private final ExternalAssetOwnersReadService externalAssetOwnersReadService; - private final ExternalAssetOwnerValidator externalAssetOwnerValidator; private final ExternalAssetOwnerHelper externalAssetOwnerHelper; - @Override - @Transactional - public CommandProcessingResult intermediarySaleLoanByLoanId(JsonCommand command) { - final JsonElement json = fromApiJsonHelper.parse(command.json()); - validateIntermediarySaleRequestBody(command.json()); - Long loanId = command.getLoanId(); - LoanDataForExternalTransfer loanDataForExternalTransfer = fetchAndValidateLoanDataForExternalTransfer(loanId); - if (!delayedSettlementAttributeService.isEnabled(loanDataForExternalTransfer.getLoanProductId())) { - throw new ExternalAssetOwnerInitiateTransferException( - String.format("Delayed Settlement Configuration is not enabled for the loan product: %s", - loanDataForExternalTransfer.getLoanProductShortName())); - } - ExternalId externalId = getTransferExternalIdFromJson(json); - validateExternalId(externalId); - validateLoanStatusIntermediarySale(loanDataForExternalTransfer); - ExternalAssetOwnerTransfer intermediarySaleTransfer = createIntermediarySaleTransfer(loanId, json, - loanDataForExternalTransfer.getExternalId()); - validateIntermediarySale(intermediarySaleTransfer); - externalAssetOwnerTransferRepository.saveAndFlush(intermediarySaleTransfer); - return buildResponseData(intermediarySaleTransfer); - } - - @Override - @Transactional - public CommandProcessingResult saleLoanByLoanId(JsonCommand command) { - final JsonElement json = fromApiJsonHelper.parse(command.json()); - final LoanDataForExternalTransfer loanDataForExternalTransfer = fetchAndValidateLoanDataForExternalTransfer(command.getLoanId()); - final boolean isDelayedSettlementEnabled = delayedSettlementAttributeService - .isEnabled(loanDataForExternalTransfer.getLoanProductId()); - validateSaleRequestBody(command.json()); - ExternalId externalId = getTransferExternalIdFromJson(json); - validateExternalId(externalId); - Long loanId = command.getLoanId(); - validateLoanStatus(loanDataForExternalTransfer, isDelayedSettlementEnabled); - ExternalAssetOwnerTransfer externalAssetOwnerTransfer = createSaleTransfer(loanId, json, - loanDataForExternalTransfer.getExternalId()); - validateSale(externalAssetOwnerTransfer, isDelayedSettlementEnabled); - externalAssetOwnerTransferRepository.saveAndFlush(externalAssetOwnerTransfer); - return buildResponseData(externalAssetOwnerTransfer); - } - - @Override - @Transactional - public CommandProcessingResult buybackLoanByLoanId(JsonCommand command) { - final JsonElement json = fromApiJsonHelper.parse(command.json()); - validateBuybackRequestBody(command.json()); - LoanDataForExternalTransfer loanDataForExternalTransfer = fetchAndValidateLoanDataForExternalTransfer(command.getLoanId()); - LocalDate settlementDate = getSettlementDateFromJson(json); - ExternalId externalId = getTransferExternalIdFromJson(json); - validateSettlementDate(settlementDate); - validateExternalId(externalId); - ExternalAssetOwnerTransfer effectiveTransfer = fetchAndValidateEffectiveTransferForBuyback(loanDataForExternalTransfer, - 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)); @@ -164,16 +95,6 @@ private LoanDataForExternalTransfer fetchAndValidateLoanDataForExternalTransfer( return loanRepository.findLoanDataForExternalTransferByLoanId(loanId).orElseThrow(() -> new LoanNotFoundException(loanId)); } - @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); - return buildResponseData(cancelTransfer); - } - private void validateEffectiveTransferForSale(final List effectiveTransfers) { if (effectiveTransfers.size() == 2) { throw new ExternalAssetOwnerInitiateTransferException("This loan cannot be sold, there is already an in progress transfer"); @@ -349,16 +270,6 @@ private ExternalAssetOwnerTransfer createCancelTransfer(ExternalAssetOwnerTransf return externalAssetOwnerTransfer; } - private CommandProcessingResult buildResponseData(ExternalAssetOwnerTransfer savedExternalAssetOwnerTransfer) { - return new CommandProcessingResultBuilder() // - .withEntityId(savedExternalAssetOwnerTransfer.getId()) // - .withEntityExternalId(savedExternalAssetOwnerTransfer.getExternalId()) // - .withSubEntityId(savedExternalAssetOwnerTransfer.getLoanId()) // - .withSubEntityExternalId(Objects.isNull(savedExternalAssetOwnerTransfer.getExternalLoanId()) ? null - : savedExternalAssetOwnerTransfer.getExternalLoanId()) // - .build(); - } - private void validateSale(ExternalAssetOwnerTransfer externalAssetOwnerTransfer, boolean isDelayedSettlementEnabled) { validateSettlementDate(externalAssetOwnerTransfer); @@ -409,48 +320,6 @@ private List getValidLoanStatusList(boolean isDelayedSettlementEnabl } } - private ExternalAssetOwnerTransfer createSaleTransfer(Long loanId, JsonElement json, ExternalId externalLoanId) { - ExternalAssetOwnerTransfer externalAssetOwnerTransfer = new ExternalAssetOwnerTransfer(); - LocalDate effectiveFrom = ThreadLocalContextUtil.getBusinessDate(); - - ExternalAssetOwner owner = getOwner(json); - externalAssetOwnerTransfer.setOwner(owner); - externalAssetOwnerTransfer.setExternalId(getTransferExternalIdFromJson(json)); - externalAssetOwnerTransfer.setStatus(PENDING); - externalAssetOwnerTransfer.setPurchasePriceRatio(getPurchasePriceRatioFromJson(json)); - externalAssetOwnerTransfer.setSettlementDate(getSettlementDateFromJson(json)); - externalAssetOwnerTransfer.setEffectiveDateFrom(effectiveFrom); - externalAssetOwnerTransfer.setEffectiveDateTo(FUTURE_DATE_9999_12_31); - externalAssetOwnerTransfer.setLoanId(loanId); - externalAssetOwnerTransfer.setExternalLoanId(externalLoanId); - externalAssetOwnerTransfer.setExternalGroupId(getTransferExternalGroupIdFromJson(json)); - - findPreviousAssetOwner(loanId).ifPresent(externalAssetOwnerTransfer::setPreviousOwner); - - return externalAssetOwnerTransfer; - } - - private ExternalAssetOwnerTransfer createIntermediarySaleTransfer(Long loanId, JsonElement json, ExternalId externalLoanId) { - ExternalAssetOwnerTransfer externalAssetOwnerTransfer = new ExternalAssetOwnerTransfer(); - LocalDate effectiveFrom = ThreadLocalContextUtil.getBusinessDate(); - - ExternalAssetOwner owner = getOwner(json); - externalAssetOwnerTransfer.setOwner(owner); - externalAssetOwnerTransfer.setExternalId(getTransferExternalIdFromJson(json)); - externalAssetOwnerTransfer.setStatus(PENDING_INTERMEDIATE); - externalAssetOwnerTransfer.setPurchasePriceRatio(getPurchasePriceRatioFromJson(json)); - externalAssetOwnerTransfer.setSettlementDate(getSettlementDateFromJson(json)); - externalAssetOwnerTransfer.setEffectiveDateFrom(effectiveFrom); - externalAssetOwnerTransfer.setEffectiveDateTo(FUTURE_DATE_9999_12_31); - externalAssetOwnerTransfer.setLoanId(loanId); - externalAssetOwnerTransfer.setExternalLoanId(externalLoanId); - externalAssetOwnerTransfer.setExternalGroupId(getTransferExternalGroupIdFromJson(json)); - - findPreviousAssetOwner(loanId).ifPresent(externalAssetOwnerTransfer::setPreviousOwner); - - return externalAssetOwnerTransfer; - } - private Optional findPreviousAssetOwner(final Long loanId) { final ExternalTransferData activeTransfer = externalAssetOwnersReadService.retrieveActiveTransferData(loanId, null, null); @@ -462,146 +331,6 @@ private Optional findPreviousAssetOwner(final Long loanId) { return Optional.empty(); } - private void validateSaleRequestBody(String apiRequestBodyAsJson) { - final Set requestParameters = new HashSet<>(Arrays.asList(ExternalTransferRequestParameters.SETTLEMENT_DATE, - ExternalTransferRequestParameters.OWNER_EXTERNAL_ID, ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, - ExternalTransferRequestParameters.TRANSFER_EXTERNAL_GROUP_ID, ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO, - ExternalTransferRequestParameters.DATEFORMAT, ExternalTransferRequestParameters.LOCALE)); - final Type typeOfMap = new TypeToken>() { - - }.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, apiRequestBodyAsJson, requestParameters); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loantransfer"); - final JsonElement json = fromApiJsonHelper.parse(apiRequestBodyAsJson); - - String ownerExternalId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID).value(ownerExternalId).notBlank() - .notExceedingLengthOf(100); - - String transferExternalId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID).value(transferExternalId).ignoreIfNull() - .notExceedingLengthOf(100); - - String purchasePriceRatio = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO).value(purchasePriceRatio).notBlank() - .notExceedingLengthOf(50); - - LocalDate settlementDate = fromApiJsonHelper.extractLocalDateNamed(ExternalTransferRequestParameters.SETTLEMENT_DATE, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.SETTLEMENT_DATE).value(settlementDate).notNull(); - - final String transferExternalGroupId = fromApiJsonHelper - .extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_GROUP_ID, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_GROUP_ID).value(transferExternalGroupId) - .ignoreIfNull().notExceedingLengthOf(100); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", - dataValidationErrors); - } - } - - private void validateIntermediarySaleRequestBody(String apiRequestBodyAsJson) { - final Set requestParameters = new HashSet<>(Arrays.asList(ExternalTransferRequestParameters.SETTLEMENT_DATE, - ExternalTransferRequestParameters.OWNER_EXTERNAL_ID, ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, - ExternalTransferRequestParameters.TRANSFER_EXTERNAL_GROUP_ID, ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO, - ExternalTransferRequestParameters.DATEFORMAT, ExternalTransferRequestParameters.LOCALE)); - final Type typeOfMap = new TypeToken>() { - - }.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, apiRequestBodyAsJson, requestParameters); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loantransfer"); - final JsonElement json = fromApiJsonHelper.parse(apiRequestBodyAsJson); - - String ownerExternalId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID).value(ownerExternalId).notBlank() - .notExceedingLengthOf(100); - - String transferExternalId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID).value(transferExternalId).ignoreIfNull() - .notExceedingLengthOf(100); - - String purchasePriceRatio = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO).value(purchasePriceRatio).notBlank() - .notExceedingLengthOf(50); - - LocalDate settlementDate = fromApiJsonHelper.extractLocalDateNamed(ExternalTransferRequestParameters.SETTLEMENT_DATE, json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.SETTLEMENT_DATE).value(settlementDate).notNull(); - - String transferExternalGroupId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_GROUP_ID, - json); - baseDataValidator.reset().parameter(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_GROUP_ID).value(transferExternalGroupId) - .ignoreIfNull().notExceedingLengthOf(100); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", - dataValidationErrors); - } - } - - private void validateBuybackRequestBody(String apiRequestBodyAsJson) { - final Set requestParameters = new HashSet<>( - Arrays.asList(ExternalTransferRequestParameters.SETTLEMENT_DATE, ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, - ExternalTransferRequestParameters.DATEFORMAT, ExternalTransferRequestParameters.LOCALE)); - final Type typeOfMap = new TypeToken>() { - - }.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, apiRequestBodyAsJson, requestParameters); - - final List 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); - return fromApiJsonHelper.extractLocalDateNamed(ExternalTransferRequestParameters.SETTLEMENT_DATE, json, dateFormat, - JsonParserHelper.localeFromString(locale)); - } - - private ExternalId getTransferExternalIdFromJson(JsonElement json) { - String transferExternalId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, json); - return StringUtils.isEmpty(transferExternalId) ? ExternalId.generate() : ExternalIdFactory.produce(transferExternalId); - } - - private ExternalId getTransferExternalGroupIdFromJson(JsonElement json) { - String transferExternalGroupId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_GROUP_ID, - json); - return StringUtils.isEmpty(transferExternalGroupId) ? null : ExternalIdFactory.produce(transferExternalGroupId); - } - - private String getPurchasePriceRatioFromJson(JsonElement json) { - return fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO, json); - } - - private ExternalAssetOwner getOwner(final JsonElement json) { - final String ownerExternalId = fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID, json); - final ExternalId externalId = ExternalIdFactory.produce(ownerExternalId); - return externalAssetOwnerRepository.findByExternalId(externalId).orElseGet(() -> { - final Long ownerId = findOrCreateOwnerId(externalId); - // getReferenceById returns a lazy proxy without hitting the DB. findById would fail - // here because the outer transaction's persistence context does not contain the entity - // committed by the inner REQUIRES_NEW transaction. - return externalAssetOwnerRepository.getReferenceById(ownerId); - }); - } - private Long findOrCreateOwnerId(final ExternalId externalId) { try { return externalAssetOwnerHelper.findOrCreateId(externalId); @@ -636,18 +365,144 @@ private List getAllowedLoanStatusesForDelayedSettlement() { } @Override - public CommandProcessingResult createExternalAssetOwner(JsonCommand command) { - externalAssetOwnerValidator.validateForCreate(command); - String ownerExternalId = command.stringValueOfParameterNamed(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID); - Optional optExternalId = externalAssetOwnerRepository - .findByExternalId(ExternalIdFactory.produce(ownerExternalId)); - if (optExternalId.isPresent()) { + @Transactional + public ExternalAssetOwnerTransferResponse saleLoan(ExternalAssetOwnerSaleRequest request) { + final LocalDate settlementDate = parseDate(request.getSettlementDate(), request.getDateFormat(), request.getLocale()); + final ExternalId transferExternalId = resolveExternalId(request.getTransferExternalId()); + final ExternalId transferExternalGroupId = resolveGroupExternalId(request.getTransferExternalGroupId()); + final LoanDataForExternalTransfer loanData = fetchAndValidateLoanDataForExternalTransfer(request.getLoanId()); + final boolean isDelayedSettlement = delayedSettlementAttributeService.isEnabled(loanData.getLoanProductId()); + validateExternalId(transferExternalId); + validateLoanStatus(loanData, isDelayedSettlement); + final ExternalAssetOwnerTransfer transfer = buildSaleTransfer(request.getLoanId(), loanData.getExternalId(), + request.getOwnerExternalId(), settlementDate, transferExternalId, transferExternalGroupId, request.getPurchasePriceRatio()); + validateSale(transfer, isDelayedSettlement); + externalAssetOwnerTransferRepository.saveAndFlush(transfer); + return toTransferResponse(transfer); + } + + @Override + @Transactional + public ExternalAssetOwnerTransferResponse intermediarySaleLoan(ExternalAssetOwnerIntermediarySaleRequest request) { + final LocalDate settlementDate = parseDate(request.getSettlementDate(), request.getDateFormat(), request.getLocale()); + final ExternalId transferExternalId = resolveExternalId(request.getTransferExternalId()); + final ExternalId transferExternalGroupId = resolveGroupExternalId(request.getTransferExternalGroupId()); + final LoanDataForExternalTransfer loanData = fetchAndValidateLoanDataForExternalTransfer(request.getLoanId()); + if (!delayedSettlementAttributeService.isEnabled(loanData.getLoanProductId())) { + throw new ExternalAssetOwnerInitiateTransferException(String.format( + "Delayed Settlement Configuration is not enabled for the loan product: %s", loanData.getLoanProductShortName())); + } + validateExternalId(transferExternalId); + validateLoanStatusIntermediarySale(loanData); + final ExternalAssetOwnerTransfer transfer = buildIntermediarySaleTransfer(request.getLoanId(), loanData.getExternalId(), + request.getOwnerExternalId(), settlementDate, transferExternalId, transferExternalGroupId, request.getPurchasePriceRatio()); + validateIntermediarySale(transfer); + externalAssetOwnerTransferRepository.saveAndFlush(transfer); + return toTransferResponse(transfer); + } + + @Override + @Transactional + public ExternalAssetOwnerTransferResponse buybackLoan(ExternalAssetOwnerBuybackRequest request) { + final LocalDate settlementDate = parseDate(request.getSettlementDate(), request.getDateFormat(), request.getLocale()); + final ExternalId transferExternalId = resolveExternalId(request.getTransferExternalId()); + final LoanDataForExternalTransfer loanData = fetchAndValidateLoanDataForExternalTransfer(request.getLoanId()); + validateSettlementDate(settlementDate); + validateExternalId(transferExternalId); + final ExternalAssetOwnerTransfer effectiveTransfer = fetchAndValidateEffectiveTransferForBuyback(loanData, settlementDate); + final ExternalAssetOwnerTransfer transfer = createBuybackTransfer(effectiveTransfer, settlementDate, transferExternalId); + externalAssetOwnerTransferRepository.saveAndFlush(transfer); + return toTransferResponse(transfer); + } + + @Override + @Transactional + public ExternalAssetOwnerTransferResponse cancelTransfer(ExternalAssetOwnerCancelRequest request) { + final ExternalAssetOwnerTransfer transfer = fetchAndValidateEffectiveTransferForCancel(request.getTransferId()); + transfer.setEffectiveDateTo(DateUtils.getBusinessLocalDate()); + final ExternalAssetOwnerTransfer cancelTransfer = createCancelTransfer(transfer); + externalAssetOwnerTransferRepository.save(cancelTransfer); + externalAssetOwnerTransferRepository.save(transfer); + return toTransferResponse(cancelTransfer); + } + + @Override + public ExternalAssetOwnerCreateResponse createOwner(ExternalAssetOwnerCreateRequest request) { + final String ownerExternalId = request.getOwnerExternalId(); + final ExternalId externalId = ExternalIdFactory.produce(ownerExternalId); + if (externalAssetOwnerRepository.findByExternalId(externalId).isPresent()) { throw new ExternalAssetOwnerDuplicateException(ownerExternalId); } + final ExternalAssetOwner owner = createAndGetAssetOwner(ownerExternalId); + return ExternalAssetOwnerCreateResponse.builder().resourceId(owner.getId()).build(); + } - final ExternalAssetOwner externalAssetOwner = createAndGetAssetOwner(ownerExternalId); - return new CommandProcessingResultBuilder() // - .withEntityId(externalAssetOwner.getId()) // - .build(); + // Helper methods + private LocalDate parseDate(String date, String dateFormat, String locale) { + if (date == null) { + return null; + } + return JsonParserHelper.convertFrom(date, "settlementDate", dateFormat != null ? dateFormat : "yyyy-MM-dd", + JsonParserHelper.localeFromString(locale != null ? locale : "en")); + } + + private ExternalId resolveExternalId(String id) { + return StringUtils.isEmpty(id) ? ExternalId.generate() : ExternalIdFactory.produce(id); + } + + private ExternalId resolveGroupExternalId(String id) { + return StringUtils.isEmpty(id) ? null : ExternalIdFactory.produce(id); + } + + private ExternalAssetOwnerTransfer buildSaleTransfer(Long loanId, ExternalId externalLoanId, String ownerExternalId, + LocalDate settlementDate, ExternalId transferExternalId, ExternalId transferExternalGroupId, String purchasePriceRatio) { + final ExternalAssetOwner owner = getOwnerByExternalId(ownerExternalId); + final ExternalAssetOwnerTransfer transfer = new ExternalAssetOwnerTransfer(); + transfer.setOwner(owner); + transfer.setExternalId(transferExternalId); + transfer.setStatus(PENDING); + transfer.setPurchasePriceRatio(purchasePriceRatio); + transfer.setSettlementDate(settlementDate); + transfer.setEffectiveDateFrom(ThreadLocalContextUtil.getBusinessDate()); + transfer.setEffectiveDateTo(FUTURE_DATE_9999_12_31); + transfer.setLoanId(loanId); + transfer.setExternalLoanId(externalLoanId); + transfer.setExternalGroupId(transferExternalGroupId); + findPreviousAssetOwner(loanId).ifPresent(transfer::setPreviousOwner); + return transfer; + } + + private ExternalAssetOwnerTransfer buildIntermediarySaleTransfer(Long loanId, ExternalId externalLoanId, String ownerExternalId, + LocalDate settlementDate, ExternalId transferExternalId, ExternalId transferExternalGroupId, String purchasePriceRatio) { + final ExternalAssetOwner owner = getOwnerByExternalId(ownerExternalId); + final ExternalAssetOwnerTransfer transfer = new ExternalAssetOwnerTransfer(); + transfer.setOwner(owner); + transfer.setExternalId(transferExternalId); + transfer.setStatus(PENDING_INTERMEDIATE); + transfer.setPurchasePriceRatio(purchasePriceRatio); + transfer.setSettlementDate(settlementDate); + transfer.setEffectiveDateFrom(ThreadLocalContextUtil.getBusinessDate()); + transfer.setEffectiveDateTo(FUTURE_DATE_9999_12_31); + transfer.setLoanId(loanId); + transfer.setExternalLoanId(externalLoanId); + transfer.setExternalGroupId(transferExternalGroupId); + findPreviousAssetOwner(loanId).ifPresent(transfer::setPreviousOwner); + return transfer; + } + + private ExternalAssetOwner getOwnerByExternalId(String ownerExternalId) { + final ExternalId externalId = ExternalIdFactory.produce(ownerExternalId); + return externalAssetOwnerRepository.findByExternalId(externalId).orElseGet(() -> { + final Long ownerId = findOrCreateOwnerId(externalId); + return externalAssetOwnerRepository.getReferenceById(ownerId); + }); } + + private ExternalAssetOwnerTransferResponse toTransferResponse(ExternalAssetOwnerTransfer transfer) { + return ExternalAssetOwnerTransferResponse.builder().resourceId(transfer.getId()) + .resourceExternalId(transfer.getExternalId() != null ? transfer.getExternalId().getValue() : null) + .subResourceId(transfer.getLoanId()) + .subResourceExternalId(transfer.getExternalLoanId() != null ? transfer.getExternalLoanId().getValue() : null).build(); + } + } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/IntermediarySaleToExternalAssetOwnerHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/IntermediarySaleToExternalAssetOwnerHandler.java index 9c41b5bd3b5..4fe531581bc 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/IntermediarySaleToExternalAssetOwnerHandler.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/IntermediarySaleToExternalAssetOwnerHandler.java @@ -18,23 +18,35 @@ */ package org.apache.fineract.investor.service; +import io.github.resilience4j.retry.annotation.Retry; 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; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerIntermediarySaleRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +@Slf4j +@Component @RequiredArgsConstructor -@Service -@CommandType(entity = "LOAN", action = "INTERMEDIARYSALE") -public class IntermediarySaleToExternalAssetOwnerHandler implements NewCommandSourceHandler { +public class IntermediarySaleToExternalAssetOwnerHandler + implements CommandHandler { private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService; + private final InvestorCommandValidationService validationService; + @Retry(name = "commandExternalAssetOwnerIntermediarySale", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return externalAssetOwnersWriteService.intermediarySaleLoanByLoanId(command); + @Transactional + public ExternalAssetOwnerTransferResponse handle(Command command) { + validationService.validate(command.getPayload()); + return externalAssetOwnersWriteService.intermediarySaleLoan(command.getPayload()); } + @Override + public ExternalAssetOwnerTransferResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CancelLoanFromExternalAssetOwnerHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/InvestorCommandValidationService.java similarity index 55% rename from fineract-investor/src/main/java/org/apache/fineract/investor/service/CancelLoanFromExternalAssetOwnerHandler.java rename to fineract-investor/src/main/java/org/apache/fineract/investor/service/InvestorCommandValidationService.java index 7e40e368295..5757f1bcdf0 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/CancelLoanFromExternalAssetOwnerHandler.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/InvestorCommandValidationService.java @@ -18,22 +18,21 @@ */ package org.apache.fineract.investor.service; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; 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; +import org.springframework.stereotype.Component; +@Component @RequiredArgsConstructor -@Service -@CommandType(entity = "ASSET_OWNER_TRANSACTION", action = "CANCEL") -public class CancelLoanFromExternalAssetOwnerHandler implements NewCommandSourceHandler { +public class InvestorCommandValidationService { - private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService; + private final Validator validator; - @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return externalAssetOwnersWriteService.cancelTransactionById(command); + public void validate(T payload) { + final var violations = validator.validate(payload); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/SaleLoanToExternalAssetOwnerHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/SaleLoanToExternalAssetOwnerHandler.java index 39c56a1ef1e..f9c4fe627d5 100644 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/SaleLoanToExternalAssetOwnerHandler.java +++ b/fineract-investor/src/main/java/org/apache/fineract/investor/service/SaleLoanToExternalAssetOwnerHandler.java @@ -18,22 +18,35 @@ */ package org.apache.fineract.investor.service; +import io.github.resilience4j.retry.annotation.Retry; 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; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerSaleRequest; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +@Slf4j +@Component @RequiredArgsConstructor -@Service -@CommandType(entity = "LOAN", action = "SALE") -public class SaleLoanToExternalAssetOwnerHandler implements NewCommandSourceHandler { +public class SaleLoanToExternalAssetOwnerHandler + implements CommandHandler { private final ExternalAssetOwnersWriteService externalAssetOwnersWriteService; + private final InvestorCommandValidationService validationService; + @Retry(name = "commandExternalAssetOwnerSale", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return externalAssetOwnersWriteService.saleLoanByLoanId(command); + @Transactional + public ExternalAssetOwnerTransferResponse handle(Command command) { + validationService.validate(command.getPayload()); + return externalAssetOwnersWriteService.saleLoan(command.getPayload()); + } + + @Override + public ExternalAssetOwnerTransferResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/service/UpdateExternalAssetOwnerLoanProductAttributeHandler.java b/fineract-investor/src/main/java/org/apache/fineract/investor/service/UpdateExternalAssetOwnerLoanProductAttributeHandler.java deleted file mode 100644 index 08cc47b459d..00000000000 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/service/UpdateExternalAssetOwnerLoanProductAttributeHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * 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 com.google.gson.JsonElement; -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.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeRequestParameters; -import org.springframework.stereotype.Service; - -@RequiredArgsConstructor -@Service -@CommandType(entity = "EXTERNAL_ASSET_OWNER_LOAN_PRODUCT_ATTRIBUTE", action = "UPDATE") -public class UpdateExternalAssetOwnerLoanProductAttributeHandler implements NewCommandSourceHandler { - - private final FromJsonHelper fromApiJsonHelper; - private final ExternalAssetOwnerLoanProductAttributesWriteService externalAssetOwnerLoanProductAttributesWriteService; - - @Override - public CommandProcessingResult processCommand(JsonCommand command) { - final JsonElement json = fromApiJsonHelper.parse(command.json()); - String attributeKey = fromApiJsonHelper.extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY, - json); - String attributeValue = fromApiJsonHelper - .extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE, json); - return externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command, attributeKey, - attributeValue); - } -} diff --git a/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImplTest.java b/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImplTest.java index 32020227548..eda20a9b5ca 100644 --- a/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImplTest.java +++ b/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesWriteServiceImplTest.java @@ -35,6 +35,8 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.investor.data.ExternalAssetOwnerLoanProductAttributeRequestParameters; +import org.apache.fineract.investor.data.request.PostExternalAssetOwnerLoanProductAttributeRequest; +import org.apache.fineract.investor.data.request.PutExternalAssetOwnerLoanProductAttributeRequest; import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes; import org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributesRepository; import org.apache.fineract.investor.exception.ExternalAssetOwnerLoanProductAttributeAlreadyExistsException; @@ -74,7 +76,7 @@ public void testCreateExternalAssetOwnerLoanProductAttributeHappyPath() { when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(true); // when - testContext.externalAssetOwnerLoanProductAttributesWriteService.createExternalAssetOwnerLoanProductAttribute(command); + createExternalAssetOwnerLoanProductAttribute(testContext, command); // then verify(testContext.externalAssetOwnerLoanProductAttributesRepository).existsByLoanProductIdAndKey(any(), any()); @@ -101,8 +103,7 @@ public void testUpdateExternalAssetOwnerLoanProductAttributeHappyPath() { when(testContext.externalAssetOwnerLoanProductAttributesRepository.findById(command.entityId())) .thenReturn(Optional.of(attributeInDB)); - testContext.externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command, - testContext.attributeKey, testContext.attributeValue); + updateExternalAssetOwnerLoanProductAttribute(testContext, command); // then verify(testContext.loanProductRepository).existsById(testContext.loanProductId); @@ -128,8 +129,7 @@ public void testUpdateExternalAssetOwnerLoanProductAttributeUpdateNotRequired() when(testContext.externalAssetOwnerLoanProductAttributesRepository.findById(command.entityId())) .thenReturn(Optional.of(attributeInDB)); - testContext.externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command, - testContext.attributeKey, testContext.attributeValue); + updateExternalAssetOwnerLoanProductAttribute(testContext, command); // then verify(testContext.loanProductRepository).existsById(testContext.loanProductId); @@ -151,8 +151,7 @@ public void testUpdateExternalAssetOwnerLoanProductAttributeOnAttributeThatDoesN ExternalAssetOwnerLoanProductAttributeNotFoundException thrownException = assertThrows( ExternalAssetOwnerLoanProductAttributeNotFoundException.class, - () -> testContext.externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command, - testContext.attributeKey, testContext.attributeValue)); + () -> updateExternalAssetOwnerLoanProductAttribute(testContext, command)); // then verify(testContext.loanProductRepository).existsById(testContext.loanProductId); @@ -182,8 +181,7 @@ public void testUpdateExternalAssetOwnerLoanProductAttributeOnAttributeWithDiffe ExternalAssetOwnerLoanProductAttributesException thrownException = assertThrows( ExternalAssetOwnerLoanProductAttributesException.class, - () -> testContext.externalAssetOwnerLoanProductAttributesWriteService.updateExternalAssetOwnerLoanProductAttribute(command, - testContext.attributeKey, testContext.attributeValue)); + () -> updateExternalAssetOwnerLoanProductAttribute(testContext, command)); // then verify(testContext.loanProductRepository).existsById(testContext.loanProductId); @@ -211,7 +209,7 @@ public void testCreateExternalAssetOwnerLoanProductAttributeUsingDefaultSettleme testContext.setAttributeValue("DEFAULT_SETTLEMENT"); // when - testContext.externalAssetOwnerLoanProductAttributesWriteService.createExternalAssetOwnerLoanProductAttribute(command); + createExternalAssetOwnerLoanProductAttribute(testContext, command); // then verify(testContext.externalAssetOwnerLoanProductAttributesRepository).existsByLoanProductIdAndKey(any(), any()); @@ -233,8 +231,7 @@ public void testExternalAssetOwnerLoanProductAttributeRequestWithApiDataValidati jsonCommandElement)).thenReturn(attributeValue); PlatformApiDataValidationException thrownException = assertThrows(PlatformApiDataValidationException.class, - () -> testContext.externalAssetOwnerLoanProductAttributesWriteService - .createExternalAssetOwnerLoanProductAttribute(command)); + () -> createExternalAssetOwnerLoanProductAttribute(testContext, command)); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any()); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any()); @@ -250,8 +247,7 @@ public void testCreateLoanProductAttributeExternalAssetOwnerExternalAssetOwnerLo when(testContext.loanProductRepository.existsById(testContext.loanProductId)).thenReturn(false); LoanProductNotFoundException thrownException = assertThrows(LoanProductNotFoundException.class, - () -> testContext.externalAssetOwnerLoanProductAttributesWriteService - .createExternalAssetOwnerLoanProductAttribute(command)); + () -> createExternalAssetOwnerLoanProductAttribute(testContext, command)); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any()); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any()); @@ -271,8 +267,7 @@ public void testCreateLoanProductAttributeExternalAssetOwnerExternalAssetOwnerLo ExternalAssetOwnerLoanProductAttributeAlreadyExistsException thrownException = assertThrows( ExternalAssetOwnerLoanProductAttributeAlreadyExistsException.class, - () -> testContext.externalAssetOwnerLoanProductAttributesWriteService - .createExternalAssetOwnerLoanProductAttribute(command)); + () -> createExternalAssetOwnerLoanProductAttribute(testContext, command)); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any()); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(1)).existsByLoanProductIdAndKey(any(), any()); @@ -292,8 +287,7 @@ public void testExternalAssetOwnerLoanProductAttributeInvalidKey() { jsonCommandElement)).thenReturn("BAD_KEY"); ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException thrownException = assertThrows( ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException.class, - () -> testContext.externalAssetOwnerLoanProductAttributesWriteService - .createExternalAssetOwnerLoanProductAttribute(command)); + () -> createExternalAssetOwnerLoanProductAttribute(testContext, command)); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any()); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any()); @@ -312,8 +306,7 @@ public void testExternalAssetOwnerLoanProductAttributeInvalidValue() { jsonCommandElement)).thenReturn("BAD_VALUE"); ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException thrownException = assertThrows( ExternalAssetOwnerLoanProductAttributeInvalidSettlementAttributeException.class, - () -> testContext.externalAssetOwnerLoanProductAttributesWriteService - .createExternalAssetOwnerLoanProductAttribute(command)); + () -> createExternalAssetOwnerLoanProductAttribute(testContext, command)); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).saveAndFlush(any()); verify(testContext.externalAssetOwnerLoanProductAttributesRepository, times(0)).existsByLoanProductIdAndKey(any(), any()); @@ -334,6 +327,44 @@ private void assertLoanProductAttributeValues(final TestContext testContext, Assertions.assertEquals(testContext.attributeValue, loanProductAttribute.getAttributeValue()); } + private void createExternalAssetOwnerLoanProductAttribute(final TestContext testContext, final JsonCommand command) { + testContext.externalAssetOwnerLoanProductAttributesWriteService + .createExternalAssetOwnerLoanProductAttribute(createPostRequest(testContext, command)); + } + + private void updateExternalAssetOwnerLoanProductAttribute(final TestContext testContext, final JsonCommand command) { + testContext.externalAssetOwnerLoanProductAttributesWriteService + .updateExternalAssetOwnerLoanProductAttribute(createPutRequest(testContext, command)); + } + + private PostExternalAssetOwnerLoanProductAttributeRequest createPostRequest(final TestContext testContext, final JsonCommand command) { + final JsonElement jsonCommandElement = testContext.fromApiJsonHelper.parse(command.json()); + final String attributeKey = testContext.fromApiJsonHelper + .extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY, jsonCommandElement); + final String attributeValue = testContext.fromApiJsonHelper + .extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE, jsonCommandElement); + validateAttributeRequest(attributeKey, attributeValue); + return PostExternalAssetOwnerLoanProductAttributeRequest.builder().loanProductId(command.getProductId()).attributeKey(attributeKey) + .attributeValue(attributeValue).build(); + } + + private PutExternalAssetOwnerLoanProductAttributeRequest createPutRequest(final TestContext testContext, final JsonCommand command) { + final JsonElement jsonCommandElement = testContext.fromApiJsonHelper.parse(command.json()); + final String attributeKey = testContext.fromApiJsonHelper + .extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_KEY, jsonCommandElement); + final String attributeValue = testContext.fromApiJsonHelper + .extractStringNamed(ExternalAssetOwnerLoanProductAttributeRequestParameters.ATTRIBUTE_VALUE, jsonCommandElement); + validateAttributeRequest(attributeKey, attributeValue); + return PutExternalAssetOwnerLoanProductAttributeRequest.builder().loanProductId(command.getProductId()) + .attributeId(command.entityId()).attributeKey(attributeKey).attributeValue(attributeValue).build(); + } + + private void validateAttributeRequest(final String attributeKey, final String attributeValue) { + if (attributeKey == null || attributeKey.isBlank() || attributeValue == null || attributeValue.isBlank()) { + throw new PlatformApiDataValidationException(java.util.List.of()); + } + } + /** * Helper method to create {@link JsonCommand} object from json command string. * diff --git a/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceTest.java b/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceTest.java index 0646ad4e8c7..901d38acb05 100644 --- a/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceTest.java +++ b/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnersWriteServiceTest.java @@ -36,6 +36,8 @@ import com.google.gson.JsonElement; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; import java.math.BigDecimal; import java.math.RoundingMode; import java.sql.SQLException; @@ -52,14 +54,17 @@ import org.apache.commons.lang3.RandomStringUtils; import org.apache.fineract.cob.data.LoanDataForExternalTransfer; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.domain.ExternalId; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.apache.fineract.investor.data.ExternalAssetOwnerTransferResponse; import org.apache.fineract.investor.data.ExternalTransferRequestParameters; import org.apache.fineract.investor.data.ExternalTransferStatus; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerBuybackRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerIntermediarySaleRequest; +import org.apache.fineract.investor.data.request.ExternalAssetOwnerSaleRequest; import org.apache.fineract.investor.domain.ExternalAssetOwner; import org.apache.fineract.investor.domain.ExternalAssetOwnerRepository; import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer; @@ -102,7 +107,6 @@ public void testIntermediarySaleLoanByLoanIdHappyPath() { .forClass(ExternalAssetOwnerTransfer.class); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -111,7 +115,7 @@ public void testIntermediarySaleLoanByLoanIdHappyPath() { when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(true); // when - testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoanByLoanId(command); + intermediarySaleLoanByLoanId(testContext); // then verify(testContext.externalAssetOwnerTransferRepository).saveAndFlush(externalAssetOwnerTransferArgumentCaptor.capture()); @@ -128,7 +132,6 @@ public void testIntermediarySaleLoanByLoanIdDelayedSettlementIsNotEnabled() { TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -136,7 +139,7 @@ public void testIntermediarySaleLoanByLoanIdDelayedSettlementIsNotEnabled() { // when ExternalAssetOwnerInitiateTransferException thrownException = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoan(createIntermediarySaleRequest(testContext))); // then verify(testContext.externalAssetOwnerTransferRepository, times(0)).saveAndFlush(any(ExternalAssetOwnerTransfer.class)); @@ -154,7 +157,6 @@ public void testValidateEffectiveTransferForIntermediarySale(final String testNa TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -164,7 +166,7 @@ public void testValidateEffectiveTransferForIntermediarySale(final String testNa // when ExternalAssetOwnerInitiateTransferException thrownException = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoan(createIntermediarySaleRequest(testContext))); // then verify(testContext.externalAssetOwnerTransferRepository, times(0)).saveAndFlush(any(ExternalAssetOwnerTransfer.class)); @@ -182,7 +184,6 @@ public void testValidateValidActiveLoanStatus(final String testName, final LoanS .forClass(ExternalAssetOwnerTransfer.class); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -192,7 +193,7 @@ public void testValidateValidActiveLoanStatus(final String testName, final LoanS when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(true); // when - testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoanByLoanId(command); + intermediarySaleLoanByLoanId(testContext); // then verify(testContext.externalAssetOwnerTransferRepository).saveAndFlush(externalAssetOwnerTransferArgumentCaptor.capture()); @@ -210,7 +211,6 @@ public void testValidateInvalidActiveLoanStatus(final String testName, final Loa final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanDataForExternalTransfer.getLoanStatus()).thenReturn(loanStatus); when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(true); @@ -219,12 +219,11 @@ public void testValidateInvalidActiveLoanStatus(final String testName, final Loa // when ExternalAssetOwnerInitiateTransferException exception = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoan(createIntermediarySaleRequest(testContext))); assertEquals(exception.getMessage(), String.format("Loan status %s is not valid for transfer.", loanStatus.name())); // then - verify(testContext.fromApiJsonHelper, times(2)).parse(command.json()); verify(testContext.loanRepository, times(1)).findLoanDataForExternalTransferByLoanId(testContext.loanId); verify(testContext.delayedSettlementAttributeService).isEnabled(testContext.loanProductId); verify(testContext.externalAssetOwnerTransferRepository, times(1)).exists(any(Specification.class)); @@ -243,7 +242,6 @@ public void testValidateValidDelayedSettlementLoanStatus(final String testName, .forClass(ExternalAssetOwnerTransfer.class); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanDataForExternalTransfer.getLoanStatus()).thenReturn(loanStatus); when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(true); @@ -253,7 +251,7 @@ public void testValidateValidDelayedSettlementLoanStatus(final String testName, any(LocalDate.class))).thenReturn(assetOwnerTransfers); // when - CommandProcessingResult result = testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command); + CommandProcessingResult result = saleLoanByLoanId(testContext); // then verify(testContext.externalAssetOwnerRepository).findByExternalId(any(ExternalId.class)); @@ -279,7 +277,6 @@ public void testValidateInvalidDelayedSettlementLoanStatus(final String testName final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanDataForExternalTransfer.getLoanStatus()).thenReturn(loanStatus); when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(true); @@ -288,12 +285,11 @@ public void testValidateInvalidDelayedSettlementLoanStatus(final String testName // when ExternalAssetOwnerInitiateTransferException exception = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoan(createSaleRequest(testContext))); assertEquals(exception.getMessage(), String.format("Loan status %s is not valid for transfer.", loanStatus.name())); // then - verify(testContext.fromApiJsonHelper, times(2)).parse(command.json()); verify(testContext.loanRepository, times(1)).findLoanDataForExternalTransferByLoanId(testContext.loanId); verify(testContext.delayedSettlementAttributeService).isEnabled(testContext.loanProductId); verify(testContext.externalAssetOwnerTransferRepository, times(1)).exists(any(Specification.class)); @@ -309,7 +305,6 @@ public void verifyWhenLoanSaleIsInitiatedThenAssetOwnerTransferIsCreated( .forClass(ExternalAssetOwnerTransfer.class); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(isDelayedSettlementEnabled); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) @@ -318,7 +313,7 @@ public void verifyWhenLoanSaleIsInitiatedThenAssetOwnerTransferIsCreated( any(LocalDate.class))).thenReturn(externalAssetOwnerTransferList); // when - CommandProcessingResult result = testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command); + CommandProcessingResult result = saleLoanByLoanId(testContext); // then verify(testContext.externalAssetOwnerRepository).findByExternalId(any(ExternalId.class)); @@ -341,18 +336,10 @@ public void verifyWhenLoanSaleIsInitiatedThenAssetOwnerTransferIsCreated( @Test public void validateSettlementDateInThePastTest() { TestContext testContext = new TestContext(); - final JsonElement jsonCommandElement = testContext.fromJsonHelper.parse(testContext.jsonCommand); ArgumentCaptor externalAssetOwnerTransferArgumentCaptor = ArgumentCaptor .forClass(ExternalAssetOwnerTransfer.class); - lenient().when( - testContext.fromApiJsonHelper.extractLocalDateNamed(ExternalTransferRequestParameters.SETTLEMENT_DATE, jsonCommandElement)) - .thenReturn(LocalDate.EPOCH); - lenient().when(testContext.fromApiJsonHelper.extractLocalDateNamed(ExternalTransferRequestParameters.SETTLEMENT_DATE, - jsonCommandElement, TestContext.DATE_FORMAT, Locale.GERMANY)).thenReturn(LocalDate.EPOCH); - // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -360,7 +347,8 @@ public void validateSettlementDateInThePastTest() { // when ExternalAssetOwnerInitiateTransferException thrownException = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.intermediarySaleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl + .intermediarySaleLoan(createIntermediarySaleRequest(testContext, LocalDate.EPOCH))); // then verify(testContext.externalAssetOwnerTransferRepository, times(0)).saveAndFlush(externalAssetOwnerTransferArgumentCaptor.capture()); @@ -435,7 +423,6 @@ public void verifyWhenLoanSaleIsInitiatedWithoutOwnerThenAssetOwnerTransferIsCre .forClass(ExternalAssetOwnerTransfer.class); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(false); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) @@ -445,7 +432,7 @@ public void verifyWhenLoanSaleIsInitiatedWithoutOwnerThenAssetOwnerTransferIsCre when(testContext.externalAssetOwnerRepository.getReferenceById(42L)).thenReturn(testContext.externalAssetOwner); // when - CommandProcessingResult result = testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command); + CommandProcessingResult result = saleLoanByLoanId(testContext); // then verify(testContext.externalAssetOwnerRepository).findByExternalId(any(ExternalId.class)); @@ -472,7 +459,6 @@ public void verifyWhenOwnerCreationHitsConstraintViolationWithJpaSystemException final ArgumentCaptor transferCaptor = ArgumentCaptor.forClass(ExternalAssetOwnerTransfer.class); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); final SQLException sqlException = new SQLException("Duplicate entry", "23505"); final JpaSystemException jpaException = new JpaSystemException(new RuntimeException(sqlException)); @@ -485,7 +471,7 @@ public void verifyWhenOwnerCreationHitsConstraintViolationWithJpaSystemException when(testContext.externalAssetOwnerRepository.getReferenceById(99L)).thenReturn(testContext.externalAssetOwner); // when - CommandProcessingResult result = testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command); + CommandProcessingResult result = saleLoanByLoanId(testContext); // then verify(testContext.externalAssetOwnerHelper, times(2)).findOrCreateId(any(ExternalId.class)); @@ -503,7 +489,6 @@ public void verifyWhenOwnerCreationHitsConstraintViolationWithDataIntegrityViola final ArgumentCaptor transferCaptor = ArgumentCaptor.forClass(ExternalAssetOwnerTransfer.class); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); final SQLException sqlException = new SQLException("Duplicate entry", "23000"); final DataIntegrityViolationException diveException = new DataIntegrityViolationException("Duplicate", sqlException); @@ -516,7 +501,7 @@ public void verifyWhenOwnerCreationHitsConstraintViolationWithDataIntegrityViola when(testContext.externalAssetOwnerRepository.getReferenceById(99L)).thenReturn(testContext.externalAssetOwner); // when - CommandProcessingResult result = testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command); + CommandProcessingResult result = saleLoanByLoanId(testContext); // then verify(testContext.externalAssetOwnerHelper, times(2)).findOrCreateId(any(ExternalId.class)); @@ -533,7 +518,6 @@ public void verifyWhenOwnerCreationThrowsNonConstraintJpaSystemExceptionThenExce final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); final JpaSystemException jpaException = new JpaSystemException(new RuntimeException("Connection lost")); @@ -544,24 +528,43 @@ public void verifyWhenOwnerCreationThrowsNonConstraintJpaSystemExceptionThenExce when(testContext.externalAssetOwnerHelper.findOrCreateId(any(ExternalId.class))).thenThrow(jpaException); // when & then - assertThrows(JpaSystemException.class, () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + assertThrows(JpaSystemException.class, + () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoan(createSaleRequest(testContext))); verify(testContext.externalAssetOwnerHelper, times(1)).findOrCreateId(any(ExternalId.class)); } + private ExternalAssetOwnerSaleRequest createSaleRequest(final TestContext testContext) { + return ExternalAssetOwnerSaleRequest.builder().loanId(testContext.loanId).ownerExternalId(testContext.ownerExternalId) + .transferExternalId(testContext.transferExternalId).transferExternalGroupId(testContext.transferExternalGroupId) + .purchasePriceRatio(TestContext.PURCHASE_RATIO.toString()).settlementDate(testContext.settlementDate.toString()) + .dateFormat(TestContext.DATE_FORMAT).locale(TestContext.LOCALE).build(); + } + + private ExternalAssetOwnerIntermediarySaleRequest createIntermediarySaleRequest(final TestContext testContext) { + return createIntermediarySaleRequest(testContext, testContext.settlementDate); + } + + private ExternalAssetOwnerIntermediarySaleRequest createIntermediarySaleRequest(final TestContext testContext, + final LocalDate settlementDate) { + return ExternalAssetOwnerIntermediarySaleRequest.builder().loanId(testContext.loanId).ownerExternalId(testContext.ownerExternalId) + .transferExternalId(testContext.transferExternalId).transferExternalGroupId(testContext.transferExternalGroupId) + .purchasePriceRatio(TestContext.PURCHASE_RATIO.toString()).settlementDate(settlementDate.toString()) + .dateFormat(TestContext.DATE_FORMAT).locale(TestContext.LOCALE).build(); + } + @Test public void verifyWhenLoanIsNotFoundThenExceptionIsThrown() { final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)).thenReturn(Optional.empty()); // when - assertThrows(LoanNotFoundException.class, () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + assertThrows(LoanNotFoundException.class, + () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoan(createSaleRequest(testContext))); // then - verify(testContext.fromApiJsonHelper, times(1)).parse(command.json()); verifyNoMoreInteractions(testContext.loanRepository); verifyNoInteractions(testContext.externalAssetOwnerRepository, testContext.externalAssetOwnerTransferRepository, testContext.delayedSettlementAttributeService); @@ -572,60 +575,26 @@ public void verifyWhenLoanIsNotFoundThenExceptionIsThrown() { public void verifyWhenFieldValueInvalidThenExceptionIsThrown(final String ownerExternalId, final String transferExternalId, final String purchaseRatio, final LocalDate settlementDate) { final TestContext testContext = new TestContext(); + final InvestorCommandValidationService validationService = new InvestorCommandValidationService( + Validation.buildDefaultValidatorFactory().getValidator()); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); - final JsonElement jsonCommandElement = testContext.fromJsonHelper.parse(testContext.jsonCommand); - - when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(false); - when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) - .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); - when(testContext.fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.OWNER_EXTERNAL_ID, jsonCommandElement)) - .thenReturn(ownerExternalId); - when(testContext.fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.TRANSFER_EXTERNAL_ID, jsonCommandElement)) - .thenReturn(transferExternalId); - when(testContext.fromApiJsonHelper.extractStringNamed(ExternalTransferRequestParameters.PURCHASE_PRICE_RATIO, jsonCommandElement)) - .thenReturn(purchaseRatio); - when(testContext.fromApiJsonHelper.extractLocalDateNamed(ExternalTransferRequestParameters.SETTLEMENT_DATE, jsonCommandElement)) - .thenReturn(settlementDate); + final ExternalAssetOwnerSaleRequest request = ExternalAssetOwnerSaleRequest.builder().loanId(testContext.loanId) + .ownerExternalId(ownerExternalId).transferExternalId(transferExternalId).purchasePriceRatio(purchaseRatio) + .settlementDate(settlementDate != null ? settlementDate.toString() : null).dateFormat(TestContext.DATE_FORMAT) + .locale(TestContext.LOCALE).build(); - // when - assertThrows(PlatformApiDataValidationException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + // when & then + assertThrows(ConstraintViolationException.class, () -> validationService.validate(request)); - // then - verify(testContext.fromApiJsonHelper, times(2)).parse(command.json()); - verifyNoMoreInteractions(testContext.loanRepository); - verify(testContext.delayedSettlementAttributeService).isEnabled(testContext.loanProductId); verifyNoInteractions(testContext.externalAssetOwnerRepository, testContext.externalAssetOwnerTransferRepository); } - private static Stream invalidFieldsDataProvider() { - // ownerExternalId, transferExternalId, purchaseRatio, settlementDate - return Stream.of( - // settlement date cannot be null - Arguments.of("value", "value", "value", null), - // purchaseRatio cannot be null - Arguments.of("value", "value", null, LocalDate.now(ZoneId.systemDefault()).plusDays(1)), - // purchaseRatio length cannot be > 50 - Arguments.of("value", "value", RandomStringUtils.randomAlphanumeric(51), LocalDate.now(ZoneId.systemDefault()).plusDays(1)), - // transferExternalId length cannot be > 100 - Arguments.of("value", RandomStringUtils.randomAlphanumeric(101), "value", - LocalDate.now(ZoneId.systemDefault()).plusDays(1)), - // ownerExternalId cannot be null - Arguments.of(null, "value", "value", LocalDate.now(ZoneId.systemDefault()).plusDays(1)), - // ownerExternalId length cannot be > 100 - Arguments.of(RandomStringUtils.randomAlphanumeric(101), "value", "value", - LocalDate.now(ZoneId.systemDefault()).plusDays(1))); - } - @Test public void verifyWhenTransferExternalIdExistsThenExceptionIsThrown() { final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); - when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(false); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -633,10 +602,9 @@ public void verifyWhenTransferExternalIdExistsThenExceptionIsThrown() { // when assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoan(createSaleRequest(testContext))); // then - verify(testContext.fromApiJsonHelper, times(2)).parse(command.json()); verify(testContext.loanRepository, times(1)).findLoanDataForExternalTransferByLoanId(testContext.loanId); verify(testContext.delayedSettlementAttributeService).isEnabled(testContext.loanProductId); verify(testContext.externalAssetOwnerTransferRepository, times(1)).exists(any(Specification.class)); @@ -649,8 +617,6 @@ public void verifyWhenTooManyEffectiveTransfersThenExceptionIsThrown(final boole final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); - when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(isDelayedSettlementEnabled); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -659,12 +625,11 @@ public void verifyWhenTooManyEffectiveTransfersThenExceptionIsThrown(final boole // when ExternalAssetOwnerInitiateTransferException exception = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoan(createSaleRequest(testContext))); assertEquals("This loan cannot be sold, there is already an in progress transfer", exception.getMessage()); // then - verify(testContext.fromApiJsonHelper, times(2)).parse(command.json()); verify(testContext.loanRepository).findLoanDataForExternalTransferByLoanId(testContext.loanId); verify(testContext.delayedSettlementAttributeService).isEnabled(testContext.loanProductId); verify(testContext.externalAssetOwnerTransferRepository).exists(any(Specification.class)); @@ -673,17 +638,11 @@ public void verifyWhenTooManyEffectiveTransfersThenExceptionIsThrown(final boole verify(testContext.externalAssetOwnerRepository).findByExternalId(any(ExternalId.class)); } - private static Stream delayedSettlementFlagDataProvider() { - return Stream.of(Arguments.of(false), Arguments.of(true)); - } - @Test public void verifyWhenNoEffectiveTransfersWithDelayedSettlementThenExceptionIsThrown() { final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); - when(testContext.delayedSettlementAttributeService.isEnabled(testContext.loanProductId)).thenReturn(true); when(testContext.loanRepository.findLoanDataForExternalTransferByLoanId(testContext.loanId)) .thenReturn(Optional.of(testContext.loanDataForExternalTransfer)); @@ -692,11 +651,11 @@ public void verifyWhenNoEffectiveTransfersWithDelayedSettlementThenExceptionIsTh // when ExternalAssetOwnerInitiateTransferException exception = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoan(createSaleRequest(testContext))); assertEquals("This loan cannot be sold, no effective transfer found.", exception.getMessage()); + // then - verify(testContext.fromApiJsonHelper, times(2)).parse(command.json()); verify(testContext.loanRepository).findLoanDataForExternalTransferByLoanId(testContext.loanId); verify(testContext.delayedSettlementAttributeService).isEnabled(testContext.loanProductId); verify(testContext.externalAssetOwnerTransferRepository).exists(any(Specification.class)); @@ -705,6 +664,38 @@ public void verifyWhenNoEffectiveTransfersWithDelayedSettlementThenExceptionIsTh verify(testContext.externalAssetOwnerRepository).findByExternalId(any(ExternalId.class)); } + static Stream invalidFieldsDataProvider() { + return Stream.of(Arguments.of("value", "value", "value", null), + Arguments.of("value", "value", null, LocalDate.now(ZoneId.systemDefault()).plusDays(1)), + Arguments.of("value", "value", RandomStringUtils.randomAlphanumeric(51), LocalDate.now(ZoneId.systemDefault()).plusDays(1)), + Arguments.of("value", RandomStringUtils.randomAlphanumeric(101), "value", + LocalDate.now(ZoneId.systemDefault()).plusDays(1)), + Arguments.of(null, "value", "value", LocalDate.now(ZoneId.systemDefault()).plusDays(1)), Arguments.of( + RandomStringUtils.randomAlphanumeric(101), "value", "value", LocalDate.now(ZoneId.systemDefault()).plusDays(1))); + } + + static Stream delayedSettlementFlagDataProvider() { + return Stream.of(Arguments.of(false), Arguments.of(true)); + } + + static Stream invalidTransferStatusDataProvider() { + return Stream.of( + Arguments.of(ExternalTransferStatus.PENDING, false, + "External asset owner transfer is already in PENDING state for this loan"), + Arguments.of(ExternalTransferStatus.PENDING_INTERMEDIATE, true, + "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), + Arguments.of(ExternalTransferStatus.ACTIVE, true, + "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), + Arguments.of(ExternalTransferStatus.DECLINED, true, + "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), + Arguments.of(ExternalTransferStatus.PENDING, true, + "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), + Arguments.of(ExternalTransferStatus.BUYBACK, true, + "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), + Arguments.of(ExternalTransferStatus.CANCELLED, true, + "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state.")); + } + @ParameterizedTest @MethodSource("invalidTransferStatusDataProvider") public void verifyWhenInvalidTransferStatusThenExceptionIsThrown(final ExternalTransferStatus externalTransferStatus, @@ -712,7 +703,6 @@ public void verifyWhenInvalidTransferStatusThenExceptionIsThrown(final ExternalT final TestContext testContext = new TestContext(); // given - final JsonCommand command = createJsonCommand(testContext.jsonCommand, testContext.loanId); final ExternalAssetOwnerTransfer externalAssetOwnerTransfer = new ExternalAssetOwnerTransfer(); externalAssetOwnerTransfer.setStatus(externalTransferStatus); @@ -724,12 +714,11 @@ public void verifyWhenInvalidTransferStatusThenExceptionIsThrown(final ExternalT // when ExternalAssetOwnerInitiateTransferException exception = assertThrows(ExternalAssetOwnerInitiateTransferException.class, - () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoanByLoanId(command)); + () -> testContext.externalAssetOwnersWriteServiceImpl.saleLoan(createSaleRequest(testContext))); assertEquals(exception.getMessage(), expectedExceptionMessage); // then - verify(testContext.fromApiJsonHelper, times(2)).parse(command.json()); verify(testContext.loanRepository).findLoanDataForExternalTransferByLoanId(testContext.loanId); verify(testContext.delayedSettlementAttributeService).isEnabled(testContext.loanProductId); verify(testContext.externalAssetOwnerTransferRepository).exists(any(Specification.class)); @@ -738,24 +727,6 @@ public void verifyWhenInvalidTransferStatusThenExceptionIsThrown(final ExternalT verify(testContext.externalAssetOwnerRepository).findByExternalId(any(ExternalId.class)); } - private static Stream invalidTransferStatusDataProvider() { - return Stream.of( - Arguments.of(ExternalTransferStatus.PENDING, false, - "External asset owner transfer is already in PENDING state for this loan"), - Arguments.of(ExternalTransferStatus.PENDING_INTERMEDIATE, true, - "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), - Arguments.of(ExternalTransferStatus.ACTIVE, true, - "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), - Arguments.of(ExternalTransferStatus.DECLINED, true, - "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), - Arguments.of(ExternalTransferStatus.PENDING, true, - "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), - Arguments.of(ExternalTransferStatus.BUYBACK, true, - "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state."), - Arguments.of(ExternalTransferStatus.CANCELLED, true, - "This loan cannot be sold, because it is not in ACTIVE-INTERMEDIATE state.")); - } - @ParameterizedTest @MethodSource("buybackValidationWithDelaySettlementSuccessfulDataProvider") void buybackLoanByLoanIdWhenDelaySettlementEnabledSuccess(final List transferStatuses, @@ -763,8 +734,6 @@ void buybackLoanByLoanIdWhenDelaySettlementEnabledSuccess(final List savedTransferCaptor = ArgumentCaptor.forClass(ExternalAssetOwnerTransfer.class); @@ -815,8 +784,6 @@ void buybackLoanByLoanIdWhenDelaySettlementEnabledFailure(final List testContext.externalAssetOwnersWriteServiceImpl.buybackLoanByLoanId(command)); + () -> buybackLoanByLoanId(testContext)); // then assertEquals(expectedExceptionMessage, actualException.getMessage()); @@ -866,18 +833,36 @@ private static Stream buybackValidationWithDelaySettlementFailureData "This loan cannot be bought back, external asset owner buyback transfer is already in progress")); } - /** - * Helper method to create {@link JsonCommand} object from json command string. - * - * @param jsonCommand - * the json command string - * @param loanId - * the loan id - * @return the {@link JsonCommand} object. - */ - private JsonCommand createJsonCommand(final String jsonCommand, final Long loanId) { - return new JsonCommand(null, jsonCommand, null, null, null, null, null, null, null, loanId, null, null, null, null, null, null, - null, null); + private CommandProcessingResult saleLoanByLoanId(final TestContext testContext) { + final ExternalAssetOwnerTransferResponse response = testContext.externalAssetOwnersWriteServiceImpl + .saleLoan(createSaleRequest(testContext)); + return toCommandProcessingResult(response); + } + + private CommandProcessingResult intermediarySaleLoanByLoanId(final TestContext testContext) { + final ExternalAssetOwnerTransferResponse response = testContext.externalAssetOwnersWriteServiceImpl + .intermediarySaleLoan(createIntermediarySaleRequest(testContext)); + return toCommandProcessingResult(response); + } + + private CommandProcessingResult buybackLoanByLoanId(final TestContext testContext) { + final ExternalAssetOwnerTransferResponse response = testContext.externalAssetOwnersWriteServiceImpl + .buybackLoan(createBuybackRequest(testContext)); + return toCommandProcessingResult(response); + } + + private ExternalAssetOwnerBuybackRequest createBuybackRequest(final TestContext testContext) { + return ExternalAssetOwnerBuybackRequest.builder().loanId(testContext.loanId).transferExternalId(testContext.transferExternalId) + .settlementDate(testContext.settlementDate.toString()).dateFormat(TestContext.DATE_FORMAT).locale(TestContext.LOCALE) + .build(); + } + + private CommandProcessingResult toCommandProcessingResult(final ExternalAssetOwnerTransferResponse response) { + return new CommandProcessingResultBuilder().withEntityId(response.getResourceId()) + .withEntityExternalId(response.getResourceExternalId() == null ? null : new ExternalId(response.getResourceExternalId())) + .withSubEntityId(response.getSubResourceId()).withSubEntityExternalId( + response.getSubResourceExternalId() == null ? null : new ExternalId(response.getSubResourceExternalId())) + .build(); } /** diff --git a/fineract-validation/src/main/resources/ValidationMessages.properties b/fineract-validation/src/main/resources/ValidationMessages.properties index 1e4e9d56fbe..909fabcfc16 100644 --- a/fineract-validation/src/main/resources/ValidationMessages.properties +++ b/fineract-validation/src/main/resources/ValidationMessages.properties @@ -134,3 +134,19 @@ org.apache.fineract.portfolio.meeting.date-format.not-null=The parameter 'dateFo org.apache.fineract.portfolio.meeting.locale.not-null=The parameter 'locale' is mandatory org.apache.fineract.portfolio.meeting.attendance.client-id.not-null=The parameter 'clientId' is mandatory org.apache.fineract.portfolio.meeting.attendance.attendance-type.not-null=The parameter 'attendanceType' is mandatory + +# External Asset Owner Transfer +org.apache.fineract.investor.transfer.owner-external-id.size=The parameter 'ownerExternalId' cannot exceed 100 characters +org.apache.fineract.investor.transfer.purchase-price-ratio.size=The parameter 'purchasePriceRatio' cannot exceed 50 characters +org.apache.fineract.investor.transfer.transfer-external-id.size=The parameter 'transferExternalId' cannot exceed 100 characters +org.apache.fineract.investor.transfer.transfer-external-group-id.size=The parameter 'transferExternalGroupId' cannot exceed 100 characters +org.apache.fineract.investor.owner.owner-external-id.not-null=The parameter 'ownerExternalId' is mandatory +org.apache.fineract.investor.transfer.owner-external-id.not-blank=The parameter `ownerExternalId` is mandatory. +org.apache.fineract.investor.transfer.purchase-price-ratio.not-blank=The parameter `purchasePriceRatio` is mandatory. +validation.msg.externalAssetOwner.ownerExternalId.cannot.be.blank=The parameter 'ownerExternalId' cannot be blank +org.apache.fineract.investor.transfer.settlement-date.not-null=The parameter `settlementDate` is mandatory. +org.apache.fineract.investor.transfer.transfer-id.not-null=The parameter `transferId` is mandatory. +validation.msg.externalAssetOwnerLoanProductAttribute.attributeKey.cannot.be.blank=The parameter 'attributeKey' cannot be blank +validation.msg.externalAssetOwnerLoanProductAttribute.attributeKey.max.length=The parameter 'attributeKey' cannot exceed 255 characters +validation.msg.externalAssetOwnerLoanProductAttribute.attributeValue.cannot.be.blank=The parameter 'attributeValue' cannot be blank +validation.msg.externalAssetOwnerLoanProductAttribute.attributeValue.max.length=The parameter 'attributeValue' cannot exceed 255 characters diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignTrialBalanceSummaryReportTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignTrialBalanceSummaryReportTest.java index 6b2d0df6707..a46953a8eb4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignTrialBalanceSummaryReportTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignTrialBalanceSummaryReportTest.java @@ -32,11 +32,11 @@ import org.apache.fineract.client.models.BusinessStep; import org.apache.fineract.client.models.BusinessStepRequest; import org.apache.fineract.client.models.ChargeRequest; -import org.apache.fineract.client.models.ExternalAssetOwnerRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerSaleRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; import org.apache.fineract.client.models.GetFinancialActivityAccountsResponse; import org.apache.fineract.client.models.PostClientsRequest; import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest; -import org.apache.fineract.client.models.PostInitiateTransferResponse; import org.apache.fineract.client.models.PostLoanOriginatorsRequest; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; @@ -164,8 +164,9 @@ public void testExternalAssetOwnerEntriesAppearInReport() { Long loanId = createAndDisburseLoan(clientId, "01 March 2020", "02 March 2020", null, null); String ownerExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse saleResponse = ok(() -> fineractClient().externalAssetOwners().transferRequestWithLoanId(loanId, - new ExternalAssetOwnerRequest().settlementDate("2020-03-02").dateFormat("yyyy-MM-dd").locale(LoanTestData.LOCALE) + ExternalAssetOwnerTransferResponse saleResponse = ok(() -> fineractClient().externalAssetOwners().transferRequestWithLoanId( + loanId, + new ExternalAssetOwnerSaleRequest().settlementDate("2020-03-02").dateFormat("yyyy-MM-dd").locale(LoanTestData.LOCALE) .transferExternalId(UUID.randomUUID().toString()).ownerExternalId(ownerExternalId).purchasePriceRatio("1.0"), "sale")); assertNotNull(saleResponse); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java index e25b4e2103c..0d0229a5b3a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalAssetOwnerHelper.java @@ -25,16 +25,17 @@ import java.util.ArrayList; import java.util.List; import org.apache.fineract.accounting.common.AccountingConstants; -import org.apache.fineract.client.models.ExternalAssetOwnerRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerSaleRequest; import org.apache.fineract.client.models.ExternalAssetOwnerSearchRequest; -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.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.client.models.ExternalOwnerJournalEntryResponse; +import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryResponse; +import org.apache.fineract.client.models.ExternalTransferResponse; import org.apache.fineract.client.models.GetFinancialActivityAccountsResponse; import org.apache.fineract.client.models.PageExternalTransferData; +import org.apache.fineract.client.models.PageExternalTransferResponse; import org.apache.fineract.client.models.PagedRequestExternalAssetOwnerSearchRequest; import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest; -import org.apache.fineract.client.models.PostInitiateTransferResponse; import org.apache.fineract.client.util.CallFailedRuntimeException; import org.apache.fineract.client.util.Calls; import org.apache.fineract.integrationtests.common.accounting.Account; @@ -44,7 +45,7 @@ public class ExternalAssetOwnerHelper { public ExternalAssetOwnerHelper() {} - public PostInitiateTransferResponse initiateTransferByLoanId(Long loanId, String command, ExternalAssetOwnerRequest request) { + public ExternalAssetOwnerTransferResponse initiateTransferByLoanId(Long loanId, String command, ExternalAssetOwnerSaleRequest request) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.transferRequestWithLoanId(loanId, request, command)); } @@ -60,39 +61,39 @@ public void cancelTransferByTransferExternalIdError(String transferExternalId) { assertEquals(403, exception.getResponse().code()); } - public PageExternalTransferData retrieveTransferByTransferExternalId(String transferExternalId) { + public PageExternalTransferResponse retrieveTransferByTransferExternalId(String transferExternalId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getTransfers(transferExternalId, null, null, 0, 100)); } - public PageExternalTransferData retrieveTransferByLoanExternalId(String loanExternalId) { + public PageExternalTransferResponse retrieveTransferByLoanExternalId(String loanExternalId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getTransfers(null, null, loanExternalId, 0, 100)); } - public PageExternalTransferData retrieveTransfersByLoanId(Long loanId) { + public PageExternalTransferResponse retrieveTransfersByLoanId(Long loanId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getTransfers(null, loanId, null, 0, 100)); } - public PageExternalTransferData retrieveTransfersByLoanId(Long loanId, int offset, int limit) { + public PageExternalTransferResponse retrieveTransfersByLoanId(Long loanId, int offset, int limit) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getTransfers(null, loanId, null, offset, limit)); } - public ExternalTransferData retrieveActiveTransferByLoanExternalId(String loanExternalId) { + public ExternalTransferResponse retrieveActiveTransferByLoanExternalId(String loanExternalId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getActiveTransfer(null, null, loanExternalId)); } - public ExternalTransferData retrieveActiveTransferByTransferExternalId(String transferExternalId) { + public ExternalTransferResponse retrieveActiveTransferByTransferExternalId(String transferExternalId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getActiveTransfer(transferExternalId, null, null)); } - public ExternalTransferData retrieveActiveTransferByLoanId(Long loanId) { + public ExternalTransferResponse retrieveActiveTransferByLoanId(Long loanId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getActiveTransfer(null, loanId, null)); } - public ExternalOwnerTransferJournalEntryData retrieveJournalEntriesOfTransfer(Long transferId) { + public ExternalOwnerTransferJournalEntryResponse retrieveJournalEntriesOfTransfer(Long transferId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getJournalEntriesOfTransfer(transferId, 0, 100)); } - public ExternalOwnerJournalEntryData retrieveJournalEntriesOfOwner(String ownerExternalId) { + public ExternalOwnerJournalEntryResponse retrieveJournalEntriesOfOwner(String ownerExternalId) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.getJournalEntriesOfOwner(ownerExternalId, 0, 100)); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/InvestorHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/InvestorHelper.java index 5aa7bec75bf..1a428844007 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/InvestorHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/InvestorHelper.java @@ -19,9 +19,9 @@ package org.apache.fineract.integrationtests.investor; import java.util.List; +import org.apache.fineract.client.models.ExternalAssetOwnerCreateRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerCreateResponse; import org.apache.fineract.client.models.ExternalTransferOwnerData; -import org.apache.fineract.client.models.PostExternalAssetOwnerRequest; -import org.apache.fineract.client.models.PostExternalAssetOwnerResponse; import org.apache.fineract.client.util.Calls; import org.apache.fineract.integrationtests.common.FineractClientHelper; @@ -35,7 +35,7 @@ public static List retrieveExternalAssetOwners() { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.retrieveExternalAssetOwners()); } - public static PostExternalAssetOwnerResponse createExternalAssetOwner(final PostExternalAssetOwnerRequest request) { + public static ExternalAssetOwnerCreateResponse createExternalAssetOwner(final ExternalAssetOwnerCreateRequest request) { return Calls.ok(FineractClientHelper.getFineractClient().externalAssetOwners.createExternalAssetOwner(request)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTest.java index e9b091581f9..0236b0deb26 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTest.java @@ -26,9 +26,9 @@ import java.util.List; import java.util.Optional; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.ExternalAssetOwnerCreateRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerCreateResponse; import org.apache.fineract.client.models.ExternalTransferOwnerData; -import org.apache.fineract.client.models.PostExternalAssetOwnerRequest; -import org.apache.fineract.client.models.PostExternalAssetOwnerResponse; import org.apache.fineract.client.util.CallFailedRuntimeException; import org.apache.fineract.integrationtests.BaseLoanIntegrationTest; import org.apache.fineract.integrationtests.common.Utils; @@ -41,9 +41,9 @@ public class ExternalAssetOwnerTest extends BaseLoanIntegrationTest { @Test public void testCreateExternalAssetOwnerSuccessfully() { final String ownerExternalId = Utils.uniqueRandomStringGenerator("eao", 20); - final PostExternalAssetOwnerRequest request = new PostExternalAssetOwnerRequest().ownerExternalId(ownerExternalId); + final ExternalAssetOwnerCreateRequest request = new ExternalAssetOwnerCreateRequest().ownerExternalId(ownerExternalId); - final PostExternalAssetOwnerResponse response = InvestorHelper.createExternalAssetOwner(request); + final ExternalAssetOwnerCreateResponse response = InvestorHelper.createExternalAssetOwner(request); assertNotNull(response); assertNotNull(response.getResourceId()); @@ -57,7 +57,7 @@ public void testCreateExternalAssetOwnerSuccessfully() { @Test public void testCreateExternalAssetOwnerFailsWhenOwnerExternalIdIsNull() { - final PostExternalAssetOwnerRequest request = new PostExternalAssetOwnerRequest().ownerExternalId(null); + final ExternalAssetOwnerCreateRequest request = new ExternalAssetOwnerCreateRequest().ownerExternalId(null); final CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> InvestorHelper.createExternalAssetOwner(request)); @@ -68,9 +68,9 @@ public void testCreateExternalAssetOwnerFailsWhenOwnerExternalIdIsNull() { @Test public void testCreateExternalAssetOwnerFailsWhenOwnerExternalIdIsDuplicate() { final String ownerExternalId = Utils.uniqueRandomStringGenerator("eao", 20); - final PostExternalAssetOwnerRequest request = new PostExternalAssetOwnerRequest().ownerExternalId(ownerExternalId); + final ExternalAssetOwnerCreateRequest request = new ExternalAssetOwnerCreateRequest().ownerExternalId(ownerExternalId); - final PostExternalAssetOwnerResponse firstResponse = InvestorHelper.createExternalAssetOwner(request); + final ExternalAssetOwnerCreateResponse firstResponse = InvestorHelper.createExternalAssetOwner(request); assertNotNull(firstResponse); assertNotNull(firstResponse.getResourceId()); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerToOwnerTransferTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerToOwnerTransferTest.java index c18cce5af10..1463640e249 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerToOwnerTransferTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerToOwnerTransferTest.java @@ -18,19 +18,19 @@ */ package org.apache.fineract.integrationtests.investor.externalassetowner; -import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.ACTIVE; -import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.CANCELLED; -import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.DECLINED; -import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.PENDING; -import static org.apache.fineract.client.models.ExternalTransferData.SubStatusEnum.BALANCE_ZERO; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.ACTIVE; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.CANCELLED; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.DECLINED; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.PENDING; +import static org.apache.fineract.client.models.ExternalTransferResponse.SubStatusEnum.BALANCE_ZERO; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import java.math.BigDecimal; import java.util.UUID; -import org.apache.fineract.client.models.ExternalTransferData; -import org.apache.fineract.client.models.PageExternalTransferData; -import org.apache.fineract.client.models.PostInitiateTransferResponse; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.client.models.ExternalTransferResponse; +import org.apache.fineract.client.models.PageExternalTransferResponse; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.junit.jupiter.api.Test; @@ -56,7 +56,7 @@ public void saleFromOwnerAToOwnerBWithoutDelayedSettlement() { // Step 2: Sell loan to Owner A String ownerAExternalId = UUID.randomUUID().toString(); String saleATransferExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse saleAResponse = createSaleTransfer(loanID, "2020-03-02", saleATransferExternalId, + ExternalAssetOwnerTransferResponse saleAResponse = createSaleTransfer(loanID, "2020-03-02", saleATransferExternalId, UUID.randomUUID().toString(), ownerAExternalId, "1.0"); validateResponse(saleAResponse, loanID); @@ -77,16 +77,16 @@ public void saleFromOwnerAToOwnerBWithoutDelayedSettlement() { // Settlement date = current business date (2020-03-03), COB will process it on next day String ownerBExternalId = UUID.randomUUID().toString(); String saleBTransferExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse saleBResponse = createSaleTransfer(loanID, "2020-03-03", saleBTransferExternalId, + ExternalAssetOwnerTransferResponse saleBResponse = createSaleTransfer(loanID, "2020-03-03", saleBTransferExternalId, UUID.randomUUID().toString(), ownerBExternalId, "1.0"); validateResponse(saleBResponse, loanID); // Verify the new PENDING transfer was created for Owner B - PageExternalTransferData transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); assertNotNull(transfers.getContent()); // Find the new PENDING transfer for Owner B - ExternalTransferData pendingTransferB = transfers.getContent().stream() + ExternalTransferResponse pendingTransferB = transfers.getContent().stream() .filter(t -> saleBTransferExternalId.equals(t.getTransferExternalId()) && PENDING.equals(t.getStatus())).findFirst() .orElse(null); assertNotNull(pendingTransferB, "PENDING transfer for Owner B should exist"); @@ -99,7 +99,7 @@ public void saleFromOwnerAToOwnerBWithoutDelayedSettlement() { assertNotNull(transfers.getContent()); // Owner A's ACTIVE transfer should now have effectiveDateTo = 2020-03-03 (settlement date of Owner B) - ExternalTransferData expiredOwnerATransfer = transfers.getContent().stream() + ExternalTransferResponse expiredOwnerATransfer = transfers.getContent().stream() .filter(t -> saleATransferExternalId.equals(t.getTransferExternalId()) && ACTIVE.equals(t.getStatus())).findFirst() .orElse(null); assertNotNull(expiredOwnerATransfer, "Expired ACTIVE transfer for Owner A should exist"); @@ -107,7 +107,7 @@ public void saleFromOwnerAToOwnerBWithoutDelayedSettlement() { "Owner A's ACTIVE transfer should be expired to the settlement date of Owner B's transfer"); // Owner B should have an ACTIVE transfer with effectiveDateTo = 9999-12-31 - ExternalTransferData activeOwnerBTransfer = transfers.getContent().stream() + ExternalTransferResponse activeOwnerBTransfer = transfers.getContent().stream() .filter(t -> saleBTransferExternalId.equals(t.getTransferExternalId()) && ACTIVE.equals(t.getStatus())).findFirst() .orElse(null); assertNotNull(activeOwnerBTransfer, "ACTIVE transfer for Owner B should exist"); @@ -117,7 +117,7 @@ public void saleFromOwnerAToOwnerBWithoutDelayedSettlement() { // Verify active mapping now points to Owner B (use direct API, not getAndValidateThereIsActiveMapping // which assumes only one ACTIVE transfer) - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); assertNotNull(activeTransfer, "There should be an active transfer mapping"); assertEquals(saleBTransferExternalId, activeTransfer.getTransferExternalId(), "Active mapping should point to Owner B's transfer"); @@ -151,7 +151,7 @@ public void saleFromOwnerAToOwnerBToOwnerCChainedTransfers() { updateBusinessDateAndExecuteCOBJob("2020-03-04"); // Verify Owner B is active - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); assertEquals(saleBExternalId, activeTransfer.getTransferExternalId()); // Sell from Owner B to Owner C (settlementDate = current business date 2020-03-04) @@ -166,8 +166,8 @@ public void saleFromOwnerAToOwnerBToOwnerCChainedTransfers() { "Owner C should be the active owner after chained transfers"); // Verify Owner B's transfer is expired - PageExternalTransferData allTransfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); - ExternalTransferData ownerBActive = allTransfers.getContent().stream() + PageExternalTransferResponse allTransfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + ExternalTransferResponse ownerBActive = allTransfers.getContent().stream() .filter(t -> saleBExternalId.equals(t.getTransferExternalId()) && ACTIVE.equals(t.getStatus())).findFirst() .orElse(null); assertNotNull(ownerBActive); @@ -198,7 +198,7 @@ public void ownerToOwnerPendingCancelledBeforeCOBKeepsOriginalOwnerIntact() { // Initiate owner-to-owner sale to Owner B String ownerBExternalId = UUID.randomUUID().toString(); String saleBExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse saleBResponse = createSaleTransfer(loanID, "2020-03-03", saleBExternalId, + ExternalAssetOwnerTransferResponse saleBResponse = createSaleTransfer(loanID, "2020-03-03", saleBExternalId, UUID.randomUUID().toString(), ownerBExternalId, "1.0"); validateResponse(saleBResponse, loanID); @@ -206,21 +206,21 @@ public void ownerToOwnerPendingCancelledBeforeCOBKeepsOriginalOwnerIntact() { EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalId(saleBExternalId); // Verify Owner A is still the active owner — ACTIVE transfer with effectiveDateTo = 9999-12-31 - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); assertNotNull(activeTransfer, "Owner A should still be the active owner after cancel"); assertEquals(saleAExternalId, activeTransfer.getTransferExternalId(), "Active mapping should still point to Owner A after cancel"); // Verify Owner A's ACTIVE transfer is untouched (effectiveDateTo = 9999-12-31) - PageExternalTransferData transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); - ExternalTransferData ownerAActive = transfers.getContent().stream() + PageExternalTransferResponse transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + ExternalTransferResponse ownerAActive = transfers.getContent().stream() .filter(t -> saleAExternalId.equals(t.getTransferExternalId()) && ACTIVE.equals(t.getStatus()) && java.time.LocalDate.parse("9999-12-31").equals(t.getEffectiveTo())) .findFirst().orElse(null); assertNotNull(ownerAActive, "Owner A's ACTIVE transfer should still have open-ended effectiveTo"); // Verify Owner B's transfer is CANCELLED - ExternalTransferData ownerBCancelled = transfers.getContent().stream() + ExternalTransferResponse ownerBCancelled = transfers.getContent().stream() .filter(t -> saleBExternalId.equals(t.getTransferExternalId()) && CANCELLED.equals(t.getStatus())).findFirst() .orElse(null); assertNotNull(ownerBCancelled, "Owner B's transfer should be CANCELLED"); @@ -256,20 +256,20 @@ public void ownerToOwnerPendingDeclinedInCOBKeepsOriginalOwnerIntact() { LOAN_TRANSACTION_HELPER.writeOffLoan("04 March 2020", loanID); // Verify Owner A is still the active owner (PENDING for Owner B should be declined, not yet settled) - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanID.longValue()); assertNotNull(activeTransfer, "Owner A should still be the active owner before settlement date"); assertEquals(saleAExternalId, activeTransfer.getTransferExternalId(), "Active mapping should still point to Owner A"); // Verify Owner B's PENDING transfer is declined - PageExternalTransferData transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); - ExternalTransferData ownerBDeclined = transfers.getContent().stream() + PageExternalTransferResponse transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + ExternalTransferResponse ownerBDeclined = transfers.getContent().stream() .filter(t -> saleBExternalId.equals(t.getTransferExternalId()) && DECLINED.equals(t.getStatus())).findFirst() .orElse(null); assertNotNull(ownerBDeclined, "Owner B's transfer should be DECLINED"); assertEquals(BALANCE_ZERO, ownerBDeclined.getSubStatus(), "Decline reason should be BALANCE_ZERO"); // Verify Owner A's ACTIVE transfer is still open-ended - ExternalTransferData ownerAActive = transfers.getContent().stream() + ExternalTransferResponse ownerAActive = transfers.getContent().stream() .filter(t -> saleAExternalId.equals(t.getTransferExternalId()) && ACTIVE.equals(t.getStatus()) && java.time.LocalDate.parse("9999-12-31").equals(t.getEffectiveTo())) .findFirst().orElse(null); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java index c38d91c519e..01455c0a2ea 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferCancelTest.java @@ -18,9 +18,9 @@ */ 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.client.models.ExternalTransferResponse.StatusEnum.BUYBACK; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.CANCELLED; +import static org.apache.fineract.client.models.ExternalTransferResponse.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; @@ -45,13 +45,13 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; import org.apache.fineract.accounting.common.AccountingConstants; -import org.apache.fineract.client.models.ExternalAssetOwnerRequest; -import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryData; -import org.apache.fineract.client.models.ExternalTransferData; +import org.apache.fineract.client.models.ExternalAssetOwnerSaleRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryResponse; +import org.apache.fineract.client.models.ExternalTransferResponse; import org.apache.fineract.client.models.GetFinancialActivityAccountsResponse; -import org.apache.fineract.client.models.PageExternalTransferData; +import org.apache.fineract.client.models.PageExternalTransferResponse; import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest; -import org.apache.fineract.client.models.PostInitiateTransferResponse; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.BaseLoanIntegrationTest; @@ -138,7 +138,7 @@ public void successCancelSale() { Integer loanID = createLoanForClient(clientID); addPenaltyForLoan(loanID, "10"); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); validateResponse(saleTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02", @@ -146,7 +146,7 @@ public void successCancelSale() { 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()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); retrieveResponse.getContent().forEach(transfer -> getAndValidateThereIsNoJournalEntriesForTransfer(transfer.getTransferId())); EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalId(saleTransferResponse.getResourceExternalId()); @@ -167,7 +167,7 @@ public void successCancelSale() { } private void getAndValidateThereIsNoJournalEntriesForTransfer(Long transferId) { - ExternalOwnerTransferJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); + ExternalOwnerTransferJournalEntryResponse result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); assertNull(result.getJournalEntryData()); } @@ -179,9 +179,9 @@ public void saleAndBuybackOnTheSameDay() { Integer clientID = createClient(); Integer loanID = createLoanForClient(clientID); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); validateResponse(saleTransferResponse, loanID); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-02"); validateResponse(buybackTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, @@ -239,25 +239,25 @@ public void saleAndBuybackOnTheSameDay() { } } - private PostInitiateTransferResponse createSaleTransfer(Integer loanID, String settlementDate) { + private ExternalAssetOwnerTransferResponse 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, + private ExternalAssetOwnerTransferResponse createSaleTransfer(Integer loanID, String settlementDate, String transferExternalId, String ownerExternalId, String purchasePriceRatio) { - PostInitiateTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "sale", - new ExternalAssetOwnerRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") + ExternalAssetOwnerTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "sale", + new ExternalAssetOwnerSaleRequest().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) { + private ExternalAssetOwnerTransferResponse createBuybackTransfer(Integer loanID, String settlementDate) { String transferExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "buyback", - new ExternalAssetOwnerRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") + ExternalAssetOwnerTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), + "buyback", new ExternalAssetOwnerSaleRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") .transferExternalId(transferExternalId)); assertEquals(transferExternalId, saleResponse.getResourceExternalId()); return saleResponse; @@ -361,17 +361,17 @@ private HashMap collaterals(Integer collateralId, BigDecimal qua } private void getAndValidateExternalAssetOwnerTransferByLoan(Integer loanID, ExpectedExternalTransferData... expectedItems) { - PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); assertEquals(expectedItems.length, retrieveResponse.getNumberOfElements()); for (ExpectedExternalTransferData expected : expectedItems) { assertNotNull(retrieveResponse.getContent()); - Optional first = retrieveResponse.getContent().stream() + Optional 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(); + ExternalTransferResponse etd = first.get(); assertEquals(expected.transferExternalId, etd.getTransferExternalId()); assertEquals(expected.status, etd.getStatus()); assertEquals(LocalDate.parse(expected.settlementDate), etd.getSettlementDate()); @@ -392,16 +392,17 @@ private void getAndValidateExternalAssetOwnerTransferByLoan(Integer loanID, Expe } private void getAndValidateThereIsNoActiveMapping(Long loanId) { - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanId); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanId); assertNull(activeTransfer); } private void getAndValidateThereIsNoActiveMapping(String transferExternalId) { - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByTransferExternalId(transferExternalId); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER + .retrieveActiveTransferByTransferExternalId(transferExternalId); assertNull(activeTransfer); } - private void validateResponse(PostInitiateTransferResponse transferResponse, Integer loanID) { + private void validateResponse(ExternalAssetOwnerTransferResponse transferResponse, Integer loanID) { assertNotNull(transferResponse); assertNotNull(transferResponse.getResourceId()); assertNotNull(transferResponse.getResourceExternalId()); @@ -414,7 +415,7 @@ private void validateResponse(PostInitiateTransferResponse transferResponse, Int @RequiredArgsConstructor() public static class ExpectedExternalTransferData { - private final ExternalTransferData.StatusEnum status; + private final ExternalTransferResponse.StatusEnum status; private final String transferExternalId; @@ -430,7 +431,7 @@ public static class ExpectedExternalTransferData { private final BigDecimal totalFeeOutstanding; private final BigDecimal totalOverpaid; - static ExpectedExternalTransferData expected(ExternalTransferData.StatusEnum status, String transferExternalId, + static ExpectedExternalTransferData expected(ExternalTransferResponse.StatusEnum status, String transferExternalId, String settlementDate, String effectiveFrom, String effectiveTo, boolean detailsExpected, BigDecimal totalOutstanding, BigDecimal totalPrincipalOutstanding, BigDecimal totalInterestOutstanding, BigDecimal totalPenaltyOutstanding, BigDecimal totalFeeOutstanding, BigDecimal totalOverpaid) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferTest.java index 8eff86f3094..bc47ad94b84 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferTest.java @@ -42,12 +42,12 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.client.models.ExternalAssetOwnerRequest; -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.PostInitiateTransferResponse; +import org.apache.fineract.client.models.ExternalAssetOwnerSaleRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.client.models.ExternalOwnerJournalEntryResponse; +import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryResponse; +import org.apache.fineract.client.models.ExternalTransferResponse; +import org.apache.fineract.client.models.PageExternalTransferResponse; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.BaseLoanIntegrationTest; @@ -121,31 +121,31 @@ protected void updateBusinessDateAndExecuteCOBJob(String date) { SCHEDULER_JOB_HELPER.executeAndAwaitJob("Loan COB"); } - protected PostInitiateTransferResponse createSaleTransfer(Integer loanID, String settlementDate) { + protected ExternalAssetOwnerTransferResponse createSaleTransfer(Integer loanID, String settlementDate) { String transferExternalId = UUID.randomUUID().toString(); String transferExternalGroupId = UUID.randomUUID().toString(); ownerExternalId = UUID.randomUUID().toString(); return createSaleTransfer(loanID, settlementDate, transferExternalId, transferExternalGroupId, ownerExternalId, "1.0"); } - protected PostInitiateTransferResponse createSaleTransfer(Integer loanID, String settlementDate, String transferExternalId, + protected ExternalAssetOwnerTransferResponse createSaleTransfer(Integer loanID, String settlementDate, String transferExternalId, String transferExternalGroupId, String ownerExternalId, String purchasePriceRatio) { - PostInitiateTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "sale", - new ExternalAssetOwnerRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") + ExternalAssetOwnerTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "sale", + new ExternalAssetOwnerSaleRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") .transferExternalId(transferExternalId).transferExternalGroupId(transferExternalGroupId) .ownerExternalId(ownerExternalId).purchasePriceRatio(purchasePriceRatio)); assertEquals(transferExternalId, saleResponse.getResourceExternalId()); return saleResponse; } - protected PostInitiateTransferResponse createBuybackTransfer(Integer loanID, String settlementDate) { + protected ExternalAssetOwnerTransferResponse 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 ExternalAssetOwnerRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") + protected ExternalAssetOwnerTransferResponse createBuybackTransfer(Integer loanID, String settlementDate, String transferExternalId) { + ExternalAssetOwnerTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), + "buyback", new ExternalAssetOwnerSaleRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") .transferExternalId(transferExternalId)); assertEquals(transferExternalId, saleResponse.getResourceExternalId()); return saleResponse; @@ -250,20 +250,21 @@ protected HashMap collaterals(Integer collateralId, BigDecimal q } protected void getAndValidateExternalAssetOwnerTransferByLoan(Integer loanID, ExpectedExternalTransferData... expectedItems) { - PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); assertEquals(expectedItems.length, retrieveResponse.getNumberOfElements()); validateExternalAssetOwnerTransfer(retrieveResponse, expectedItems); } - protected void validateExternalAssetOwnerTransfer(PageExternalTransferData response, ExpectedExternalTransferData... expectedItems) { + protected void validateExternalAssetOwnerTransfer(PageExternalTransferResponse response, + ExpectedExternalTransferData... expectedItems) { for (ExpectedExternalTransferData expected : expectedItems) { assertNotNull(response.getContent()); - Optional first = response.getContent().stream() + Optional 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(); + ExternalTransferResponse etd = first.get(); assertEquals(expected.transferExternalId, etd.getTransferExternalId()); assertEquals(expected.status, etd.getStatus()); assertEquals(LocalDate.parse(expected.settlementDate), etd.getSettlementDate()); @@ -287,24 +288,25 @@ protected void validateExternalAssetOwnerTransfer(PageExternalTransferData respo } protected void getAndValidateThereIsActiveMapping(Integer loanID) { - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId((long) loanID); + ExternalTransferResponse 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(); + ExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()).getContent() + .stream().filter(transfer -> ExternalTransferResponse.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); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanId); assertNull(activeTransfer); } protected void getAndValidateThereIsNoActiveMapping(String transferExternalId) { - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByTransferExternalId(transferExternalId); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER + .retrieveActiveTransferByTransferExternalId(transferExternalId); assertNull(activeTransfer); } - protected void validateResponse(PostInitiateTransferResponse transferResponse, Integer loanID) { + protected void validateResponse(ExternalAssetOwnerTransferResponse transferResponse, Integer loanID) { assertNotNull(transferResponse); assertNotNull(transferResponse.getResourceId()); assertNotNull(transferResponse.getResourceExternalId()); @@ -315,7 +317,7 @@ protected void validateResponse(PostInitiateTransferResponse transferResponse, I } protected void getAndValidateOwnerJournalEntries(String ownerExternalId, ExpectedJournalEntryData... expectedItems) { - ExternalOwnerJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfOwner(ownerExternalId); + ExternalOwnerJournalEntryResponse result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfOwner(ownerExternalId); assertNotNull(result); assertEquals(expectedItems.length, result.getJournalEntryData().getTotalElements()); int i = 0; @@ -331,7 +333,7 @@ protected void getAndValidateOwnerJournalEntries(String ownerExternalId, Expecte } protected void getAndValidateThereIsJournalEntriesForTransfer(Long transferId, ExpectedJournalEntryData... expectedItems) { - ExternalOwnerTransferJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); + ExternalOwnerTransferJournalEntryResponse result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); assertNotNull(result); long totalElements = result.getJournalEntryData().getTotalElements(); assertEquals(expectedItems.length, totalElements); @@ -348,14 +350,14 @@ protected void getAndValidateThereIsJournalEntriesForTransfer(Long transferId, E } protected void getAndValidateThereIsNoJournalEntriesForTransfer(Long transferId) { - ExternalOwnerTransferJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); + ExternalOwnerTransferJournalEntryResponse result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); assertNull(result.getJournalEntryData()); } @RequiredArgsConstructor() public static class ExpectedExternalTransferData { - private final ExternalTransferData.StatusEnum status; + private final ExternalTransferResponse.StatusEnum status; private final String transferExternalId; @@ -363,7 +365,7 @@ public static class ExpectedExternalTransferData { private final String effectiveFrom; private final String effectiveTo; - private final ExternalTransferData.SubStatusEnum subStatus; + private final ExternalTransferResponse.SubStatusEnum subStatus; private final boolean detailsExpected; private final BigDecimal totalOutstanding; private final BigDecimal totalPrincipalOutstanding; @@ -372,7 +374,7 @@ public static class ExpectedExternalTransferData { private final BigDecimal totalFeeOutstanding; private final BigDecimal totalOverpaid; - static ExpectedExternalTransferData expected(ExternalTransferData.StatusEnum status, String transferExternalId, + static ExpectedExternalTransferData expected(ExternalTransferResponse.StatusEnum status, String transferExternalId, String settlementDate, String effectiveFrom, String effectiveTo, boolean detailsExpected, BigDecimal totalOutstanding, BigDecimal totalPrincipalOutstanding, BigDecimal totalInterestOutstanding, BigDecimal totalPenaltyOutstanding, BigDecimal totalFeeOutstanding, BigDecimal totalOverpaid) { @@ -381,14 +383,14 @@ static ExpectedExternalTransferData expected(ExternalTransferData.StatusEnum sta totalFeeOutstanding, totalOverpaid); } - static ExpectedExternalTransferData expected(ExternalTransferData.StatusEnum status, String transferExternalId, + static ExpectedExternalTransferData expected(ExternalTransferResponse.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) { + static ExpectedExternalTransferData expected(ExternalTransferResponse.StatusEnum status, String transferExternalId, + String settlementDate, String effectiveFrom, String effectiveTo, ExternalTransferResponse.SubStatusEnum subStatus) { return new ExpectedExternalTransferData(status, transferExternalId, settlementDate, effectiveFrom, effectiveTo, subStatus, false, null, null, null, null, null, null); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferUndisbursedLoanTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferUndisbursedLoanTest.java index 83d5b30fded..5acc2c94ee1 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferUndisbursedLoanTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/ExternalAssetOwnerTransferUndisbursedLoanTest.java @@ -24,10 +24,10 @@ import java.math.BigDecimal; import java.util.UUID; -import org.apache.fineract.client.models.ExternalAssetOwnerRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerSaleRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostClientsResponse; -import org.apache.fineract.client.models.PostInitiateTransferResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoanProductsResponse; import org.apache.fineract.client.models.PostLoansResponse; @@ -103,8 +103,8 @@ public void testExternalAssetOwnerTransferForUndisbursedLoan() { String transferExternalId = UUID.randomUUID().toString(); String ownerExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse transferResponse = externalAssetOwnerHelper.initiateTransferByLoanId(loanId, "sale", - new ExternalAssetOwnerRequest().settlementDate("01 January 2024").dateFormat("dd MMMM yyyy").locale("en") + ExternalAssetOwnerTransferResponse transferResponse = externalAssetOwnerHelper.initiateTransferByLoanId(loanId, "sale", + new ExternalAssetOwnerSaleRequest().settlementDate("01 January 2024").dateFormat("dd MMMM yyyy").locale("en") .transferExternalId(transferExternalId).ownerExternalId(ownerExternalId).purchasePriceRatio("1.0")); assertNotNull(transferResponse); @@ -159,8 +159,8 @@ public void testExternalAssetOwnerTransferForBackdatedUndisbursedLoan() { String transferExternalId = UUID.randomUUID().toString(); String ownerExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse transferResponse = externalAssetOwnerHelper.initiateTransferByLoanId(loanId, "sale", - new ExternalAssetOwnerRequest().settlementDate("01 March 2024").dateFormat("dd MMMM yyyy").locale("en") + ExternalAssetOwnerTransferResponse transferResponse = externalAssetOwnerHelper.initiateTransferByLoanId(loanId, "sale", + new ExternalAssetOwnerSaleRequest().settlementDate("01 March 2024").dateFormat("dd MMMM yyyy").locale("en") .transferExternalId(transferExternalId).ownerExternalId(ownerExternalId).purchasePriceRatio("1.0")); assertNotNull(transferResponse); @@ -228,12 +228,12 @@ public void testExternalAssetOwnerTransferComparison_DisbursedVsUndisbursed() { String transfer2ExternalId = UUID.randomUUID().toString(); String ownerExternalId = UUID.randomUUID().toString(); - PostInitiateTransferResponse transfer1Response = externalAssetOwnerHelper.initiateTransferByLoanId(loan1Id, "sale", - new ExternalAssetOwnerRequest().settlementDate("31 January 2024").dateFormat("dd MMMM yyyy").locale("en") + ExternalAssetOwnerTransferResponse transfer1Response = externalAssetOwnerHelper.initiateTransferByLoanId(loan1Id, "sale", + new ExternalAssetOwnerSaleRequest().settlementDate("31 January 2024").dateFormat("dd MMMM yyyy").locale("en") .transferExternalId(transfer1ExternalId).ownerExternalId(ownerExternalId).purchasePriceRatio("1.0")); - PostInitiateTransferResponse transfer2Response = externalAssetOwnerHelper.initiateTransferByLoanId(loan2Id, "sale", - new ExternalAssetOwnerRequest().settlementDate("31 January 2024").dateFormat("dd MMMM yyyy").locale("en") + ExternalAssetOwnerTransferResponse transfer2Response = externalAssetOwnerHelper.initiateTransferByLoanId(loan2Id, "sale", + new ExternalAssetOwnerSaleRequest().settlementDate("31 January 2024").dateFormat("dd MMMM yyyy").locale("en") .transferExternalId(transfer2ExternalId).ownerExternalId(ownerExternalId).purchasePriceRatio("1.0")); GetLoansLoanIdResponse disbursedLoan = loanTransactionHelper.getLoanDetails(loan1Id); 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 08d426b1a07..ce449fbc37c 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 @@ -18,14 +18,14 @@ */ package org.apache.fineract.integrationtests.investor.externalassetowner; -import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.ACTIVE; -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.DECLINED; -import static org.apache.fineract.client.models.ExternalTransferData.StatusEnum.PENDING; -import static org.apache.fineract.client.models.ExternalTransferData.SubStatusEnum.BALANCE_ZERO; -import static org.apache.fineract.client.models.ExternalTransferData.SubStatusEnum.SAMEDAY_TRANSFERS; -import static org.apache.fineract.client.models.ExternalTransferData.SubStatusEnum.UNSOLD; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.ACTIVE; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.BUYBACK; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.CANCELLED; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.DECLINED; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.PENDING; +import static org.apache.fineract.client.models.ExternalTransferResponse.SubStatusEnum.BALANCE_ZERO; +import static org.apache.fineract.client.models.ExternalTransferResponse.SubStatusEnum.SAMEDAY_TRANSFERS; +import static org.apache.fineract.client.models.ExternalTransferResponse.SubStatusEnum.UNSOLD; 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.assertFalse; @@ -61,17 +61,17 @@ import okhttp3.ResponseBody; import org.apache.fineract.accounting.common.AccountingConstants; import org.apache.fineract.accounting.journalentry.domain.JournalEntryType; -import org.apache.fineract.client.models.ExternalAssetOwnerRequest; -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.ExternalAssetOwnerSaleRequest; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.client.models.ExternalOwnerJournalEntryResponse; +import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryResponse; +import org.apache.fineract.client.models.ExternalTransferResponse; import org.apache.fineract.client.models.GetFinancialActivityAccountsResponse; import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; import org.apache.fineract.client.models.JournalEntryCommand; import org.apache.fineract.client.models.JournalEntryTransactionItem; -import org.apache.fineract.client.models.PageExternalTransferData; +import org.apache.fineract.client.models.PageExternalTransferResponse; import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest; -import org.apache.fineract.client.models.PostInitiateTransferResponse; import org.apache.fineract.client.models.PostJournalEntriesResponse; import org.apache.fineract.client.models.PostLoanProductsResponse; import org.apache.fineract.client.models.PostLoansLoanIdRequest; @@ -185,7 +185,7 @@ public void saleActiveLoanToExternalAssetOwnerWithCancelAndBuybackADayLater() { Integer loanID = createLoanForClient(clientID); addPenaltyForLoan(loanID, "10"); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); validateResponse(saleTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02", @@ -193,7 +193,7 @@ public void saleActiveLoanToExternalAssetOwnerWithCancelAndBuybackADayLater() { new BigDecimal("757.420000"), new BigDecimal("10.000000"), new BigDecimal("0.000000"), new BigDecimal("0.000000"))); getAndValidateThereIsNoActiveMapping(saleTransferResponse.getResourceExternalId()); - PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); retrieveResponse.getContent().forEach(transfer -> getAndValidateThereIsNoJournalEntriesForTransfer(transfer.getTransferId())); EXTERNAL_ASSET_OWNER_HELPER.cancelTransferByTransferExternalId(saleTransferResponse.getResourceExternalId()); @@ -207,7 +207,7 @@ public void saleActiveLoanToExternalAssetOwnerWithCancelAndBuybackADayLater() { "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"))); - PostInitiateTransferResponse oldSaleTransferResponse = saleTransferResponse; + ExternalAssetOwnerTransferResponse oldSaleTransferResponse = saleTransferResponse; saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); validateResponse(saleTransferResponse, loanID); @@ -270,7 +270,7 @@ public void saleActiveLoanToExternalAssetOwnerWithCancelAndBuybackADayLater() { ExpectedJournalEntryData.expected((long) TRANSFER_ACCOUNT.getAccountID(), (long) JournalEntryType.CREDIT.getValue(), BigDecimal.valueOf(15767.420000), expectedDate, expectedDate)); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); validateResponse(buybackTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, oldSaleTransferResponse.getResourceExternalId(), "2020-03-02", @@ -380,7 +380,7 @@ public void saleActiveLoanToExternalAssetOwnerAndBuybackADayLater() { Integer loanID = createLoanForClient(clientID); addPenaltyForLoan(loanID, "10"); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); validateResponse(saleTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02", @@ -388,7 +388,7 @@ public void saleActiveLoanToExternalAssetOwnerAndBuybackADayLater() { new BigDecimal("757.420000"), new BigDecimal("10.000000"), new BigDecimal("0.000000"), new BigDecimal("0.000000"))); getAndValidateThereIsNoActiveMapping(saleTransferResponse.getResourceExternalId()); - PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); retrieveResponse.getContent().forEach(transfer -> getAndValidateThereIsNoJournalEntriesForTransfer(transfer.getTransferId())); updateBusinessDateAndExecuteCOBJob("2020-03-03"); @@ -418,7 +418,7 @@ public void saleActiveLoanToExternalAssetOwnerAndBuybackADayLater() { ExpectedJournalEntryData.expected((long) TRANSFER_ACCOUNT.getAccountID(), (long) JournalEntryType.CREDIT.getValue(), BigDecimal.valueOf(15767.420000), expectedDate, expectedDate)); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); validateResponse(buybackTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02", @@ -512,7 +512,7 @@ public void saleOverpaidLoanToExternalAssetOwnerAndBuybackADayLater() { Integer loanID = createLoanForClient(clientID); addPenaltyForLoan(loanID, "10"); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); validateResponse(saleTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02", @@ -520,7 +520,7 @@ public void saleOverpaidLoanToExternalAssetOwnerAndBuybackADayLater() { new BigDecimal("757.420000"), new BigDecimal("10.000000"), new BigDecimal("0.000000"), new BigDecimal("0.000000"))); getAndValidateThereIsNoActiveMapping(saleTransferResponse.getResourceExternalId()); - PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); retrieveResponse.getContent().forEach(transfer -> getAndValidateThereIsNoJournalEntriesForTransfer(transfer.getTransferId())); updateBusinessDateAndExecuteCOBJob("2020-03-03"); @@ -550,7 +550,7 @@ public void saleOverpaidLoanToExternalAssetOwnerAndBuybackADayLater() { ExpectedJournalEntryData.expected((long) TRANSFER_ACCOUNT.getAccountID(), (long) JournalEntryType.CREDIT.getValue(), BigDecimal.valueOf(15767.420000), expectedDate, expectedDate)); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); validateResponse(buybackTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-02", "2020-03-02", @@ -668,7 +668,7 @@ public void saleIsDeclinedWhenLoanIsCancelled() { Integer clientID = createClient(); Integer loanID = createLoanForClient(clientID); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-06"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-06"); updateBusinessDateAndExecuteCOBJob("2020-03-04"); LOAN_TRANSACTION_HELPER.writeOffLoan("04 March 2020", loanID); @@ -691,9 +691,9 @@ public void buybackIsExecutedWhenLoanIsCancelled() { Integer clientID = createClient(); Integer loanID = createLoanForClient(clientID); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-04"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-04"); updateBusinessDateAndExecuteCOBJob("2020-03-05"); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-06"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-06"); LOAN_TRANSACTION_HELPER.writeOffLoan("04 March 2020", loanID); @@ -722,8 +722,8 @@ public void buybackAndSaleIsCancelledWhenLoanIsCancelled() { Integer clientID = createClient(); Integer loanID = createLoanForClient(clientID); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-04"); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-06"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-04"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-06"); LOAN_TRANSACTION_HELPER.writeOffLoan("02 March 2020", loanID); @@ -749,8 +749,8 @@ public void sameDayBuybackAndSaleIsCancelledWhenLoanIsCancelled() { Integer clientID = createClient(); Integer loanID = createLoanForClient(clientID); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-03"); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-03"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-03"); LOAN_TRANSACTION_HELPER.writeOffLoan("02 March 2020", loanID); @@ -776,9 +776,9 @@ public void saleAndBuybackOnTheSameDay() { Integer clientID = createClient(); Integer loanID = createLoanForClient(clientID); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-02"); validateResponse(saleTransferResponse, loanID); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-02"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-02"); validateResponse(buybackTransferResponse, loanID); getAndValidateExternalAssetOwnerTransferByLoan(loanID, @@ -826,8 +826,8 @@ public void saleAndBuybackMultipleTimes() { Integer clientID = createClient(); Integer loanID = createLoanForClient(clientID); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-04"); - PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-04"); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, "2020-03-04"); + ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2020-03-04"); getAndValidateExternalAssetOwnerTransferByLoan(loanID, ExpectedExternalTransferData.expected(PENDING, saleTransferResponse.getResourceExternalId(), "2020-03-04", "2020-03-02", @@ -938,7 +938,7 @@ public void saleExceptionHandling() { Integer loanIDForOwnerTransfer = createLoanForClient(clientID); createSaleTransfer(loanIDForOwnerTransfer, "2020-03-03"); updateBusinessDateAndExecuteCOBJob("2020-03-04"); - PostInitiateTransferResponse ownerToOwnerSaleResponse = createSaleTransfer(loanIDForOwnerTransfer, "2020-03-05"); + ExternalAssetOwnerTransferResponse ownerToOwnerSaleResponse = createSaleTransfer(loanIDForOwnerTransfer, "2020-03-05"); assertNotNull(ownerToOwnerSaleResponse.getResourceId()); String externalId = UUID.randomUUID().toString(); String transferExternalGroupId = UUID.randomUUID().toString(); @@ -1223,7 +1223,7 @@ public void transactionSummaryReportWithAssetOwner_CheckFromAssetOwnerIdForBuyba final Integer loanID = createLoanForClient(clientID); // Create first sale transfer - final PostInitiateTransferResponse firstSaleTransferResponse = createSaleTransfer(loanID, "2023-08-16"); + final ExternalAssetOwnerTransferResponse firstSaleTransferResponse = createSaleTransfer(loanID, "2023-08-16"); validateResponse(firstSaleTransferResponse, loanID); // Verify the transfer is PENDING initially @@ -1248,14 +1248,14 @@ public void transactionSummaryReportWithAssetOwner_CheckFromAssetOwnerIdForBuyba new BigDecimal("0.000000"))); // Get the owner ID of the first transfer for later verification - PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); assertNotNull(retrieveResponse.getContent().get(1).getOwner()); final String firstOwnerId = retrieveResponse.getContent().get(1).getOwner().getExternalId(); assertNull(retrieveResponse.getContent().get(1).getPreviousOwner(), "First sale transfer should not have previous_owner_id"); // Create buyback transfer updateBusinessDateAndExecuteCOBJob("2023-08-18"); - final PostInitiateTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2023-08-18"); + final ExternalAssetOwnerTransferResponse buybackTransferResponse = createBuybackTransfer(loanID, "2023-08-18"); validateResponse(buybackTransferResponse, loanID); // Execute COB job to process buyback @@ -1340,8 +1340,8 @@ public void addManualJournalEntriesWithAssetExternalization() { loanTransactionHelper.disburseLoan(loanId, new PostLoansLoanIdRequest().actualDisbursementDate(operationDate) .dateFormat(DATETIME_PATTERN).transactionAmount(BigDecimal.valueOf(1000.0)).locale("en")); - PostInitiateTransferResponse transferResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanId, "sale", - new ExternalAssetOwnerRequest().settlementDate("2025-04-20").dateFormat("yyyy-MM-dd").locale("en") + ExternalAssetOwnerTransferResponse transferResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanId, "sale", + new ExternalAssetOwnerSaleRequest().settlementDate("2025-04-20").dateFormat("yyyy-MM-dd").locale("en") .transferExternalId(externalAssetOwner).transferExternalGroupId(null).ownerExternalId(externalAssetOwner) .purchasePriceRatio("0.90")); assertEquals(externalAssetOwner, transferResponse.getResourceExternalId()); @@ -1385,7 +1385,7 @@ public void saleTransferWithSameOwnerExternalIdInParallelShouldNotFail() { final ExecutorService executorService = Executors.newFixedThreadPool(threadCount); final CountDownLatch startLatch = new CountDownLatch(1); final CountDownLatch doneLatch = new CountDownLatch(threadCount); - final List results = Collections.synchronizedList(new ArrayList<>()); + final List results = Collections.synchronizedList(new ArrayList<>()); final List exceptions = Collections.synchronizedList(new ArrayList<>()); for (int i = 0; i < threadCount; i++) { @@ -1393,9 +1393,9 @@ public void saleTransferWithSameOwnerExternalIdInParallelShouldNotFail() { executorService.execute(() -> { try { startLatch.await(); - PostInitiateTransferResponse response = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), - "sale", - new ExternalAssetOwnerRequest().settlementDate("2020-03-02").dateFormat("yyyy-MM-dd").locale("en") + ExternalAssetOwnerTransferResponse response = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId( + loanID.longValue(), "sale", + new ExternalAssetOwnerSaleRequest().settlementDate("2020-03-02").dateFormat("yyyy-MM-dd").locale("en") .transferExternalId(UUID.randomUUID().toString()) .transferExternalGroupId(UUID.randomUUID().toString()).ownerExternalId(sharedOwnerExternalId) .purchasePriceRatio("1.0")); @@ -1423,7 +1423,7 @@ public void saleTransferWithSameOwnerExternalIdInParallelShouldNotFail() { // Verify all transfers reference the same owner for (Integer loanID : loanIDs) { - PageExternalTransferData transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse transfers = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); assertEquals(1, transfers.getTotalElements()); assertNotNull(transfers.getContent()); assertNotNull(transfers.getContent().getFirst().getOwner()); @@ -1443,31 +1443,31 @@ private void updateBusinessDateAndExecuteCOBJob(String date) { SCHEDULER_JOB_HELPER.executeAndAwaitJob("Loan COB"); } - private PostInitiateTransferResponse createSaleTransfer(Integer loanID, String settlementDate) { + private ExternalAssetOwnerTransferResponse createSaleTransfer(Integer loanID, String settlementDate) { String transferExternalId = UUID.randomUUID().toString(); String transferExternalGroupId = UUID.randomUUID().toString(); ownerExternalId = UUID.randomUUID().toString(); return createSaleTransfer(loanID, settlementDate, transferExternalId, transferExternalGroupId, ownerExternalId, "1.0"); } - private PostInitiateTransferResponse createSaleTransfer(Integer loanID, String settlementDate, String transferExternalId, + private ExternalAssetOwnerTransferResponse createSaleTransfer(Integer loanID, String settlementDate, String transferExternalId, String transferExternalGroupId, String ownerExternalId, String purchasePriceRatio) { - PostInitiateTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "sale", - new ExternalAssetOwnerRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") + ExternalAssetOwnerTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), "sale", + new ExternalAssetOwnerSaleRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") .transferExternalId(transferExternalId).transferExternalGroupId(transferExternalGroupId) .ownerExternalId(ownerExternalId).purchasePriceRatio(purchasePriceRatio)); assertEquals(transferExternalId, saleResponse.getResourceExternalId()); return saleResponse; } - private PostInitiateTransferResponse createBuybackTransfer(Integer loanID, String settlementDate) { + private ExternalAssetOwnerTransferResponse 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 ExternalAssetOwnerRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") + private ExternalAssetOwnerTransferResponse createBuybackTransfer(Integer loanID, String settlementDate, String transferExternalId) { + ExternalAssetOwnerTransferResponse saleResponse = EXTERNAL_ASSET_OWNER_HELPER.initiateTransferByLoanId(loanID.longValue(), + "buyback", new ExternalAssetOwnerSaleRequest().settlementDate(settlementDate).dateFormat("yyyy-MM-dd").locale("en") .transferExternalId(transferExternalId)); assertEquals(transferExternalId, saleResponse.getResourceExternalId()); return saleResponse; @@ -1572,17 +1572,17 @@ private HashMap collaterals(Integer collateralId, BigDecimal qua } private void getAndValidateExternalAssetOwnerTransferByLoan(Integer loanID, ExpectedExternalTransferData... expectedItems) { - PageExternalTransferData retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); + PageExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()); assertEquals(expectedItems.length, retrieveResponse.getNumberOfElements()); for (ExpectedExternalTransferData expected : expectedItems) { assertNotNull(retrieveResponse.getContent()); - Optional first = retrieveResponse.getContent().stream() + Optional 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(); + ExternalTransferResponse etd = first.get(); assertEquals(expected.transferExternalId, etd.getTransferExternalId()); assertEquals(expected.status, etd.getStatus()); @@ -1607,24 +1607,25 @@ private void getAndValidateExternalAssetOwnerTransferByLoan(Integer loanID, Expe } private void getAndValidateThereIsActiveMapping(Integer loanID) { - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId((long) loanID); + ExternalTransferResponse 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(); + ExternalTransferResponse retrieveResponse = EXTERNAL_ASSET_OWNER_HELPER.retrieveTransfersByLoanId(loanID.longValue()).getContent() + .stream().filter(transfer -> ExternalTransferResponse.StatusEnum.ACTIVE.equals(transfer.getStatus())).findFirst().get(); assertEquals(retrieveResponse.getTransferId(), activeTransfer.getTransferId()); } private void getAndValidateThereIsNoActiveMapping(Long loanId) { - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanId); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByLoanId(loanId); assertNull(activeTransfer); } private void getAndValidateThereIsNoActiveMapping(String transferExternalId) { - ExternalTransferData activeTransfer = EXTERNAL_ASSET_OWNER_HELPER.retrieveActiveTransferByTransferExternalId(transferExternalId); + ExternalTransferResponse activeTransfer = EXTERNAL_ASSET_OWNER_HELPER + .retrieveActiveTransferByTransferExternalId(transferExternalId); assertNull(activeTransfer); } - private void validateResponse(PostInitiateTransferResponse transferResponse, Integer loanID) { + private void validateResponse(ExternalAssetOwnerTransferResponse transferResponse, Integer loanID) { assertNotNull(transferResponse); assertNotNull(transferResponse.getResourceId()); assertNotNull(transferResponse.getResourceExternalId()); @@ -1635,7 +1636,7 @@ private void validateResponse(PostInitiateTransferResponse transferResponse, Int } private void getAndValidateOwnerJournalEntries(String ownerExternalId, ExpectedJournalEntryData... expectedItems) { - ExternalOwnerJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfOwner(ownerExternalId); + ExternalOwnerJournalEntryResponse result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfOwner(ownerExternalId); assertNotNull(result); assertEquals(expectedItems.length, result.getJournalEntryData().getTotalElements()); int i = 0; @@ -1651,7 +1652,7 @@ private void getAndValidateOwnerJournalEntries(String ownerExternalId, ExpectedJ } private void getAndValidateThereIsJournalEntriesForTransfer(Long transferId, ExpectedJournalEntryData... expectedItems) { - ExternalOwnerTransferJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); + ExternalOwnerTransferJournalEntryResponse result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); assertNotNull(result); long totalElements = result.getJournalEntryData().getTotalElements(); assertEquals(expectedItems.length, totalElements); @@ -1668,14 +1669,14 @@ private void getAndValidateThereIsJournalEntriesForTransfer(Long transferId, Exp } private void getAndValidateThereIsNoJournalEntriesForTransfer(Long transferId) { - ExternalOwnerTransferJournalEntryData result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); + ExternalOwnerTransferJournalEntryResponse result = EXTERNAL_ASSET_OWNER_HELPER.retrieveJournalEntriesOfTransfer(transferId); assertNull(result.getJournalEntryData()); } @RequiredArgsConstructor() public static class ExpectedExternalTransferData { - private final ExternalTransferData.StatusEnum status; + private final ExternalTransferResponse.StatusEnum status; private final String transferExternalId; @@ -1683,7 +1684,7 @@ public static class ExpectedExternalTransferData { private final String effectiveFrom; private final String effectiveTo; - private final ExternalTransferData.SubStatusEnum subStatus; + private final ExternalTransferResponse.SubStatusEnum subStatus; private final boolean detailsExpected; private final BigDecimal totalOutstanding; @@ -1693,7 +1694,7 @@ public static class ExpectedExternalTransferData { private final BigDecimal totalFeeOutstanding; private final BigDecimal totalOverpaid; - static ExpectedExternalTransferData expected(ExternalTransferData.StatusEnum status, String transferExternalId, + static ExpectedExternalTransferData expected(ExternalTransferResponse.StatusEnum status, String transferExternalId, String settlementDate, String effectiveFrom, String effectiveTo, boolean detailsExpected, BigDecimal totalOutstanding, BigDecimal totalPrincipalOutstanding, BigDecimal totalInterestOutstanding, BigDecimal totalPenaltyOutstanding, BigDecimal totalFeeOutstanding, BigDecimal totalOverpaid) { @@ -1702,14 +1703,14 @@ static ExpectedExternalTransferData expected(ExternalTransferData.StatusEnum sta totalFeeOutstanding, totalOverpaid); } - static ExpectedExternalTransferData expected(ExternalTransferData.StatusEnum status, String transferExternalId, + static ExpectedExternalTransferData expected(ExternalTransferResponse.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) { + static ExpectedExternalTransferData expected(ExternalTransferResponse.StatusEnum status, String transferExternalId, + String settlementDate, String effectiveFrom, String effectiveTo, ExternalTransferResponse.SubStatusEnum subStatus) { return new ExpectedExternalTransferData(status, transferExternalId, settlementDate, effectiveFrom, effectiveTo, subStatus, false, null, null, null, null, null, null); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/SearchExternalAssetOwnerTransferTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/SearchExternalAssetOwnerTransferTest.java index 30267956adb..a2f70c3d29a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/SearchExternalAssetOwnerTransferTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/investor/externalassetowner/SearchExternalAssetOwnerTransferTest.java @@ -18,19 +18,24 @@ */ 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.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.CANCELLED; +import static org.apache.fineract.client.models.ExternalTransferResponse.StatusEnum.PENDING; 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 java.math.BigDecimal; import java.time.LocalDate; +import java.util.Objects; +import java.util.Optional; import java.util.UUID; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.ExternalAssetOwnerTransferResponse; +import org.apache.fineract.client.models.ExternalTransferData; +import org.apache.fineract.client.models.ExternalTransferResponse; 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.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.common.Utils; import org.junit.jupiter.api.Test; @@ -50,7 +55,7 @@ public void saleActiveLoanToExternalAssetOwnerWithSearching() { Integer loanID = createLoanForClient(clientID, "29 February 2020"); addPenaltyForLoan(loanID, "10"); - PostInitiateTransferResponse saleTransferResponse = createSaleTransfer(loanID, baseDate); + ExternalAssetOwnerTransferResponse saleTransferResponse = createSaleTransfer(loanID, baseDate); validateResponse(saleTransferResponse, loanID); // LookUp by ExternalId @@ -203,4 +208,81 @@ private void validateResponse(PageExternalTransferData response, final Integer s assertEquals(true, response.getFirst()); } + private void validateExternalAssetOwnerTransfer(PageExternalTransferData response, ExpectedExternalTransferData... expectedItems) { + for (ExpectedExternalTransferData expected : expectedItems) { + assertNotNull(response.getContent()); + Optional first = response.getContent().stream() + .filter(e -> Objects.equals(e.getTransferExternalId(), expected.transferExternalId) + && Objects.equals(e.getStatus().name(), expected.status.name())) + .findFirst(); + assertTrue(first.isPresent(), "Expected transfer not found. transferExternalId=" + expected.transferExternalId + ", status=" + + expected.status + ", actualContent=" + response.getContent()); + ExternalTransferData etd = first.get(); + assertEquals(expected.transferExternalId, etd.getTransferExternalId()); + assertEquals(expected.status.name(), etd.getStatus().name()); + 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.name(), etd.getSubStatus().name()); + } + } + } + + public static final class ExpectedExternalTransferData { + + private final ExternalTransferResponse.StatusEnum status; + private final String transferExternalId; + private final String settlementDate; + private final String effectiveFrom; + private final String effectiveTo; + private final ExternalTransferResponse.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; + + private ExpectedExternalTransferData(ExternalTransferResponse.StatusEnum status, String transferExternalId, String settlementDate, + String effectiveFrom, String effectiveTo, ExternalTransferResponse.SubStatusEnum subStatus, boolean detailsExpected, + BigDecimal totalOutstanding, BigDecimal totalPrincipalOutstanding, BigDecimal totalInterestOutstanding, + BigDecimal totalPenaltyOutstanding, BigDecimal totalFeeOutstanding, BigDecimal totalOverpaid) { + this.status = status; + this.transferExternalId = transferExternalId; + this.settlementDate = settlementDate; + this.effectiveFrom = effectiveFrom; + this.effectiveTo = effectiveTo; + this.subStatus = subStatus; + this.detailsExpected = detailsExpected; + this.totalOutstanding = totalOutstanding; + this.totalPrincipalOutstanding = totalPrincipalOutstanding; + this.totalInterestOutstanding = totalInterestOutstanding; + this.totalPenaltyOutstanding = totalPenaltyOutstanding; + this.totalFeeOutstanding = totalFeeOutstanding; + this.totalOverpaid = totalOverpaid; + } + + static ExpectedExternalTransferData expected(ExternalTransferResponse.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); + } + } + }