This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 15fcaed61 FINERACT-1971: Loan totalUnpaidPayableNotDueInterest field
has wrong value after maturity
15fcaed61 is described below
commit 15fcaed61ffd7cf1fbaa140eb000b6fe9bc241e9
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Sun Jan 26 23:03:05 2025 -0500
FINERACT-1971: Loan totalUnpaidPayableNotDueInterest field has wrong value
after maturity
---
.../portfolio/loanaccount/domain/Loan.java | 4 ++
.../ProgressiveLoanSummaryDataProvider.java | 3 ++
...PaymentAllocationLoanRepaymentScheduleTest.java | 57 ++++++++++++++++++++++
3 files changed, 64 insertions(+)
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 3a91044ea..e0fa02d6f 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -2666,6 +2666,10 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
return this.actualMaturityDate;
}
+ public boolean isMatured(final LocalDate referenceDate) {
+ return (this.actualMaturityDate != null) ?
(referenceDate.compareTo(this.actualMaturityDate) >= 0) : false;
+ }
+
public ChangedTransactionDetail processTransactions() {
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor = getTransactionProcessor();
final List<LoanTransaction> allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsForReprocessing();
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
index 4eb588fb2..418d011af 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanSummaryDataProvider.java
@@ -80,6 +80,9 @@ public class ProgressiveLoanSummaryDataProvider extends
CommonLoanSummaryDataPro
@Override
public BigDecimal
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final Loan loan,
final Collection<LoanSchedulePeriodData> periods, final LocalDate
businessDate, final CurrencyData currency) {
+ if (loan.isMatured(businessDate)) {
+ return BigDecimal.ZERO;
+ }
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment =
getRelatedRepaymentScheduleInstallment(loan, businessDate);
if (loan.isInterestBearing() && loanRepaymentScheduleInstallment !=
null) {
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
index 671eed4af..fb3b0e4f4 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
@@ -5890,6 +5890,63 @@ public class
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
}
+ // UC154: On the maturity date or after that all the outstanding interest
is due
+ // 1. Submit Loan, approve and Disburse
+ // 2. Run the COB daily until maturity date
+ // 3. After maturity, totalUnpaidPayableNotDueInterest returns must be not
a positive value.
+ @Test
+ public void uc154() {
+ final String operationDate = "23 December 2024";
+ AtomicLong createdLoanId = new AtomicLong();
+ runAt(operationDate, () -> {
+ Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
+ PostLoanProductsRequest product =
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
+
.interestRatePerPeriod(4.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS).interestRateFrequencyType(YEARS)
+
.daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(3)//
+ .repaymentEvery(1)//
+ .repaymentFrequencyType(1L)//
+ .allowPartialPeriodInterestCalcualtion(false)//
+ .multiDisburseLoan(false)//
+ .disallowExpectedDisbursements(null)//
+ .allowApprovedDisbursedAmountsOverApplied(null)//
+ .overAppliedCalculationType(null)//
+ .overAppliedNumber(null)//
+ .installmentAmountInMultiplesOf(null)//
+ ;//
+ PostLoanProductsResponse loanProductResponse =
loanProductHelper.createLoanProduct(product);
+ PostLoansRequest applicationRequest = applyLoanRequest(clientId,
loanProductResponse.getResourceId(), operationDate, 100.0, 3)
+ .interestRatePerPeriod(BigDecimal.valueOf(4.0));
+
+ applicationRequest =
applicationRequest.interestCalculationPeriodType(DAYS)
+
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
+
+ PostLoansResponse loanResponse =
loanTransactionHelper.applyLoan(applicationRequest);
+ createdLoanId.set(loanResponse.getLoanId());
+
+ loanTransactionHelper.approveLoan(loanResponse.getLoanId(), new
PostLoansLoanIdRequest()
+
.approvedLoanAmount(BigDecimal.valueOf(100.0)).dateFormat(DATETIME_PATTERN).approvedOnDate(operationDate).locale("en"));
+
+ loanTransactionHelper.disburseLoan(loanResponse.getLoanId(), new
PostLoansLoanIdRequest().actualDisbursementDate(operationDate)
+
.dateFormat(DATETIME_PATTERN).transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));
+
+ // After Disbursement we are expecting amount in Zero
+ GetLoansLoanIdResponse loanDetails =
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+ assertEquals(BigDecimal.ZERO,
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+ assertEquals(BigDecimal.ZERO,
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+ });
+
+ runAt("23 March 2025", () -> {
+ executeInlineCOB(createdLoanId.get());
+ GetLoansLoanIdResponse loanDetails =
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+ // totalUnpaidPayableDueInterest → Total outstanding interest
amount on all the periods that are before
+
assertEquals(BigDecimal.valueOf(loanDetails.getSummary().getInterestCharged()).stripTrailingZeros(),
+
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+ // Total outstanding interest amount on the current period, if the
current period due date is after than the
+ // current date
+ assertEquals(BigDecimal.ZERO,
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+ });
+ }
+
private Long
applyAndApproveLoanProgressiveAdvancedPaymentAllocationStrategyMonthlyRepayments(Long
clientId, Long loanProductId,
Integer numberOfRepayments, String loanDisbursementDate, double
amount) {
LOG.info("------------------------------APPLY AND APPROVE LOAN
---------------------------------------");