3939import org .apache .fineract .infrastructure .core .service .DateUtils ;
4040import org .apache .fineract .infrastructure .core .service .MathUtil ;
4141import org .apache .fineract .organisation .monetary .data .CurrencyData ;
42+ import org .apache .fineract .organisation .monetary .domain .MonetaryCurrency ;
4243import org .apache .fineract .organisation .monetary .domain .Money ;
4344import org .apache .fineract .organisation .monetary .domain .MoneyHelper ;
4445import org .apache .fineract .portfolio .common .domain .DaysInMonthType ;
5657import org .apache .fineract .portfolio .loanaccount .loanschedule .domain .ScheduledDateGenerator ;
5758import org .apache .fineract .portfolio .loanproduct .calc .data .EmiAdjustment ;
5859import org .apache .fineract .portfolio .loanproduct .calc .data .EmiChangeOperation ;
60+ import org .apache .fineract .portfolio .loanproduct .calc .data .EqualAmortizationValues ;
5961import org .apache .fineract .portfolio .loanproduct .calc .data .InterestPeriod ;
6062import org .apache .fineract .portfolio .loanproduct .calc .data .OutstandingDetails ;
6163import org .apache .fineract .portfolio .loanproduct .calc .data .PeriodDueDetails ;
@@ -313,6 +315,31 @@ public void payPrincipal(ProgressiveLoanInterestScheduleModel scheduleModel, Loc
313315 }
314316 }
315317
318+ @ Override
319+ public EqualAmortizationValues calculateEqualAmortizationValues (Money totalOutstanding , Integer numberOfInstallments ,
320+ Integer installmentAmountInMultiplesOf , MonetaryCurrency currency ) {
321+ if (totalOutstanding .isGreaterThanZero ()) {
322+ Money equalMonthlyValue = totalOutstanding .dividedBy (numberOfInstallments , totalOutstanding .getMc ());
323+ if (installmentAmountInMultiplesOf != null ) {
324+ equalMonthlyValue = Money .roundToMultiplesOf (equalMonthlyValue , installmentAmountInMultiplesOf );
325+ }
326+ Money adjustmentForLastInstallment = totalOutstanding .minus (equalMonthlyValue .multipliedBy (numberOfInstallments ));
327+ return new EqualAmortizationValues (equalMonthlyValue , adjustmentForLastInstallment );
328+ }
329+ return new EqualAmortizationValues (Money .zero (currency ), Money .zero (currency ));
330+ }
331+
332+ @ Override
333+ public EqualAmortizationValues calculateAdjustedEqualAmortizationValues (Money outstanding , Money total ,
334+ Money sumOfOtherEqualAmortizationValues , Integer numberOfInstallments , Integer installmentAmountInMultiplesOf ,
335+ MonetaryCurrency currency ) {
336+ EqualAmortizationValues calculatedEMI = calculateEqualAmortizationValues (total , numberOfInstallments ,
337+ installmentAmountInMultiplesOf , currency );
338+ Money value = calculatedEMI .value ().minus (sumOfOtherEqualAmortizationValues );
339+ Money adjust = outstanding .minus (value .multipliedBy (numberOfInstallments ));
340+ return new EqualAmortizationValues (value , adjust );
341+ }
342+
316343 private Optional <RepaymentPeriod > getLatestNotLastOpenRepaymentPeriodBeforeDate (ProgressiveLoanInterestScheduleModel scheduleModel ,
317344 LocalDate transactionDate ) {
318345 List <RepaymentPeriod > unpaidRepaymentPeriods = scheduleModel .repaymentPeriods () //
@@ -420,8 +447,9 @@ public Money getPeriodInterestTillDate(@NotNull ProgressiveLoanInterestScheduleM
420447 targetDate );
421448 RepaymentPeriod repaymentPeriod = recalculatedScheduleModelTillDate .findRepaymentPeriodByDueDate (periodDueDate ).orElseThrow ();
422449 return includeCreditedInterest ? repaymentPeriod .getCalculatedDueInterest ()
423- : repaymentPeriod .getCalculatedDueInterest ().minus (repaymentPeriod .getReAgedInterest (), recalculatedScheduleModelTillDate .mc ()).minus (repaymentPeriod .getCreditedInterest (),
424- recalculatedScheduleModelTillDate .mc ());
450+ : repaymentPeriod .getCalculatedDueInterest ()
451+ .minus (repaymentPeriod .getReAgedInterest (), recalculatedScheduleModelTillDate .mc ())
452+ .minus (repaymentPeriod .getCreditedInterest (), recalculatedScheduleModelTillDate .mc ());
425453 }
426454
427455 @ Override
@@ -1512,39 +1540,35 @@ private void accelerateMaturityDateTo(ProgressiveLoanInterestScheduleModel inter
15121540 }
15131541 }
15141542
1515- private void updateEMIForReAgeEqualAmortization (List <RepaymentPeriod > repaymentPeriods , Money principal , Money interest ) {
1516- Money principalPortion = principal .dividedBy (repaymentPeriods .size ());
1517- Money principalAdjustment = principal .minus (principalPortion .multipliedBy (repaymentPeriods .size ()));
1518- Money interestPortion = interest .dividedBy (repaymentPeriods .size ());
1519- Money interestAdjustment = interest .minus (interestPortion .multipliedBy (repaymentPeriods .size ()));
1543+ private void updateEMIForReAgeEqualAmortization (List <RepaymentPeriod > repaymentPeriods , Money principal , Money interest ,
1544+ Money feesPenaltiesOutstanding , EqualAmortizationValues feesPenaltiesEqualAmortizationValues , MonetaryCurrency currency ) {
1545+ EqualAmortizationValues interestEAV = calculateEqualAmortizationValues (interest , repaymentPeriods .size (), null , currency );
1546+ EqualAmortizationValues principalEAV = calculateAdjustedEqualAmortizationValues (principal ,
1547+ principal .add (interest ).add (feesPenaltiesOutstanding ),
1548+ interestEAV .value ().add (feesPenaltiesEqualAmortizationValues .value ()), repaymentPeriods .size (), null , currency );
15201549 RepaymentPeriod last = repaymentPeriods .getLast ();
15211550 repaymentPeriods .forEach (rp -> {
1522- rp .setReAgedInterest (interestPortion );
1523- if (last == rp ) {
1524- rp .setReAgedInterest (interestPortion .add (interestAdjustment ));
1525- Money newEmi = principalPortion .add (principalAdjustment );
1526- rp .setEmi (newEmi );
1527- rp .setOriginalEmi (newEmi );
1528- } else {
1529- rp .setEmi (principalPortion );
1530- rp .setOriginalEmi (principalPortion );
1531- }
1551+ boolean isLast = last == rp ;
1552+ rp .setReAgedInterest (interestEAV .calculateValue (isLast ));
1553+ Money emi = principalEAV .calculateValue (isLast );
1554+ rp .setEmi (emi );
1555+ rp .setOriginalEmi (emi );
15321556 });
15331557 }
15341558
15351559 @ Override
1536- public OutstandingDetails precalculateReAgeEqualAmortizationAmount (ProgressiveLoanInterestScheduleModel interestSchedule , LocalDate transactionDate ,
1537- LoanReAgeParameter reageParameter ) {
1538- return getOutstandingAmountsTillDate (interestSchedule ,
1539- reageParameter .getInterestHandlingType ().equals (LoanReAgeInterestHandlingType .EQUAL_AMORTIZATION_PAYABLE_INTEREST )
1540- ? transactionDate
1541- : interestSchedule .getMaturityDate ());
1560+ public OutstandingDetails precalculateReAgeEqualAmortizationAmount (ProgressiveLoanInterestScheduleModel interestSchedule ,
1561+ LocalDate transactionDate , LoanReAgeParameter reageParameter ) {
1562+ return getOutstandingAmountsTillDate (interestSchedule ,
1563+ reageParameter .getInterestHandlingType ().equals (LoanReAgeInterestHandlingType .EQUAL_AMORTIZATION_PAYABLE_INTEREST )
1564+ ? transactionDate
1565+ : interestSchedule .getMaturityDate ());
15421566 }
15431567
1544-
15451568 @ Override
15461569 public void reAgeEqualAmortization (ProgressiveLoanInterestScheduleModel interestSchedule , LocalDate transactionDate ,
1547- LoanReAgeParameter reageParameter ) {
1570+ LoanReAgeParameter reageParameter , Money feesPenaltiesOutstanding ,
1571+ EqualAmortizationValues feesPenaltiesEqualAmortizationValues ) {
15481572 LocalDate originalMaturityDate = interestSchedule .getMaturityDate ();
15491573 boolean isAfterOriginalMaturityDate = transactionDate .isAfter (originalMaturityDate );
15501574 List <RepaymentPeriod > reAgedRepaymentPeriods = new ArrayList <>(reageParameter .getNumberOfInstallments ());
@@ -1559,6 +1583,9 @@ public void reAgeEqualAmortization(ProgressiveLoanInterestScheduleModel interest
15591583 // close all open repayment period while keep paid amounts
15601584 interestSchedule .repaymentPeriods ().forEach (rp -> {
15611585 rp .setEmi (rp .getTotalPaidAmount ());
1586+ // TODO only works for total unpaid credited interest portions
1587+ rp .getInterestPeriods ().forEach (ip -> ip .addCreditedInterestAmount (ip .getCreditedInterest ().negated ()));
1588+ rp .getInterestPeriods ().forEach (ip -> ip .addCreditedPrincipalAmount (ip .getCreditedPrincipal ().negated ()));
15621589 });
15631590
15641591 // stop calculate unrecognised interest at this point because all
@@ -1573,7 +1600,8 @@ public void reAgeEqualAmortization(ProgressiveLoanInterestScheduleModel interest
15731600 updateModelForReageEqualAmortization (interestSchedule , reageParameter , reAgedRepaymentPeriods , isAfterOriginalMaturityDate );
15741601
15751602 updateEMIForReAgeEqualAmortization (reAgedRepaymentPeriods , reAgeingAmounts .getOutstandingPrincipal (),
1576- reAgeingAmounts .getOutstandingInterest ());
1603+ reAgeingAmounts .getOutstandingInterest (), feesPenaltiesOutstanding , feesPenaltiesEqualAmortizationValues ,
1604+ interestSchedule .zero ().getCurrency ());
15771605
15781606 calculateOutstandingBalance (interestSchedule );
15791607
@@ -1598,7 +1626,7 @@ private void updateModelForReageEqualAmortization(ProgressiveLoanInterestSchedul
15981626 firstReAgedPeriod .setDueDate (toDate );
15991627 firstReAgedPeriod .getLastInterestPeriod ().setDueDate (toDate );
16001628 firstReAgedPeriod .setReAged (true );
1601- firstReAgedPeriod .getPrevious ().ifPresent (prev -> prev .setNoUnrecognisedInterest (true ));
1629+ firstReAgedPeriod .getPrevious ().ifPresent (prev -> prev .setNoUnrecognisedInterest (true ));
16021630 reAgedRepaymentPeriods .add (firstReAgedPeriod );
16031631
16041632 // insert remaining
@@ -1628,12 +1656,13 @@ private void createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(Progressiv
16281656 targetPeriod .addPaidInterestAmount (paidInterestToAdd );
16291657 targetPeriod .addPaidPrincipalAmount (paidPrincipalToAdd );
16301658 targetPeriod .setEmi (targetPeriod .getTotalPaidAmount ());
1659+ targetPeriod .setReAged (true );
1660+ targetPeriod .setReAgedEarlyRepaymentHolder (true );
16311661
16321662 RepaymentPeriod repaymentPeriodToInsert = RepaymentPeriod .create (targetPeriod , targetPeriod .getDueDate (),
16331663 interestSchedule .getMaturityDate (), interestSchedule .zero (), interestSchedule .mc (),
16341664 interestSchedule .loanProductRelatedDetail ());
16351665 repaymentPeriodToInsert .setReAged (true );
1636- repaymentPeriodToInsert .setReAgedEarlyRepaymentHolder (true );
16371666 interestSchedule .repaymentPeriods ().add (repaymentPeriodToInsert );
16381667 }
16391668
0 commit comments