From 2acf985e988a20c0f9a835519b1be3843188933c Mon Sep 17 00:00:00 2001 From: Kristof Jozsa Date: Wed, 28 Aug 2024 13:55:10 +0200 Subject: [PATCH] FINERACT-1981: pay off schedule handling --- .../LoanRepaymentScheduleInstallment.java | 42 +++++---- ...edPaymentScheduleTransactionProcessor.java | 85 ++++++++++++++++--- .../ProgressiveLoanScheduleGenerator.java | 46 +++++----- 3 files changed, 119 insertions(+), 54 deletions(-) diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java index 34d8baf6b5c..afaf345bfda 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.portfolio.loanaccount.domain; +import static org.apache.fineract.portfolio.loanproduct.domain.AllocationType.PENALTY; + import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -169,18 +171,18 @@ public LoanRepaymentScheduleInstallment() { } public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate, - final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges, - final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent, - final Set compoundingDetails, final BigDecimal rescheduleInterestPortion) { + final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges, + final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent, + final Set compoundingDetails, final BigDecimal rescheduleInterestPortion) { this(loan, installmentNumber, fromDate, dueDate, principal, interest, feeCharges, penaltyCharges, recalculatedInterestComponent, compoundingDetails, rescheduleInterestPortion, false); } public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate, - final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges, - final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent, - final Set compoundingDetails, final BigDecimal rescheduleInterestPortion, - final boolean isDownPayment) { + final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges, + final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent, + final Set compoundingDetails, final BigDecimal rescheduleInterestPortion, + final boolean isDownPayment) { this.loan = loan; this.installmentNumber = installmentNumber; this.fromDate = fromDate; @@ -200,9 +202,9 @@ public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installme } public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate, - final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges, - final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent, - final Set compoundingDetails) { + final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges, + final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent, + final Set compoundingDetails) { this.loan = loan; this.installmentNumber = installmentNumber; this.fromDate = fromDate; @@ -228,9 +230,9 @@ public LoanRepaymentScheduleInstallment(final Loan loan) { } public LoanRepaymentScheduleInstallment(Loan loan, Integer installmentNumber, LocalDate fromDate, LocalDate dueDate, - BigDecimal principal, BigDecimal interestCharged, BigDecimal feeChargesCharged, BigDecimal penaltyCharges, - BigDecimal creditedPrincipal, BigDecimal creditedFee, BigDecimal creditedPenalty, boolean additional, boolean isDownPayment, - boolean isReAged) { + BigDecimal principal, BigDecimal interestCharged, BigDecimal feeChargesCharged, BigDecimal penaltyCharges, + BigDecimal creditedPrincipal, BigDecimal creditedFee, BigDecimal creditedPenalty, boolean additional, boolean isDownPayment, + boolean isReAged) { this.loan = loan; this.installmentNumber = installmentNumber; this.fromDate = fromDate; @@ -248,7 +250,7 @@ public LoanRepaymentScheduleInstallment(Loan loan, Integer installmentNumber, Lo } public static LoanRepaymentScheduleInstallment newReAgedInstallment(final Loan loan, final Integer installmentNumber, - final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal) { + final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal) { return new LoanRepaymentScheduleInstallment(loan, installmentNumber, fromDate, dueDate, principal, null, null, null, null, null, null, false, false, true); } @@ -488,6 +490,10 @@ public void resetChargesCharged() { this.penaltyCharges = null; } + public boolean isCurrentInstallment(LocalDate transactionDate) { + return getFromDate().isBefore(transactionDate) && !getDueDate().isBefore(transactionDate); + } + public interface PaymentFunction { Money accept(LocalDate transactionDate, Money transactionAmountRemaining); @@ -717,7 +723,7 @@ public boolean isOverdueOn(final LocalDate date) { } public void updateChargePortion(final Money feeChargesDue, final Money feeChargesWaived, final Money feeChargesWrittenOff, - final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) { + final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) { this.feeChargesCharged = defaultToNullIfZero(feeChargesDue.getAmount()); this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.getAmount()); this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.getAmount()); @@ -727,7 +733,7 @@ public void updateChargePortion(final Money feeChargesDue, final Money feeCharge } public void addToChargePortion(final Money feeChargesDue, final Money feeChargesWaived, final Money feeChargesWrittenOff, - final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) { + final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) { this.feeChargesCharged = defaultToNullIfZero(feeChargesDue.plus(this.feeChargesCharged).getAmount()); this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.plus(this.feeChargesWaived).getAmount()); this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.plus(this.feeChargesWrittenOff).getAmount()); @@ -754,7 +760,7 @@ public void updateObligationsMet(final MonetaryCurrency currency, final LocalDat } private void trackAdvanceAndLateTotalsForRepaymentPeriod(final LocalDate transactionDate, final MonetaryCurrency currency, - final Money amountPaidInRepaymentPeriod) { + final Money amountPaidInRepaymentPeriod) { if (isInAdvance(transactionDate)) { this.totalPaidInAdvance = asMoney(this.totalPaidInAdvance, currency).plus(amountPaidInRepaymentPeriod).getAmount(); } else if (isLatePayment(transactionDate)) { @@ -976,7 +982,7 @@ public Money unpayPrincipalComponent(final LocalDate transactionDate, final Mone } private void reduceAdvanceAndLateTotalsForRepaymentPeriod(final LocalDate transactionDate, final MonetaryCurrency currency, - final Money amountDeductedInRepaymentPeriod) { + final Money amountDeductedInRepaymentPeriod) { if (isInAdvance(transactionDate)) { Money mTotalPaidInAdvance = Money.of(currency, this.totalPaidInAdvance); diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java index a9b5773b94e..0a28422cd07 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java @@ -79,6 +79,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ProgressiveLoanScheduleGenerator; import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator; import org.apache.fineract.portfolio.loanproduct.domain.AllocationType; import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType; @@ -281,7 +282,7 @@ protected LoanTransaction findOriginalTransaction(LoanTransaction loanTransactio } return originalTransaction.get(); } else { // when there is no id, then it might be that the original transaction is changed, so we need to look - // it up from the Ctx. + // it up from the Ctx. Long originalChargebackTransactionId = ctx.getChangedTransactionDetail().getCurrentTransactionToOldId().get(loanTransaction); Collection updatedTransactions = ctx.getChangedTransactionDetail().getNewTransactionMappings().values(); Optional updatedTransaction = updatedTransactions.stream().filter(tr -> tr.getLoanTransactionRelations() @@ -1157,22 +1158,22 @@ private Money processAllocationsHorizontally(LoanTransaction loanTransaction, Mo // For having similar logic we are populating installment list even when the future installment // allocation rule is NEXT_INSTALLMENT or LAST_INSTALLMENT hence the list has only one element. - List inAdvanceInstallments = new ArrayList<>(); - if (FutureInstallmentAllocationRule.REAMORTIZATION.equals(futureInstallmentAllocationRule)) { - inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) + List inAdvanceInstallments = switch (futureInstallmentAllocationRule) { + case REAMORTIZATION -> installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) .filter(e -> loanTransaction.isBefore(e.getDueDate())).toList(); - } else if (FutureInstallmentAllocationRule.NEXT_INSTALLMENT.equals(futureInstallmentAllocationRule)) { - inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) - .filter(e -> loanTransaction.isBefore(e.getDueDate())) - .min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList(); - } else if (FutureInstallmentAllocationRule.LAST_INSTALLMENT.equals(futureInstallmentAllocationRule)) { - inAdvanceInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) - .filter(e -> loanTransaction.isBefore(e.getDueDate())) - .max(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList(); - } + case NEXT_INSTALLMENT -> // first future unpaid installment + installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) + .filter(e -> loanTransaction.isBefore(e.getDueDate())) + .min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList(); + case LAST_INSTALLMENT -> // last future unpaid installment + installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff) + .filter(e -> loanTransaction.isBefore(e.getDueDate())) + .max(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList(); + }; int firstNormalInstallmentNumber = LoanRepaymentScheduleProcessingWrapper.fetchFirstNormalInstallmentNumber(installments); + Money originalInterestOfCurrentInstallment = null; for (PaymentAllocationType paymentAllocationType : paymentAllocationTypes) { switch (paymentAllocationType.getDueType()) { case PAST_DUE -> { @@ -1206,6 +1207,51 @@ private Money processAllocationsHorizontally(LoanTransaction loanTransaction, Mo case IN_ADVANCE -> { int numberOfInstallments = inAdvanceInstallments.size(); if (numberOfInstallments > 0) { + if (loanTransaction.getLoan().getLoanProduct().isInterestRecalculationEnabled()) { + AtomicReference sumAdjusted = new AtomicReference<>(Money.zero(currency)); + + // recalculate interest before processing payment + for (LoanRepaymentScheduleInstallment installment : inAdvanceInstallments) { + LocalDate transactionDate = loanTransaction.getTransactionDate(); + if (installment.isCurrentInstallment(transactionDate)) { + switch (paymentAllocationType) { + case IN_ADVANCE_INTEREST -> { + Money payableInterest = ProgressiveLoanScheduleGenerator + .calculatePayableInterest(installment, transactionDate); + originalInterestOfCurrentInstallment = installment.getInterestCharged(currency); + installment.updateInterestCharged(payableInterest.getAmount()); + } + case IN_ADVANCE_PRINCIPAL -> { + Money interestDelta = calculateInterestDelta(originalInterestOfCurrentInstallment, + installment, transactionDate, currency); + sumAdjusted.updateAndGet(v -> v.add(interestDelta)); + BigDecimal newPrincipal = installment.getPrincipal(currency).plus(interestDelta) + .getAmount(); + installment.updatePrincipal(newPrincipal); + } + } + + // find last installment number + int lastInstallmentNumber = installments.stream() // + .mapToInt(LoanRepaymentScheduleInstallment::getInstallmentNumber) // + .max().orElse(0); + + // update later installments with zero interest and increased principal + installments.stream().filter(it -> it.getInstallmentNumber() > installment.getInstallmentNumber()) + .forEach(it -> { + Money interestCharged = it.getInterestCharged(currency); + sumAdjusted.updateAndGet(v -> v.add(interestCharged)); + it.updateInterestCharged(BigDecimal.ZERO); + BigDecimal newPrincipal = it.getPrincipal(currency).plus(interestCharged).getAmount(); + if (it.getInstallmentNumber() == lastInstallmentNumber) { + newPrincipal = newPrincipal.subtract(sumAdjusted.get().getAmount()); + } + it.updatePrincipal(newPrincipal); + }); + } + } + } + // This will be the same amount as transactionAmountUnprocessed in case of the future // installment allocation is NEXT_INSTALLMENT or LAST_INSTALLMENT Money evenPortion = transactionAmountUnprocessed.dividedBy(numberOfInstallments, MoneyHelper.getRoundingMode()); @@ -1239,6 +1285,19 @@ private Money processAllocationsHorizontally(LoanTransaction loanTransaction, Mo return transactionAmountUnprocessed; } + private Money calculateInterestDelta(Money originalInterestOfCurrentInstallment, LoanRepaymentScheduleInstallment installment, + LocalDate transactionDate, MonetaryCurrency currency) { + if (originalInterestOfCurrentInstallment == null) { + // interest was not recalculated yet + Money payableInterest = ProgressiveLoanScheduleGenerator.calculatePayableInterest(installment, transactionDate); + originalInterestOfCurrentInstallment = installment.getInterestCharged(currency); + return originalInterestOfCurrentInstallment.minus(payableInterest); + } else { + // interest was already recalculated + return originalInterestOfCurrentInstallment.minus(installment.getInterestCharged(currency)); + } + } + @NotNull private static Set getLoanChargesOfInstallment(Set charges, LoanRepaymentScheduleInstallment currentInstallment, int firstNormalInstallmentNumber) { diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java index adfd1f1b78d..c18fea45f50 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java @@ -65,7 +65,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator { @Override public LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms, - final Set loanCharges, final HolidayDetailDTO holidayDetailDTO) { + final Set loanCharges, final HolidayDetailDTO holidayDetailDTO) { final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency(); // generate list of proposed schedule due dates @@ -170,8 +170,8 @@ private void prepareDisbursementsOnLoanApplicationTerms(final LoanApplicationTer } private void processDisbursements(final LoanApplicationTerms loanApplicationTerms, final LoanScheduleParams scheduleParams, - final ProgressiveLoanInterestScheduleModel interestScheduleModel, final List periods, - final BigDecimal chargesDueAtTimeOfDisbursement) { + final ProgressiveLoanInterestScheduleModel interestScheduleModel, final List periods, + final BigDecimal chargesDueAtTimeOfDisbursement) { for (DisbursementData disbursementData : loanApplicationTerms.getDisbursementDatas()) { final LocalDate disbursementDate = disbursementData.disbursementDate(); @@ -231,16 +231,16 @@ private void processDisbursements(final LoanApplicationTerms loanApplicationTerm @Override public LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Loan loan, - HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, - LocalDate rescheduleFrom) { + HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, + LocalDate rescheduleFrom) { LoanScheduleModel model = generate(mc, loanApplicationTerms, loan.getActiveCharges(), holidayDetailDTO); return LoanScheduleDTO.from(null, model); } @Override public OutstandingAmountsDTO calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate, - LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO, - LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) { + LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO, + LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) { return switch (loanApplicationTerms.getPreClosureInterestCalculationStrategy()) { case TILL_PRE_CLOSURE_DATE -> { log.debug("calculating prepayment amount till pre closure date (Strategy A)"); @@ -252,7 +252,7 @@ public OutstandingAmountsDTO calculatePrepaymentAmount(MonetaryCurrency currency outstandingAmounts.plusPrincipal(installment.getPrincipalOutstanding(currency)); if (isInstallmentAfterPayoff) { if (firstAfterPayoff.getAndSet(false)) { - outstandingAmounts.plusInterest(calculatePayableInterest(loan, installment, onDate)); + outstandingAmounts.plusInterest(calculatePayableInterest(installment, onDate)); } else { log.debug("Installment {} - {} is after payoff, not counting interest", installment.getFromDate(), installment.getDueDate()); @@ -290,9 +290,9 @@ public OutstandingAmountsDTO calculatePrepaymentAmount(MonetaryCurrency currency }; } - private Money calculatePayableInterest(Loan loan, LoanRepaymentScheduleInstallment installment, LocalDate onDate) { + public static Money calculatePayableInterest(LoanRepaymentScheduleInstallment installment, LocalDate onDate) { RoundingMode roundingMode = MoneyHelper.getRoundingMode(); - MonetaryCurrency currency = loan.getCurrency(); + MonetaryCurrency currency = installment.getLoan().getCurrency(); Money originalInterest = installment.getInterestCharged(currency); log.debug("calculating interest for {} from {} to {}", originalInterest, installment.getFromDate(), installment.getDueDate()); @@ -326,7 +326,7 @@ private BigDecimal deriveTotalChargesDueAtTimeOfDisbursement(final Set loanCharges, - final LoanScheduleParams scheduleParams, final MonetaryCurrency currency, final MathContext mc) { + final LoanScheduleParams scheduleParams, final MonetaryCurrency currency, final MathContext mc) { final PrincipalInterest principalInterest = new PrincipalInterest(repaymentPeriod.getPrincipalDue(), repaymentPeriod.getInterestDue(), null); @@ -343,9 +343,9 @@ private void applyChargesForCurrentPeriod(final LoanScheduleModelRepaymentPeriod } private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set loanCharges, - final MonetaryCurrency monetaryCurrency, final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed, - final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod, - final MathContext mc) { + final MonetaryCurrency monetaryCurrency, final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed, + final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod, + final MathContext mc) { Money cumulative = Money.zero(monetaryCurrency); for (final LoanCharge loanCharge : loanCharges) { if (!loanCharge.isDueAtDisbursement() && loanCharge.isFeeCharge()) { @@ -357,8 +357,8 @@ private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final L } private Money getCumulativeAmountOfCharge(LocalDate periodStart, LocalDate periodEnd, PrincipalInterest principalInterestForThisPeriod, - Money principalDisbursed, Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, - boolean isFirstPeriod, LoanCharge loanCharge, Money cumulative, MathContext mc) { + Money principalDisbursed, Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, + boolean isFirstPeriod, LoanCharge loanCharge, Money cumulative, MathContext mc) { boolean isDue = isFirstPeriod ? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, periodEnd) : loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd); if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) { @@ -375,10 +375,10 @@ private Money getCumulativeAmountOfCharge(LocalDate periodStart, LocalDate perio } private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, - final Set loanCharges, final MonetaryCurrency monetaryCurrency, - final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed, - final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod, - final MathContext mc) { + final Set loanCharges, final MonetaryCurrency monetaryCurrency, + final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed, + final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod, + final MathContext mc) { Money cumulative = Money.zero(monetaryCurrency); for (final LoanCharge loanCharge : loanCharges) { if (loanCharge.isPenaltyCharge()) { @@ -390,7 +390,7 @@ private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, fin } private Money calculateInstallmentCharge(final PrincipalInterest principalInterestForThisPeriod, Money cumulative, - final LoanCharge loanCharge, final MathContext mc) { + final LoanCharge loanCharge, final MathContext mc) { if (loanCharge.getChargeCalculation().isPercentageBased()) { BigDecimal amount = BigDecimal.ZERO; if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) { @@ -410,7 +410,7 @@ private Money calculateInstallmentCharge(final PrincipalInterest principalIntere } private Money calculateSpecificDueDateChargeWithPercentage(final Money principalDisbursed, - final Money totalInterestChargedForFullLoanTerm, Money cumulative, final LoanCharge loanCharge, final MathContext mc) { + final Money totalInterestChargedForFullLoanTerm, Money cumulative, final LoanCharge loanCharge, final MathContext mc) { BigDecimal amount = BigDecimal.ZERO; if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) { amount = amount.add(principalDisbursed.getAmount()).add(totalInterestChargedForFullLoanTerm.getAmount()); @@ -425,7 +425,7 @@ private Money calculateSpecificDueDateChargeWithPercentage(final Money principal } private void updatePeriodsWithCharges(final MonetaryCurrency currency, LoanScheduleParams scheduleParams, - final Collection periods, final Set nonCompoundingCharges, MathContext mc) { + final Collection periods, final Set nonCompoundingCharges, MathContext mc) { for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) { if (loanScheduleModelPeriod.isRepaymentPeriod()) { PrincipalInterest principalInterest = new PrincipalInterest(Money.of(currency, loanScheduleModelPeriod.principalDue()),