diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanMerchantIssuedRefund.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanMerchantIssuedRefund.feature index 81dfa1f8a91..f517fe05495 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanMerchantIssuedRefund.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanMerchantIssuedRefund.feature @@ -695,3 +695,118 @@ Feature: MerchantIssuedRefund | 01 February 2025 | Interest Refund | 1.46 | 1.46 | 0.0 | 0.0 | 0.0 | 23.34 | false | true | #following steps will fail if Interest Refund is not recalculated properly Then Loan has 23.97 outstanding amount + + @TestRailId:C4541 + Scenario: Verify MIR and CBR with adjust interest afterwards outcomes with proper allocations on account + When Admin sets the business date to "24 September 2024" + And Admin creates a client with random data + And 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_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 24 September 2024 | 116.89 | 35.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "24 September 2024" with "116.89" amount and expected disbursement date on "24 September 2024" + And Admin successfully disburse the loan on "24 September 2024" with "116.89" EUR transaction amount + Then Loan Repayment schedule has 3 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 24 September 2024 | | 116.89 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 30 | 24 October 2024 | | 79.08 | 37.81 | 3.51 | 0.0 | 0.0 | 41.32 | 0.0 | 0.0 | 0.0 | 41.32 | + | 2 | 31 | 24 November 2024 | | 40.13 | 38.95 | 2.37 | 0.0 | 0.0 | 41.32 | 0.0 | 0.0 | 0.0 | 41.32 | + | 3 | 30 | 24 December 2024 | | 0.0 | 40.13 | 1.2 | 0.0 | 0.0 | 41.33 | 0.0 | 0.0 | 0.0 | 41.33 | + And Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.89 | 7.08 | 0.0 | 0.0 | 123.97 | 0.0 | 0.0 | 0.0 | 123.97 | + And Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 24 September 2024 | Disbursement | 116.89 | 0.0 | 0.0 | 0.0 | 0.0 | 116.89 | false | false | +# --- repayment transaction --- # + When Admin sets the business date to "26 September 2024" + And Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "26 September 2024" with 117.12 EUR transaction amount and system-generated Idempotency key + Then Loan Repayment schedule has 3 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 24 September 2024 | | 116.89 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 30 | 24 October 2024 | 26 September 2024 | 75.8 | 41.09 | 0.23 | 0.0 | 0.0 | 41.32 | 41.32 | 41.32 | 0.0 | 0.0 | + | 2 | 31 | 24 November 2024 | 26 September 2024 | 34.48 | 41.32 | 0.0 | 0.0 | 0.0 | 41.32 | 41.32 | 41.32 | 0.0 | 0.0 | + | 3 | 30 | 24 December 2024 | 26 September 2024 | 0.0 | 34.48 | 0.0 | 0.0 | 0.0 | 34.48 | 34.48 | 34.48 | 0.0 | 0.0 | + And Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.89 | 0.23 | 0.0 | 0.0 | 117.12 | 117.12 | 117.12 | 0.0 | 0.0 | + And Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 24 September 2024 | Disbursement | 116.89 | 0.0 | 0.0 | 0.0 | 0.0 | 116.89 | false | false | + | 26 September 2024 | Repayment | 117.12 | 116.89 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 26 September 2024 | Accrual | 0.23 | 0.0 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 26 September 2024 | Accrual Activity | 0.23 | 0.0 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | +# --- Merchant Issue Refund transaction --- # + When Admin sets the business date to "06 October 2024" + Then Customer makes "MERCHANT_ISSUED_REFUND" transaction with "AUTOPAY" payment type on "06 October 2024" with 8.13 EUR transaction amount and system-generated Idempotency key + Then Loan has 0 outstanding amount + Then Loan status will be "OVERPAID" + Then Loan has 8.14 overpaid amount + Then Loan Repayment schedule has 3 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 24 September 2024 | | 116.89 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 30 | 24 October 2024 | 26 September 2024 | 75.8 | 41.09 | 0.23 | 0.0 | 0.0 | 41.32 | 41.32 | 41.32 | 0.0 | 0.0 | + | 2 | 31 | 24 November 2024 | 26 September 2024 | 34.48 | 41.32 | 0.0 | 0.0 | 0.0 | 41.32 | 41.32 | 41.32 | 0.0 | 0.0 | + | 3 | 30 | 24 December 2024 | 26 September 2024 | 0.0 | 34.48 | 0.0 | 0.0 | 0.0 | 34.48 | 34.48 | 34.48 | 0.0 | 0.0 | + And Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.89 | 0.23 | 0.0 | 0.0 | 117.12 | 117.12 | 117.12 | 0.0 | 0.0 | + And Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 24 September 2024 | Disbursement | 116.89 | 0.0 | 0.0 | 0.0 | 0.0 | 116.89 | false | false | + | 26 September 2024 | Repayment | 117.12 | 116.89 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 26 September 2024 | Accrual | 0.23 | 0.0 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 26 September 2024 | Accrual Activity | 0.23 | 0.0 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 06 October 2024 | Merchant Issued Refund | 8.13 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 06 October 2024 | Interest Refund | 0.01 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | +# --- Credit Balance Refund transaction --- # + When Admin sets the business date to "07 October 2024" + And Admin makes Credit Balance Refund transaction on "07 October 2024" with 8.14 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + Then Loan Repayment schedule has 3 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 24 September 2024 | | 116.89 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 30 | 24 October 2024 | 26 September 2024 | 75.8 | 41.09 | 0.23 | 0.0 | 0.0 | 41.32 | 41.32 | 41.32 | 0.0 | 0.0 | + | 2 | 31 | 24 November 2024 | 26 September 2024 | 34.48 | 41.32 | 0.0 | 0.0 | 0.0 | 41.32 | 41.32 | 41.32 | 0.0 | 0.0 | + | 3 | 30 | 24 December 2024 | 26 September 2024 | 0.0 | 34.48 | 0.0 | 0.0 | 0.0 | 34.48 | 34.48 | 34.48 | 0.0 | 0.0 | + And Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.89 | 0.23 | 0.0 | 0.0 | 117.12 | 117.12 | 117.12 | 0.0 | 0.0 | + And Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 24 September 2024 | Disbursement | 116.89 | 0.0 | 0.0 | 0.0 | 0.0 | 116.89 | false | false | + | 26 September 2024 | Accrual | 0.23 | 0.0 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 26 September 2024 | Repayment | 117.12 | 116.89 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 26 September 2024 | Accrual Activity | 0.23 | 0.0 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 06 October 2024 | Merchant Issued Refund | 8.13 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 06 October 2024 | Interest Refund | 0.01 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 07 October 2024 | Credit Balance Refund | 8.14 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | +# --- loan reschedule with new interest rate --- # + When Admin sets the business date to "30 October 2024" + When Admin creates and approves Loan reschedule with the following data: + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 25 September 2024 | 30 October 2024 | | | | | 25.99 | + Then Loan has 0 outstanding amount + Then Loan status will be "OVERPAID" + Then Loan has 0.1 overpaid amount + Then Loan Repayment schedule has 3 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 24 September 2024 | | 116.89 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 30 | 24 October 2024 | 26 September 2024 | 76.4 | 40.49 | 0.17 | 0.0 | 0.0 | 40.66 | 40.66 | 40.66 | 0.0 | 0.0 | + | 2 | 31 | 24 November 2024 | 26 September 2024 | 35.74 | 40.66 | 0.0 | 0.0 | 0.0 | 40.66 | 40.66 | 40.66 | 0.0 | 0.0 | + | 3 | 30 | 24 December 2024 | 26 September 2024 | 0.0 | 35.74 | 0.0 | 0.0 | 0.0 | 35.74 | 35.74 | 35.74 | 0.0 | 0.0 | + And Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.89 | 0.17 | 0.0 | 0.0 | 117.06 | 117.06 | 117.06 | 0.0 | 0.0 | + And Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 24 September 2024 | Disbursement | 116.89 | 0.0 | 0.0 | 0.0 | 0.0 | 116.89 | false | false | + | 26 September 2024 | Accrual | 0.23 | 0.0 | 0.23 | 0.0 | 0.0 | 0.0 | false | false | + | 26 September 2024 | Repayment | 117.12 | 116.89 | 0.17 | 0.0 | 0.0 | 0.0 | false | true | + | 26 September 2024 | Accrual Activity | 0.17 | 0.0 | 0.17 | 0.0 | 0.0 | 0.0 | false | true | + | 06 October 2024 | Merchant Issued Refund | 8.13 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 06 October 2024 | Interest Refund | 0.05 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true | + | 07 October 2024 | Credit Balance Refund | 8.14 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 30 October 2024 | Accrual Adjustment | 0.06 | 0.0 | 0.06 | 0.0 | 0.0 | 0.0 | false | false | + And Admin makes Credit Balance Refund transaction on "30 October 2024" with 0.1 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/ApproveLoanRescheduleRequestCommandHandler.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/ApproveLoanRescheduleRequestCommandHandler.java index 20964b6199c..04f0d957147 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/ApproveLoanRescheduleRequestCommandHandler.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/ApproveLoanRescheduleRequestCommandHandler.java @@ -18,26 +18,22 @@ */ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.handler; +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.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service +@RequiredArgsConstructor @CommandType(entity = "RESCHEDULELOAN", action = "APPROVE") public class ApproveLoanRescheduleRequestCommandHandler implements NewCommandSourceHandler { private final LoanRescheduleRequestWritePlatformService loanRescheduleRequestWritePlatformService; - @Autowired - public ApproveLoanRescheduleRequestCommandHandler(LoanRescheduleRequestWritePlatformService loanRescheduleRequestWritePlatformService) { - this.loanRescheduleRequestWritePlatformService = loanRescheduleRequestWritePlatformService; - } - @Transactional @Override public CommandProcessingResult processCommand(JsonCommand jsonCommand) { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/CreateLoanRescheduleRequestCommandHandler.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/CreateLoanRescheduleRequestCommandHandler.java index e8dbda6b7c3..f2b98050c9e 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/CreateLoanRescheduleRequestCommandHandler.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/CreateLoanRescheduleRequestCommandHandler.java @@ -18,26 +18,22 @@ */ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.handler; +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.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service +@RequiredArgsConstructor @CommandType(entity = "RESCHEDULELOAN", action = "CREATE") public class CreateLoanRescheduleRequestCommandHandler implements NewCommandSourceHandler { private final LoanRescheduleRequestWritePlatformService loanRescheduleRequestWritePlatformService; - @Autowired - public CreateLoanRescheduleRequestCommandHandler(LoanRescheduleRequestWritePlatformService loanRescheduleRequestWritePlatformService) { - this.loanRescheduleRequestWritePlatformService = loanRescheduleRequestWritePlatformService; - } - @Transactional @Override public CommandProcessingResult processCommand(JsonCommand jsonCommand) { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/RejectLoanRescheduleRequestCommandHandler.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/RejectLoanRescheduleRequestCommandHandler.java index a57eed4a420..2004cbb8815 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/RejectLoanRescheduleRequestCommandHandler.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/handler/RejectLoanRescheduleRequestCommandHandler.java @@ -18,26 +18,22 @@ */ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.handler; +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.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestWritePlatformService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service +@RequiredArgsConstructor @CommandType(entity = "RESCHEDULELOAN", action = "REJECT") public class RejectLoanRescheduleRequestCommandHandler implements NewCommandSourceHandler { private final LoanRescheduleRequestWritePlatformService loanRescheduleRequestWritePlatformService; - @Autowired - public RejectLoanRescheduleRequestCommandHandler(LoanRescheduleRequestWritePlatformService loanRescheduleRequestWritePlatformService) { - this.loanRescheduleRequestWritePlatformService = loanRescheduleRequestWritePlatformService; - } - @Transactional @Override public CommandProcessingResult processCommand(JsonCommand jsonCommand) { diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java index 4ed75b60318..9ec13b358c1 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java @@ -573,7 +573,7 @@ private void handleInterestRefund(final LoanTransaction loanTransaction, final T final Money interestAfterRefund = interestRefundService.totalInterestByTransactions(this, loan.getId(), targetDate, modifiedTransactions, unmodifiedTransactionIds); final Money newAmount = interestBeforeRefund.minus(progCtx.getSumOfInterestRefundAmount()).minus(interestAfterRefund); - loanTransaction.updateAmount(newAmount.getAmount()); + loanTransaction.updateAmount(newAmount.abs().getAmount()); } progCtx.setSumOfInterestRefundAmount(progCtx.getSumOfInterestRefundAmount().add(loanTransaction.getAmount())); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java index c56458dce06..ca09e0ac127 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRefundTransactionTest.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.integrationtests; +import static org.junit.jupiter.api.Assertions.assertTrue; + import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; @@ -25,11 +27,15 @@ import io.restassured.specification.ResponseSpecification; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicReference; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; +import org.apache.fineract.client.models.PostCreateRescheduleLoansResponse; import org.apache.fineract.client.models.PostLoanProductsResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PostLoansResponse; +import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest; import org.apache.fineract.integrationtests.common.BusinessDateHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper; @@ -153,6 +159,65 @@ public void testMerchantIssuedRefundDoesNotCreateInterestRefundWithLessThanOrEqu }); } + @Test + public void testMerchantIssuedRefundAndCreditBalanceRefundWithAdjustSchedule() { + final AtomicReference loanIdRef = new AtomicReference<>(); + + runAt("24 September 2025", () -> { + final Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + final Long loanId = createLoanForRefundWithInterestRefund(clientId, "MERCHANT_ISSUED_REFUND", "24 September 2025", 116.89, + 35.99, 3); + loanIdRef.set(loanId); + disburseLoan(loanId, BigDecimal.valueOf(116.89), "24 September 2025"); + }); + + runAt("26 September 2025", () -> { + executeInlineCOB(loanIdRef.get()); + addRepaymentForLoan(loanIdRef.get(), 117.12, "26 September 2025"); + }); + + runAt("06 October 2025", () -> { + executeInlineCOB(loanIdRef.get()); + loanTransactionHelper.makeMerchantIssuedRefund(loanIdRef.get(), new PostLoansLoanIdTransactionsRequest() + .dateFormat(DATETIME_PATTERN).transactionDate("06 October 2025").locale(LOCALE).transactionAmount(8.13)); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanIdRef.get()); + // Validate Loan is Overpaid + assertTrue(loanDetails.getStatus().getOverpaid()); + + validateLoanSummaryBalances(loanDetails, 0.00, 117.12, 0.00, 116.89, 8.14); + }); + + runAt("07 October 2025", () -> { + executeInlineCOB(loanIdRef.get()); + loanTransactionHelper.makeCreditBalanceRefund(loanIdRef.get(), new PostLoansLoanIdTransactionsRequest() + .dateFormat(DATETIME_PATTERN).transactionDate("07 October 2025").locale(LOCALE).transactionAmount(8.14)); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanIdRef.get()); + // Validate Loan is Closed + assertTrue(loanDetails.getStatus().getClosedObligationsMet()); + validateLoanSummaryBalances(loanDetails, 0.00, 117.12, 0.00, 116.89, null); + + PostCreateRescheduleLoansResponse rescheduleLoansResponse = loanRescheduleRequestHelper// + .createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest()// + .loanId(loanIdRef.get())// + .rescheduleReasonId(1L)// + .rescheduleFromDate("25 September 2025").dateFormat(DATETIME_PATTERN).locale(LOCALE)// + .submittedOnDate("07 October 2025")// + .newInterestRate(BigDecimal.valueOf(25.99)));// + + loanRescheduleRequestHelper.approveLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(), // + new PostUpdateRescheduleLoansRequest()// + .approvedOnDate("07 October 2025").locale(LOCALE).dateFormat(DATETIME_PATTERN));// + + loanDetails = loanTransactionHelper.getLoanDetails(loanIdRef.get()); + // Validate Loan is Overpaid + assertTrue(loanDetails.getStatus().getOverpaid()); + + validateLoanSummaryBalances(loanDetails, 0.00, 117.06, 0.00, 116.89, 0.10); + }); + } + private Long createAndDisburseLoanForMerchantIssuedRefundWithInterestRefund(Long clientId) { return createAndDisburseLoanForRefundWithInterestRefund(clientId, "MERCHANT_ISSUED_REFUND"); }