diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/account/AccountTransferStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/account/AccountTransferStepDef.java index fe92a4b4014..4f2820807f7 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/account/AccountTransferStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/account/AccountTransferStepDef.java @@ -69,6 +69,24 @@ public void undoAccountTransfer() { ok(() -> fineractClient.accountTransfers().accountTransferOperation(response.getResourceId(), "undo")); } + @When("Initiate account transfer from loan to savings on {string} for {double}") + public void initiateLoanToSavingsTransfer(String date, double amount) { + PostClientsResponse clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE); + long clientId = clientResponse.getClientId(); + long savingsId = ((PostSavingsAccountsResponse) testContext().get(TestContextKey.EUR_SAVINGS_ACCOUNT_CREATE_RESPONSE)) + .getSavingsId(); + long loanId = ((PostLoansResponse) testContext().get(TestContextKey.LOAN_CREATE_RESPONSE)).getLoanId(); + + AccountTransferRequest request = new AccountTransferRequest().fromClientId(String.valueOf(clientId)) + .fromAccountId(String.valueOf(loanId)).fromAccountType(LOAN_ACCOUNT_TYPE).fromOfficeId("1") + .toClientId(String.valueOf(clientId)).toAccountId(String.valueOf(savingsId)).toAccountType(SAVINGS_ACCOUNT_TYPE) + .toOfficeId("1").transferDate(date).transferAmount(String.valueOf(amount)).transferDescription("Transfer") + .dateFormat(DATE_FORMAT).locale(DEFAULT_LOCALE); + + PostAccountTransfersResponse response = ok(() -> fineractClient.accountTransfers().createAccountTransfer(request)); + testContext().set("accountTransferResponse", response); + } + @When("Undo the last account transfer it fails with error: it is already reverted") public void undoAccountTransferFail() { PostAccountTransfersResponse response = testContext().get("accountTransferResponse"); diff --git a/fineract-e2e-tests-runner/src/test/resources/features/AccountTransfer.feature b/fineract-e2e-tests-runner/src/test/resources/features/AccountTransfer.feature index 710f02477ce..9ae216fbb06 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/AccountTransfer.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/AccountTransfer.feature @@ -27,6 +27,7 @@ Feature: AccountTransfer | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 01 May 2026 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | | 02 May 2026 | Repayment | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 990.0 | false | false | + Then Loan has 990 outstanding amount When Undo the last account transfer Then Savings Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Balance | Reverted | @@ -36,4 +37,44 @@ Feature: AccountTransfer | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 01 May 2026 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | | 02 May 2026 | Repayment | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 990.0 | true | false | + Then Loan has 1000 outstanding amount + When Undo the last account transfer it fails with error: it is already reverted + + @TestRailId:C80938 + Scenario: Transfer from loan to savings then undo it + When Admin sets the business date to "13 May 2026" + And Admin creates a client with random data + And Admin creates a EUR savings product + And Client creates a new EUR savings account with "01 May 2026" submitted on date + And Approve EUR savings account on "01 May 2026" date + And Activate EUR savings account on "01 May 2026" date + And Client successfully deposits 1000 EUR to the savings account on "01 May 2026" date + Then Savings Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Balance | + | 01 May 2026 | Deposit | 1000.0 | 1000.0 | + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30 | 01 May 2026 | 1000 | 12 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 May 2026" with "1000" amount and expected disbursement date on "01 May 2026" + When Admin successfully disburse the loan on "01 May 2026" with "1000" EUR transaction amount + When Initiate account transfer from loan to savings on "2 May 2026" for 10 + Then Savings Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Balance | + | 01 May 2026 | Deposit | 1000.0 | 1000.0 | + | 02 May 2026 | Deposit | 10.0 | 1010.0 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 May 2026 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | + | 02 May 2026 | Refund | 10.0 | 0.0 | 0.0 | 0.0 | 0.0 | 990.0 | false | false | + Then Loan has 990 outstanding amount + When Undo the last account transfer + Then Savings Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Balance | Reverted | + | 01 May 2026 | Deposit | 1000.0 | 1000.0 | false | + | 02 May 2026 | Deposit | 10.0 | 0.0 | true | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 May 2026 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | + | 02 May 2026 | Refund | 10.0 | 0.0 | 0.0 | 0.0 | 0.0 | 990.0 | true | false | + Then Loan has 1000 outstanding amount When Undo the last account transfer it fails with error: it is already reverted diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java index b5a6c7da708..5c1c65ace0d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java @@ -532,7 +532,12 @@ public CommandProcessingResult undo(JsonCommand command) { transaction.reverse(); }); } else if (isLoanToSavingsAccountTransfer(fromAccountType, toAccountType)) { - throw new UnsupportedOperationException("Undo Loan to Savings Account Transfer is not implemented"); + accountTransferDetails.getAccountTransferTransactions().forEach(transaction -> { + this.savingsAccountWritePlatformService.undoTransaction(transaction.getToSavingsTransaction().getSavingsAccount().getId(), + transaction.getToSavingsTransaction().getId(), true); + this.loanAccountDomainService.reverseTransfer(transaction.getFromLoanTransaction()); + transaction.reverse(); + }); } final CommandProcessingResultBuilder builder = new CommandProcessingResultBuilder() //