Skip to content

Commit ee2fbea

Browse files
committed
FINERACT-2354: fix
1 parent 127871f commit ee2fbea

File tree

3 files changed

+52
-40
lines changed

3 files changed

+52
-40
lines changed

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

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3115,6 +3115,7 @@ private void reprocessInstallments(final List<LoanRepaymentScheduleInstallment>
31153115
}
31163116
previousDueDate.set(i.getDueDate());
31173117
});
3118+
installments.sort(LoanRepaymentScheduleInstallment::compareToByFromDueDate);
31183119
}
31193120

31203121
private LocalDate calculateReAgedInstallmentDueDate(final LoanReAgeParameter reAgeParameter, final LocalDate dueDate) {
@@ -3416,9 +3417,7 @@ private void handleReAgeEqualAmortizationEMICalculator(LoanTransaction loanTrans
34163417
ctx.getAlreadyProcessedTransactions());
34173418

34183419
emiCalculator.reAgeEqualAmortization(model, transactionDate, loanReAgeParameter,
3419-
outstandingBalances.fees.add(outstandingBalances.penalties),
3420-
new EqualAmortizationValues(calculatedFees.value().add(calculatedPenalties.value()),
3421-
calculatedFees.adjustment().add(calculatedPenalties.adjustment())));
3420+
outstandingBalances.fees.add(outstandingBalances.penalties), calculatedFees.add(calculatedPenalties));
34223421

34233422
installments.removeIf(i -> (i.getInstallmentNumber() != null && !i.isDownPayment() && !i.getDueDate().isBefore(transactionDate)
34243423
&& !i.isAdditional()) || (!i.getDueDate().isAfter(model.getMaturityDate()) && i.isAdditional()));
@@ -3428,6 +3427,7 @@ private void handleReAgeEqualAmortizationEMICalculator(LoanTransaction loanTrans
34283427
i.setInstallmentNumber(model.repaymentPeriods().size());
34293428
});
34303429

3430+
int reAgedInstallmentIndex = 0;
34313431
for (int index = 0; index < model.repaymentPeriods().size(); index++) {
34323432
RepaymentPeriod rp = model.repaymentPeriods().get(index);
34333433
if (rp.getDueDate().isBefore(transactionDate)) {
@@ -3441,7 +3441,6 @@ private void handleReAgeEqualAmortizationEMICalculator(LoanTransaction loanTrans
34413441
installment.setCreditedPrincipal(rp.getCreditedPrincipal().getAmount());
34423442

34433443
installment.updateObligationsMet(currency, transactionDate);
3444-
// TODO add remaining components
34453444
} else {
34463445
LoanRepaymentScheduleInstallment created = LoanRepaymentScheduleInstallment.newReAgedInstallment(loanTransaction.getLoan(),
34473446
index + 1, rp.getFromDate(), rp.getDueDate(), rp.getDuePrincipal().getAmount(), rp.getDueInterest().getAmount(),
@@ -3460,15 +3459,15 @@ private void handleReAgeEqualAmortizationEMICalculator(LoanTransaction loanTrans
34603459

34613460
paidInAdvanceBalances.loanTransactionToRepaymentScheduleMappings.forEach(m -> m.setInstallment(created));
34623461
} else {
3463-
boolean isLastRepaymentPeriod = model.isLastRepaymentPeriod(rp);
3464-
created.setFeeChargesCharged(calculatedFees.calculateValueBigDecimal(isLastRepaymentPeriod));
3465-
created.setPenaltyCharges(calculatedPenalties.calculateValueBigDecimal(isLastRepaymentPeriod));
3462+
created.setFeeChargesCharged(calculatedFees.calculateValueBigDecimal(reAgedInstallmentIndex));
3463+
created.setPenaltyCharges(calculatedPenalties.calculateValueBigDecimal(reAgedInstallmentIndex));
34663464

3467-
created.setInterestAccrued(calculatedInterestAccrued.calculateValueBigDecimal(isLastRepaymentPeriod));
3468-
created.setFeeAccrued(calculatedFeeAccrued.calculateValueBigDecimal(isLastRepaymentPeriod));
3469-
created.setPenaltyAccrued(calculatedPenaltyAccrued.calculateValueBigDecimal(isLastRepaymentPeriod));
3465+
created.setInterestAccrued(calculatedInterestAccrued.calculateValueBigDecimal(reAgedInstallmentIndex));
3466+
created.setFeeAccrued(calculatedFeeAccrued.calculateValueBigDecimal(reAgedInstallmentIndex));
3467+
created.setPenaltyAccrued(calculatedPenaltyAccrued.calculateValueBigDecimal(reAgedInstallmentIndex));
34703468

3471-
createChargeMappingsForInstallment(created, calculatedCharges, isLastRepaymentPeriod);
3469+
createChargeMappingsForInstallment(created, calculatedCharges, reAgedInstallmentIndex);
3470+
reAgedInstallmentIndex++;
34723471
}
34733472
created.setCreditedPrincipal(rp.getCreditedPrincipal().getAmount());
34743473
created.updateObligationsMet(currency, transactionDate);
@@ -3576,34 +3575,36 @@ private void handleReAgeWithCommonStrategy(LoanTransaction loanTransaction, Comm
35763575
installments.add(earlyRepaidInstallment);
35773576
}
35783577

3578+
// installment index which excludes earlyRepaidInstallment intallment index.
3579+
Integer reAgedInstallmentIndex = 0;
35793580
LoanRepaymentScheduleInstallment reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(loan,
35803581
firstReAgeInstallmentProps.reAgedInstallmentNumber, firstReAgeInstallmentProps.fromDate, loanReAgeParameter.getStartDate(),
35813582
calculatedPrincipal.value().getAmount(), calculatedInterest.value().getAmount(), calculatedFees.value().getAmount(),
35823583
calculatedPenalties.value().getAmount(), calculatedInterestAccrued.value().getAmount(),
35833584
calculatedFeeAccrued.value().getAmount(), calculatedPenaltyAccrued.value().getAmount());
35843585

35853586
reAgedInstallment = insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency, transactionDate);
3586-
createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, false);
3587-
3587+
createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, reAgedInstallmentIndex);
3588+
reAgedInstallmentIndex++;
35883589
for (int i = 1; i < numberOfReAgeInstallments; i++) {
35893590
LocalDate calculatedDueDate = scheduledDateGenerator.getRepaymentPeriodDate(loanReAgeParameter.getFrequencyType(),
35903591
loanReAgeParameter.getFrequencyNumber(), reAgedInstallment.getDueDate());
35913592
calculateReAgedInstallmentDueDate(loanReAgeParameter, reAgedInstallment.getDueDate());
35923593
int nextReAgedInstallmentNumber = firstReAgeInstallmentProps.reAgedInstallmentNumber + i;
3593-
boolean isLastInstallment = i + 1 == numberOfReAgeInstallments;
35943594

35953595
reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(reAgedInstallment.getLoan(),
35963596
nextReAgedInstallmentNumber, reAgedInstallment.getDueDate(), calculatedDueDate,
3597-
calculatedPrincipal.calculateValueBigDecimal(isLastInstallment),
3598-
calculatedInterest.calculateValueBigDecimal(isLastInstallment),
3599-
calculatedFees.calculateValueBigDecimal(isLastInstallment),
3600-
calculatedPenalties.calculateValueBigDecimal(isLastInstallment),
3601-
calculatedInterestAccrued.calculateValueBigDecimal(isLastInstallment),
3602-
calculatedFeeAccrued.calculateValueBigDecimal(isLastInstallment),
3603-
calculatedPenaltyAccrued.calculateValueBigDecimal(isLastInstallment));
3597+
calculatedPrincipal.calculateValueBigDecimal(reAgedInstallmentIndex),
3598+
calculatedInterest.calculateValueBigDecimal(reAgedInstallmentIndex),
3599+
calculatedFees.calculateValueBigDecimal(reAgedInstallmentIndex),
3600+
calculatedPenalties.calculateValueBigDecimal(reAgedInstallmentIndex),
3601+
calculatedInterestAccrued.calculateValueBigDecimal(reAgedInstallmentIndex),
3602+
calculatedFeeAccrued.calculateValueBigDecimal(reAgedInstallmentIndex),
3603+
calculatedPenaltyAccrued.calculateValueBigDecimal(reAgedInstallmentIndex));
36043604

36053605
reAgedInstallment = insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency, transactionDate);
3606-
createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, isLastInstallment);
3606+
createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, reAgedInstallmentIndex);
3607+
reAgedInstallmentIndex++;
36073608
}
36083609
int lastReAgedInstallmentNumber = reAgedInstallment.getInstallmentNumber();
36093610
List<LoanRepaymentScheduleInstallment> toRemove = installments.stream()
@@ -3615,10 +3616,10 @@ private void handleReAgeWithCommonStrategy(LoanTransaction loanTransaction, Comm
36153616
}
36163617

36173618
private void createChargeMappingsForInstallment(final LoanRepaymentScheduleInstallment installment,
3618-
List<ReAgedChargeEqualAmortizationValues> reAgedChargeEqualAmortizationValues, boolean isLastInstallment) {
3619+
List<ReAgedChargeEqualAmortizationValues> reAgedChargeEqualAmortizationValues, Integer index) {
36193620
reAgedChargeEqualAmortizationValues.forEach(amortizationValue -> {
36203621
installment.getInstallmentCharges()
3621-
.add(new LoanInstallmentCharge(amortizationValue.equalAmortizationValues.calculateValueBigDecimal(isLastInstallment),
3622+
.add(new LoanInstallmentCharge(amortizationValue.equalAmortizationValues.calculateValueBigDecimal(index),
36223623
amortizationValue.charge, installment));
36233624
});
36243625
}

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,15 +1685,14 @@ private void updateEMIForReAgeEqualAmortization(List<RepaymentPeriod> repaymentP
16851685
EqualAmortizationValues principalEAV = calculateAdjustedEqualAmortizationValues(principal,
16861686
principal.add(interest).add(feesPenaltiesOutstanding),
16871687
interestEAV.value().add(feesPenaltiesEqualAmortizationValues.value()), repaymentPeriods.size(), null, currency);
1688-
RepaymentPeriod last = repaymentPeriods.getLast();
16891688
EqualAmortizationValues emiAEV = principalEAV.add(interestEAV);
1690-
repaymentPeriods.forEach(rp -> {
1691-
boolean isLast = last.equals(rp);
1692-
rp.setReAgedInterest(interestEAV.calculateValue(isLast));
1693-
Money emi = emiAEV.calculateValue(isLast);
1689+
for (int i = 0; i < repaymentPeriods.size(); i++) {
1690+
RepaymentPeriod rp = repaymentPeriods.get(i);
1691+
rp.setReAgedInterest(interestEAV.calculateValue(i));
1692+
Money emi = emiAEV.calculateValue(i);
16941693
rp.setEmi(emi);
16951694
rp.setOriginalEmi(emi);
1696-
});
1695+
}
16971696
}
16981697

16991698
@Override
@@ -1816,9 +1815,9 @@ public EqualAmortizationValues calculateEqualAmortizationValues(Money totalOutst
18161815
equalMonthlyValue = Money.roundToMultiplesOf(equalMonthlyValue, installmentAmountInMultiplesOf);
18171816
}
18181817
Money adjustmentForLastInstallment = totalOutstanding.minus(equalMonthlyValue.multipliedBy(numberOfInstallments));
1819-
return new EqualAmortizationValues(equalMonthlyValue, adjustmentForLastInstallment);
1818+
return new EqualAmortizationValues(totalOutstanding, numberOfInstallments, equalMonthlyValue, adjustmentForLastInstallment);
18201819
}
1821-
return new EqualAmortizationValues(Money.zero(currency), Money.zero(currency));
1820+
return new EqualAmortizationValues(totalOutstanding, numberOfInstallments, Money.zero(currency), Money.zero(currency));
18221821
}
18231822

18241823
@Override
@@ -1829,6 +1828,6 @@ public EqualAmortizationValues calculateAdjustedEqualAmortizationValues(Money ou
18291828
installmentAmountInMultiplesOf, currency);
18301829
Money value = calculatedEMI.value().minus(sumOfOtherEqualAmortizationValues);
18311830
Money adjust = outstanding.minus(value.multipliedBy(numberOfInstallments));
1832-
return new EqualAmortizationValues(value, adjust);
1831+
return new EqualAmortizationValues(outstanding, numberOfInstallments, value, adjust);
18331832
}
18341833
}

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/EqualAmortizationValues.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,35 @@
1919
package org.apache.fineract.portfolio.loanproduct.calc.data;
2020

2121
import java.math.BigDecimal;
22+
import java.util.Objects;
23+
2224
import org.apache.fineract.organisation.monetary.domain.Money;
25+
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
2326

24-
public record EqualAmortizationValues(Money value, Money adjustment) {
27+
public record EqualAmortizationValues(Money totalOutstanding, Integer numberOfInstallments, Money value, Money adjustment) {
2528

2629
public Money getAdjustedValue() {
2730
return value.add(adjustment);
2831
}
2932

30-
public Money calculateValue(boolean isLast) {
31-
return (isLast ? getAdjustedValue() : value);
33+
/**
34+
* calculates value according to the index of the installments
35+
* @param index index accepted 0 to number of (installments - 1)
36+
* @return calculated value for the given index
37+
*/
38+
public Money calculateValue(Integer index) {
39+
if (getAdjustedValue().isLessThanZero()) {
40+
return value.multipliedBy(index + 1).minus(totalOutstanding).isLessThanZero()? value.zero() : value;
41+
}
42+
return (index == numberOfInstallments - 1 ? getAdjustedValue() : value);
3243
}
33-
34-
public BigDecimal calculateValueBigDecimal(boolean isLast) {
35-
return calculateValue(isLast).getAmount();
44+
public BigDecimal calculateValueBigDecimal(Integer index) {
45+
return calculateValue(index).getAmount();
3646
}
3747

48+
3849
public EqualAmortizationValues add(EqualAmortizationValues other) {
39-
return new EqualAmortizationValues(value.add(other.value), adjustment.add(other.adjustment));
50+
if (!Objects.equals(numberOfInstallments, other.numberOfInstallments)) { throw new RuntimeException("Incompatible EqualAmortizationValues. numberOfInstallments parameter should match.");}
51+
return new EqualAmortizationValues(totalOutstanding.add(other.totalOutstanding), numberOfInstallments, value.add(other.value), adjustment.add(other.adjustment));
4052
}
4153
}

0 commit comments

Comments
 (0)