Skip to content

Commit 162e543

Browse files
committed
FINERACT-2354: Re-aging: -Interest Handling Option: Equal amortization
Reimplement charge handling
1 parent 2d54a58 commit 162e543

File tree

2 files changed

+42
-38
lines changed

2 files changed

+42
-38
lines changed

fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,17 @@ public LoanRepaymentScheduleInstallment(Loan loan, Integer installmentNumber, Lo
260260
this.isReAged = isReAged;
261261
}
262262

263+
public static LoanRepaymentScheduleInstallment newReAgedInstallment(final Loan loan, final Integer installmentNumber,
264+
final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees,
265+
final BigDecimal penalties, final BigDecimal interestAccrued, final BigDecimal feeAccrued, final BigDecimal penaltyAccrued) {
266+
LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(loan, installmentNumber, fromDate, dueDate,
267+
principal, interest, fees, penalties, null, null, null, null, false, false, true);
268+
installment.setInterestAccrued(interestAccrued);
269+
installment.setFeeAccrued(feeAccrued);
270+
installment.setPenaltyAccrued(penaltyAccrued);
271+
return installment;
272+
}
273+
263274
public static LoanRepaymentScheduleInstallment newReAgedInstallment(final Loan loan, final Integer installmentNumber,
264275
final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees,
265276
final BigDecimal penalties) {

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@
7070
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
7171
import org.apache.fineract.organisation.monetary.domain.Money;
7272
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
73-
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
7473
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
7574
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
7675
import org.apache.fineract.portfolio.loanaccount.data.OutstandingAmountsDTO;
@@ -2686,6 +2685,7 @@ private Set<LoanCharge> getLoanChargesOfInstallment(final Set<LoanCharge> charge
26862685
final boolean isFirstInstallment = installment.getInstallmentNumber().equals(firstInstallmentNumber);
26872686
return charges.stream()
26882687
.filter(loanCharge -> (loanCharge.isInstalmentFee() && loanCharge.hasInstallmentFor(installment))
2688+
|| (installment.isReAged() && loanCharge.hasInstallmentFor(installment))
26892689
|| loanCharge.isDueInPeriod(installment.getFromDate(), installment.getDueDate(), isFirstInstallment))
26902690
.collect(Collectors.toSet());
26912691
}
@@ -3303,51 +3303,48 @@ private void handleReAgeWithCommonStrategy(LoanTransaction loanTransaction, Comm
33033303
Money principalValue = calculatedEMI.value.minus(calculatedInterest.value.add(calculatedFees.value).add(calculatedPenalties.value));
33043304
Money principalAdjust = outstandingBalances.principal.minus(principalValue.multipliedBy(numberOfReAgeInstallments));
33053305
EqualAmortizationValues calculatedPrincipal = new EqualAmortizationValues(principalValue, principalAdjust);
3306+
List<ReAgedChargeEqualAmortizationValues> calculatedCharges = outstandingBalances.liftedLoanCharges().stream()
3307+
.map(loanCharge -> new ReAgedChargeEqualAmortizationValues(loanCharge, calculateEqualAmortizationValues(
3308+
loanCharge.getAmountOutstanding(currency), numberOfReAgeInstallments, null, currency)))
3309+
.toList();
33063310

33073311
FirstReAgeInstallmentProps firstReAgeInstallmentProps = calculateFirstReAgeInstallmentProps(installments,
33083312
loanReAgeParameter.getStartDate());
33093313

33103314
LoanRepaymentScheduleInstallment reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(loan,
33113315
firstReAgeInstallmentProps.reAgedInstallmentNumber, firstReAgeInstallmentProps.fromDate, loanReAgeParameter.getStartDate(),
33123316
calculatedPrincipal.value.getAmount(), calculatedInterest.value.getAmount(), calculatedFees.value.getAmount(),
3313-
calculatedPenalties.value.getAmount());
3314-
// todo redistribute lifted fees and penalties
3315-
createChargesDuringReAgingIfNeeded(calculatedFees.value.getAmount(), calculatedPenalties.value.getAmount(), outstandingBalances,
3316-
loan, loanReAgeParameter.getStartDate());
3317-
reAgedInstallment.setInterestAccrued(calculatedInterestAccrued.value.getAmount());
3318-
reAgedInstallment.setFeeAccrued(calculatedFeeAccrued.value.getAmount());
3319-
reAgedInstallment.setPenaltyAccrued(calculatedPenaltyAccrued.value.getAmount());
3317+
calculatedPenalties.value.getAmount(), calculatedInterestAccrued.value.getAmount(), calculatedFeeAccrued.value.getAmount(),
3318+
calculatedPenaltyAccrued.value.getAmount());
3319+
33203320
reAgedInstallment = insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency,
33213321
loanTransaction.getTransactionDate(), settings.isEqualInstallmentForInterest(),
33223322
settings.isEqualInstallmentForFeesAndPenalties());
3323+
createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, false);
33233324

33243325
for (int i = 1; i < numberOfReAgeInstallments; i++) {
33253326
LocalDate calculatedDueDate = calculateReAgedInstallmentDueDate(loanReAgeParameter, reAgedInstallment.getDueDate());
33263327
int nextReAgedInstallmentNumber = firstReAgeInstallmentProps.reAgedInstallmentNumber + i;
3327-
if (i + 1 == numberOfReAgeInstallments) {
3328+
boolean isLastInstallment = i + 1 == numberOfReAgeInstallments;
3329+
if (isLastInstallment) {
33283330
// Last installment values
33293331
reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(reAgedInstallment.getLoan(),
33303332
nextReAgedInstallmentNumber, reAgedInstallment.getDueDate(), calculatedDueDate,
33313333
calculatedPrincipal.getAdjustedValue().getAmount(), calculatedInterest.getAdjustedValue().getAmount(),
3332-
calculatedFees.getAdjustedValue().getAmount(), calculatedPenalties.getAdjustedValue().getAmount());
3333-
reAgedInstallment.setInterestAccrued(calculatedInterestAccrued.getAdjustedValue().getAmount());
3334-
reAgedInstallment.setFeeAccrued(calculatedFeeAccrued.getAdjustedValue().getAmount());
3335-
reAgedInstallment.setPenaltyAccrued(calculatedPenaltyAccrued.getAdjustedValue().getAmount());
3336-
// todo redistribute lifted fees and penalties
3337-
createChargesDuringReAgingIfNeeded(calculatedFees.getAdjustedValue().getAmount(),
3338-
calculatedPenalties.getAdjustedValue().getAmount(), outstandingBalances, loan, reAgedInstallment.getDueDate());
3334+
calculatedFees.getAdjustedValue().getAmount(), calculatedPenalties.getAdjustedValue().getAmount(),
3335+
calculatedInterestAccrued.getAdjustedValue().getAmount(), calculatedFeeAccrued.getAdjustedValue().getAmount(),
3336+
calculatedPenaltyAccrued.getAdjustedValue().getAmount());
33393337
} else {
33403338
reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(reAgedInstallment.getLoan(),
33413339
nextReAgedInstallmentNumber, reAgedInstallment.getDueDate(), calculatedDueDate,
33423340
calculatedPrincipal.value.getAmount(), calculatedInterest.value.getAmount(), calculatedFees.value.getAmount(),
3343-
calculatedPenalties.value.getAmount());
3344-
// todo redistribute lifted fees and penalties
3345-
createChargesDuringReAgingIfNeeded(calculatedFees.value.getAmount(), calculatedPenalties.value.getAmount(),
3346-
outstandingBalances, loan, reAgedInstallment.getDueDate());
3341+
calculatedPenalties.value.getAmount(), calculatedInterestAccrued.value.getAmount(),
3342+
calculatedFeeAccrued.value.getAmount(), calculatedPenaltyAccrued.value.getAmount());
33473343
}
33483344
reAgedInstallment = insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency,
33493345
loanTransaction.getTransactionDate(), settings.isEqualInstallmentForInterest(),
33503346
settings.isEqualInstallmentForFeesAndPenalties());
3347+
createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, isLastInstallment);
33513348
}
33523349
int lastReAgedInstallmentNumber = reAgedInstallment.getInstallmentNumber();
33533350
List<LoanRepaymentScheduleInstallment> toRemove = installments.stream()
@@ -3361,19 +3358,13 @@ private void handleReAgeWithCommonStrategy(LoanTransaction loanTransaction, Comm
33613358
}
33623359
}
33633360

3364-
private void createChargesDuringReAgingIfNeeded(final BigDecimal calculatedFees, final BigDecimal calculatedPenalties,
3365-
final OutstandingBalances outstandingBalances, final Loan loan, final LocalDate chargeDueDate) {
3366-
if (MathUtil.nullToZero(calculatedFees).compareTo(BigDecimal.ZERO) > 0) {
3367-
outstandingBalances.liftedLoanCharges().forEach(charge -> {
3368-
if (charge.isDueDateCharge()) {
3369-
final LoanCharge newLoanCharge = loanChargeService.create(loan, charge.getCharge(), null,
3370-
charge.isPenaltyCharge() ? calculatedPenalties : calculatedFees, charge.getChargeTimeType(),
3371-
ChargeCalculationType.FLAT, chargeDueDate, charge.getChargePaymentMode(), null, null,
3372-
externalIdFactory.create());
3373-
loanChargeService.addLoanCharge(loan, newLoanCharge);
3374-
}
3375-
});
3376-
}
3361+
private void createChargeMappingsForInstallment(final LoanRepaymentScheduleInstallment installment,
3362+
List<ReAgedChargeEqualAmortizationValues> reAgedChargeEqualAmortizationValues, boolean isLastInstallment) {
3363+
reAgedChargeEqualAmortizationValues.forEach(amortizationValue -> {
3364+
BigDecimal value = isLastInstallment ? amortizationValue.equalAmortizationValues.getAdjustedValue().getAmount()
3365+
: amortizationValue.equalAmortizationValues.value.getAmount();
3366+
installment.getInstallmentCharges().add(new LoanInstallmentCharge(value, amortizationValue.charge, installment));
3367+
});
33773368
}
33783369

33793370
private FirstReAgeInstallmentProps calculateFirstReAgeInstallmentProps(List<LoanRepaymentScheduleInstallment> installments,
@@ -3522,11 +3513,10 @@ OutstandingBalances liftOutstandingBalances(List<LoanRepaymentScheduleInstallmen
35223513
.stream()//
35233514
.filter(c -> MathUtil.isGreaterThanZero(c.getAmountOutstanding()))//
35243515
.forEach(loanInstallmentCharge -> {
3525-
Money outstanding = loanInstallmentCharge.getAmountOutstanding(currency);
3526-
if (MathUtil.nullToZero(loanInstallmentCharge.getAmountPaid()).equals(ZERO)) {
3527-
ctx.getCharges().remove(loanInstallmentCharge);
3528-
loanTransaction.getLoan().getCharges().remove(loanInstallmentCharge);
3529-
}
3516+
// if (MathUtil.nullToZero(loanInstallmentCharge.getAmountPaid()).equals(ZERO)) {
3517+
// ctx.getCharges().remove(loanInstallmentCharge);
3518+
// loanTransaction.getLoan().getCharges().remove(loanInstallmentCharge);
3519+
// }
35303520
liftedLoanCharges.add(loanInstallmentCharge);
35313521
});
35323522
Money feesOutstanding = i.getFeeChargesOutstanding(currency);
@@ -3582,6 +3572,9 @@ private static final class CommonReAgeSettings {
35823572
boolean isEqualInstallmentForFeesAndPenalties = false;
35833573
}
35843574

3575+
private record ReAgedChargeEqualAmortizationValues(LoanCharge charge, EqualAmortizationValues equalAmortizationValues) {
3576+
}
3577+
35853578
private record FirstReAgeInstallmentProps(int reAgedInstallmentNumber, LocalDate fromDate) {
35863579
}
35873580

0 commit comments

Comments
 (0)