FINERACT-2081: Interest recalculation only for interest bearing loans

This commit is contained in:
Adam Saghy
2025-02-06 14:11:06 +01:00
parent 493012bf8c
commit 79c5fc1649
18 changed files with 128 additions and 123 deletions
@@ -2658,6 +2658,10 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
return BigDecimal.ZERO.compareTo(getLoanRepaymentScheduleDetail().getAnnualNominalInterestRate()) < 0;
}
public boolean isInterestBearingAndInterestRecalculationEnabled() {
return isInterestBearing() && isInterestRecalculationEnabled();
}
public boolean isInterestRecalculationEnabled() {
return this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled();
}
@@ -2705,8 +2709,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
}
public LoanScheduleDTO getRecalculatedSchedule(final ScheduleGeneratorDTO generatorDTO) {
if (!this.repaymentScheduleDetail().isEnableDownPayment()
&& (!this.repaymentScheduleDetail().isInterestRecalculationEnabled() || isNpa || isChargedOff())) {
if (!isInterestBearingAndInterestRecalculationEnabled() || isNpa || isChargedOff()) {
return null;
}
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
@@ -2726,7 +2729,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
public OutstandingAmountsDTO fetchPrepaymentDetail(final ScheduleGeneratorDTO scheduleGeneratorDTO, final LocalDate onDate) {
OutstandingAmountsDTO outstandingAmounts;
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled() && !isChargeOffOnDate(onDate)) {
if (isInterestBearingAndInterestRecalculationEnabled() && !isChargeOffOnDate(onDate)) {
final MathContext mc = MoneyHelper.getMathContext();
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
@@ -250,7 +250,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
isNextRepaymentAvailable = false;
}
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
if (loanApplicationTerms.isInterestBearingAndInterestRecalculationEnabled()) {
populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms,
holidayDetailDTO, scheduleParams, loanCharges, monetaryCurrency, mc);
}
@@ -495,7 +495,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
LoanScheduleParams scheduleParams, LocalDate scheduledDueDate, ScheduleCurrentPeriodParams currentPeriodParams,
LoanScheduleModelPeriod installment, LocalDate lastRestDate) {
LocalDate amountApplicableDate = installment.periodDueDate();
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
if (loanApplicationTerms.isInterestBearingAndInterestRecalculationEnabled()) {
amountApplicableDate = getNextRestScheduleDate(installment.periodDueDate().minusDays(1), loanApplicationTerms,
holidayDetailDTO);
}
@@ -1681,7 +1681,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
private void updateCompoundingMap(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
final LoanScheduleParams params, final LocalDate lastRestDate, final LocalDate scheduledDueDate) {
if (loanApplicationTerms.isInterestRecalculationEnabled()
if (loanApplicationTerms.isInterestBearingAndInterestRecalculationEnabled()
&& loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
final MonetaryCurrency currency = MonetaryCurrency.fromCurrencyData(params.getCurrency());
Money totalCompoundedAmount = Money.zero(currency);
@@ -2186,7 +2186,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
LoanTransaction.copyTransactionProperties(loanTransaction)));
}
}
final boolean applyInterestRecalculation = loanApplicationTerms.isInterestRecalculationEnabled();
final boolean applyInterestRecalculation = loanApplicationTerms.isInterestBearingAndInterestRecalculationEnabled();
// for complete schedule generation
LoanScheduleParams loanScheduleParams = LoanScheduleParams.createLoanScheduleParamsForCompleteUpdate(recalculationDetails,
@@ -2239,7 +2239,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
LocalDate currentDate = DateUtils.getBusinessLocalDate();
LocalDate lastRestDate = currentDate;
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
if (loanApplicationTerms.isInterestBearingAndInterestRecalculationEnabled()) {
lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
}
LocalDate actualRepaymentDate = RepaymentStartDateType.DISBURSEMENT_DATE
@@ -2412,7 +2412,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
instalmentNumber++;
loanTermInDays = DateUtils.getExactDifferenceInDays(installment.getFromDate(), installment.getDueDate());
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
if (loanApplicationTerms.isInterestBearingAndInterestRecalculationEnabled()) {
// populates the collection with transactions till the due
// date
@@ -1677,6 +1677,14 @@ public final class LoanApplicationTerms {
return LoanRescheduleStrategyMethod.REDUCE_EMI_AMOUNT;
}
public boolean isInterestBearing() {
return BigDecimal.ZERO.compareTo(getAnnualNominalInterestRate()) < 0;
}
public boolean isInterestBearingAndInterestRecalculationEnabled() {
return isInterestBearing() && isInterestRecalculationEnabled();
}
public boolean isInterestRecalculationEnabled() {
return this.interestRecalculationEnabled;
}
@@ -385,7 +385,7 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
}
private void handleArrearsForLoan(Loan loan) {
if (loan != null && loan.isOpen() && loan.repaymentScheduleDetail().isInterestRecalculationEnabled()
if (loan != null && loan.isOpen() && loan.isInterestBearingAndInterestRecalculationEnabled()
&& loan.loanProduct().isArrearsBasedOnOriginalSchedule()) {
updateLoanArrearsAgeingDetailsWithOriginalSchedule(loan);
} else {
@@ -137,12 +137,12 @@ public class LoanDownPaymentHandlerServiceImpl implements LoanDownPaymentHandler
|| !currentInstallment.getTotalOutstanding(loan.getCurrency()).isEqualTo(loanTransaction.getAmount(loan.getCurrency()));
if (isTransactionChronologicallyLatest && adjustedTransaction == null
&& (!reprocess || !loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) && !loan.isForeclosure()) {
&& (!reprocess || !loan.isInterestBearingAndInterestRecalculationEnabled()) && !loan.isForeclosure()) {
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction,
new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(),
new MoneyHolder(loan.getTotalOverpaidAsMoney()), null));
reprocess = false;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
if (currentInstallment == null || currentInstallment.isNotFullyPaidOff()) {
reprocess = true;
} else {
@@ -155,7 +155,7 @@ public class LoanDownPaymentHandlerServiceImpl implements LoanDownPaymentHandler
}
}
if (reprocess) {
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()
if (loan.isInterestBearingAndInterestRecalculationEnabled()
&& !loan.getLoanProductRelatedDetail().getLoanScheduleType().equals(LoanScheduleType.PROGRESSIVE)) {
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO);
} else if (loan.getLoanProductRelatedDetail() != null
@@ -54,7 +54,7 @@ public class LoanScheduleService {
}
public void recalculateScheduleFromLastTransaction(final Loan loan, final ScheduleGeneratorDTO generatorDTO) {
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled() && !loan.isChargedOff()) {
if (loan.isInterestBearingAndInterestRecalculationEnabled() && !loan.isChargedOff()) {
regenerateRepaymentScheduleWithInterestRecalculation(loan, generatorDTO);
} else {
regenerateRepaymentSchedule(loan, generatorDTO);
@@ -73,7 +73,7 @@ public class LoanScheduleService {
* loanTransaction.getTransactionDate().isAfter(recalculateFrom)) { recalculateFrom =
* loanTransaction.getTransactionDate(); } } generatorDTO.setRecalculateFrom(recalculateFrom);
*/
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled() && !loan.isChargedOff()) {
if (loan.isInterestBearingAndInterestRecalculationEnabled() && !loan.isChargedOff()) {
regenerateRepaymentScheduleWithInterestRecalculation(loan, generatorDTO);
} else {
regenerateRepaymentSchedule(loan, generatorDTO);