FINERACT-1971 Repayment schedule period - Incorrect values after charge with huge amount

This commit is contained in:
Jose Alberto Hernandez
2025-02-14 10:29:48 +01:00
committed by Adam Saghy
parent d9414a6e7e
commit 22f7972f60
6 changed files with 53 additions and 13 deletions
@@ -269,9 +269,13 @@ public final class MathUtil {
/** @return sum the values considering null values */
public static BigDecimal add(BigDecimal... amounts) {
return add(MoneyHelper.getMathContext(), amounts);
}
public static BigDecimal add(MathContext mc, BigDecimal... amounts) {
BigDecimal result = null;
for (BigDecimal amount : amounts) {
result = add(result, amount, MoneyHelper.getMathContext());
result = add(result, amount, mc);
}
return result;
}
@@ -33,7 +33,7 @@ public class MoneyHelper {
private static RoundingMode roundingMode = null;
private static MathContext mathContext;
private static final int PRECISION = 12;
public static final int PRECISION = 19;
private static ConfigurationDomainService staticConfigurationDomainService;
@@ -19,11 +19,13 @@
package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
import lombok.Builder;
import lombok.Getter;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
/**
* Immutable data object that represents a period of a loan schedule.
@@ -156,11 +158,13 @@ public final class LoanSchedulePeriodData {
final BigDecimal totalPaidLateForPeriod, final BigDecimal totalWaived, final BigDecimal totalWrittenOff,
final BigDecimal totalCredits, final boolean isDownPayment, final BigDecimal totalAccruedInterest) {
BigDecimal totalDue = MathUtil.add(principalOriginalDue, interestDue, feeChargesDue, penaltyChargesDue);
BigDecimal totalOutstanding = MathUtil.add(principalOutstanding, interestOutstanding, feeChargesOutstanding,
final MathContext mc = MoneyHelper.getMathContext();
BigDecimal totalDue = MathUtil.add(mc, principalOriginalDue, interestDue, feeChargesDue, penaltyChargesDue);
BigDecimal totalOutstanding = MathUtil.add(mc, principalOutstanding, interestOutstanding, feeChargesOutstanding,
penaltyChargesOutstanding);
BigDecimal totalActualCostOfLoanForPeriod = MathUtil.add(interestDue, feeChargesDue, penaltyChargesDue);
BigDecimal totalInstallmentAmount = MathUtil.add(principalOriginalDue, interestDue);
BigDecimal totalActualCostOfLoanForPeriod = MathUtil.add(mc, interestDue, feeChargesDue, penaltyChargesDue);
BigDecimal totalInstallmentAmount = MathUtil.add(mc, principalOriginalDue, interestDue);
return builder().period(periodNumber) //
.fromDate(fromDate) //
@@ -1226,7 +1226,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
Set<Long> disbursementPeriodIds = new HashSet<>();
while (rs.next()) {
final Long loanId = rs.getLong("loanId");
final Integer period = JdbcSupport.getInteger(rs, "period");
LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromDate");
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
@@ -1307,8 +1306,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
final BigDecimal totalOutstandingForPeriod = principalOutstanding.add(interestOutstanding).add(feeChargesOutstanding)
.add(penaltyChargesOutstanding);
final BigDecimal totalActualCostOfLoanForPeriod = interestActualDue.add(feeChargesActualDue).add(penaltyChargesActualDue);
totalRepaymentExpected = totalRepaymentExpected.plus(totalDueForPeriod);
totalRepayment = totalRepayment.plus(totalPaidForPeriod);
totalPaidInAdvance = totalPaidInAdvance.plus(totalPaidInAdvanceForPeriod);
@@ -296,6 +296,41 @@ public class LoanRepaymentScheduleForChargesAfterMaturityTest extends BaseLoanIn
});
}
@Test
public void incorrectValueAfterCharge() {
runAt("20 December 2024", () -> {
// Create Client
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
// Create Loan Product
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.minPrincipal(100.0);
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
Long loanProductId = loanProductResponse.getResourceId();
// Apply and Approve Loan
Long loanId = applyAndApproveLoan(clientId, loanProductId, "20 December 2024", 800.0, 4, req -> {
req.setRepaymentEvery(30);
req.setLoanTermFrequency(120);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
});
// Disburse Loan
disburseLoan(loanId, BigDecimal.valueOf(800.00), "20 December 2024");
// add charge with a huge amount
addCharge(loanId, false, 123456789012.12, "23 December 2024");
// verify repayment schedule
verifyRepaymentSchedule(loanId, //
installment(800.0, null, "20 December 2024"), //
installment(200.0, 0.0, 123456789212.12, false, "19 January 2025"), //
installment(200.0, 0.0, 200.0, false, "18 February 2025"), //
installment(200.0, 0.0, 200.0, false, "20 March 2025"), //
installment(200.0, 0.0, 200.0, false, "19 April 2025")//
);
});
}
private Long createLoanProductWithMultiDisbursalAndRepayments() {
boolean multiDisburseEnabled = true;
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct();
@@ -96,12 +96,12 @@ public class MultiActivityAccrualsTest extends BaseLoanIntegrationTest {
verifyTransactions(loanId, //
transaction(600.0, "Disbursement", "09 August 2024", 600.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
transaction(20.00, "Accrual", "09 December 2024", 0, 0, 20.00, 0, 0, 0.0, 0.0),
transaction(5.0, "Accrual Activity", "09 September 2024", 0, 0, 5.0, 0, 0, 0.0, 0.0),
transaction(19.98, "Accrual", "09 December 2024", 0, 0, 19.98, 0, 0, 0.0, 0.0),
transaction(4.99, "Accrual Activity", "09 September 2024", 0, 0, 4.99, 0, 0, 0.0, 0.0),
transaction(5.0, "Accrual Activity", "09 October 2024", 0, 0, 5.0, 0, 0, 0.0, 0.0),
transaction(5.0, "Accrual Activity", "09 November 2024", 0, 0, 5.0, 0, 0, 0.0, 0.0),
transaction(4.99, "Accrual Activity", "09 November 2024", 0, 0, 4.99, 0, 0, 0.0, 0.0),
transaction(5.0, "Accrual Activity", "09 December 2024", 0, 0, 5.0, 0, 0, 0.0, 0.0),
transaction(700.00, "Repayment", "09 December 2024", 0, 600.00, 20.0, 0, 0, 0.0, 80.0));
transaction(700.00, "Repayment", "09 December 2024", 0, 600.00, 19.98, 0, 0, 0.0, 80.02));
});
}
}