MIFOSX-721: fix issue with daily interest calculation when using interest charged from date feature.
This commit is contained in:
+20
-12
@@ -65,10 +65,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
this.paymentPeriodsInOneYearCalculator, mc);
|
||||
|
||||
// 5. loop over the known set of 'scheduled due dates'
|
||||
LocalDate repaymentPeriodStartDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
|
||||
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
|
||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), scheduledDates);
|
||||
|
||||
LocalDate startDate = loanApplicationTerms.getExpectedDisbursementDate();
|
||||
LocalDate periodStartDate = loanApplicationTerms.getExpectedDisbursementDate();
|
||||
LocalDate periodStartDateApplicableForInterest = periodStartDate;
|
||||
int periodNumber = 1;
|
||||
Money totalCumulativePrincipal = principalDisbursed.zero();
|
||||
Money totalCumulativeInterest = principalDisbursed.zero();
|
||||
@@ -76,18 +77,24 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
Money outstandingBalance = principalDisbursed;
|
||||
for (final LocalDate scheduledDueDate : scheduledDates) {
|
||||
|
||||
final int daysInPeriod = Days.daysBetween(startDate, scheduledDueDate).getDays();
|
||||
final int daysInPeriod = Days.daysBetween(periodStartDate, scheduledDueDate).getDays();
|
||||
int daysInPeriodApplicableForInterest = daysInPeriod;
|
||||
|
||||
if (periodStartDate.isBefore(idealDisbursementDate)) {
|
||||
periodStartDateApplicableForInterest = idealDisbursementDate;
|
||||
daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDateApplicableForInterest, scheduledDueDate).getDays();
|
||||
}
|
||||
|
||||
final double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
|
||||
.calculatePortionOfRepaymentPeriodInterestChargingGrace(repaymentPeriodStartDate, scheduledDueDate,
|
||||
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, scheduledDueDate,
|
||||
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms.getLoanTermPeriodFrequencyType(),
|
||||
loanApplicationTerms.getRepaymentEvery());
|
||||
|
||||
// 5 determine principal,interest of repayment period
|
||||
final PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal,
|
||||
totalCumulativeInterest, totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, daysInPeriod,
|
||||
outstandingBalance, loanApplicationTerms, periodNumber, mc);
|
||||
totalCumulativeInterest, totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
||||
daysInPeriodApplicableForInterest, outstandingBalance, loanApplicationTerms, periodNumber, mc);
|
||||
|
||||
// update cumulative fields for principal & interest
|
||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(principalInterestForThisPeriod.principal());
|
||||
@@ -98,8 +105,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
outstandingBalance = outstandingBalance.minus(principalInterestForThisPeriod.principal());
|
||||
|
||||
// 7. determine fees and penalties
|
||||
final Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(startDate, scheduledDueDate, loanCharges, currency);
|
||||
final Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(startDate, scheduledDueDate, loanCharges, currency);
|
||||
final Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges, currency);
|
||||
final Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges,
|
||||
currency);
|
||||
|
||||
// 8. sum up real totalInstallmentDue from components
|
||||
final Money totalInstallmentDue = principalInterestForThisPeriod.principal() //
|
||||
@@ -108,7 +116,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
.plus(penaltyChargesForInstallment);
|
||||
|
||||
// 9. create repayment period from parts
|
||||
final LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(periodNumber, startDate,
|
||||
final LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(periodNumber, periodStartDate,
|
||||
scheduledDueDate, principalInterestForThisPeriod.principal(), outstandingBalance,
|
||||
principalInterestForThisPeriod.interest(), feeChargesForInstallment, penaltyChargesForInstallment, totalInstallmentDue);
|
||||
periods.add(installment);
|
||||
@@ -120,8 +128,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount());
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount());
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(totalInstallmentDue.getAmount());
|
||||
startDate = scheduledDueDate;
|
||||
repaymentPeriodStartDate = startDate;
|
||||
periodStartDate = scheduledDueDate;
|
||||
periodStartDateApplicableForInterest = periodStartDate;
|
||||
|
||||
periodNumber++;
|
||||
}
|
||||
@@ -133,7 +141,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(PaymentPeriodsInOneYearCalculator calculator,
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest,
|
||||
Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, int daysInPeriod, Money outstandingBalance,
|
||||
Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, int daysInPeriodApplicableForInterest, Money outstandingBalance,
|
||||
LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc);
|
||||
|
||||
protected final boolean isLastRepaymentPeriod(final int numberOfRepayments, final int periodNumber) {
|
||||
|
||||
+7
-7
@@ -19,14 +19,14 @@ import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
* <li>Equal installment payments</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* When amortized using <i>equal principal payments</i>, the <b>principal
|
||||
* component</b> of each installment is fixed and <b>interest due</b> is
|
||||
* calculated from the <b>outstanding principal balance</b> resulting in a
|
||||
* different <b>total payment due</b> for each installment.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* When amortized using <i>equal installments</i>, the <b>total payment due</b>
|
||||
* for each installment is fixed and is calculated using the excel like
|
||||
@@ -42,17 +42,17 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
|
||||
@SuppressWarnings("unused") final Money totalCumulativeInterest,
|
||||
@SuppressWarnings("unused") final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
||||
final int daysInPeriod, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms,
|
||||
final int daysInPeriodApplicableForInterest, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms,
|
||||
final int periodNumber, final MathContext mc) {
|
||||
|
||||
final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace, daysInPeriod,
|
||||
outstandingBalance);
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace,
|
||||
daysInPeriodApplicableForInterest, outstandingBalance);
|
||||
|
||||
final Money interestForThisInstallment = result.interest();
|
||||
|
||||
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, daysInPeriod,
|
||||
outstandingBalance, periodNumber, mc);
|
||||
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator,
|
||||
daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc);
|
||||
|
||||
// update cumulative fields for principal & interest
|
||||
final Money interestBroughtFowardDueToGrace = result.interestPaymentDueToGrace();
|
||||
|
||||
+3
-3
@@ -15,14 +15,14 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener
|
||||
public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(final PaymentPeriodsInOneYearCalculator calculator,
|
||||
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
|
||||
final Money totalCumulativeInterest, final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
||||
final int daysInPeriod, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms,
|
||||
final int daysInPeriodApplicableForInterest, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms,
|
||||
final int periodNumber, final MathContext mc) {
|
||||
|
||||
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, daysInPeriod,
|
||||
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, daysInPeriodApplicableForInterest,
|
||||
outstandingBalance, periodNumber, mc);
|
||||
|
||||
final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace, daysInPeriod,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
|
||||
outstandingBalance);
|
||||
Money interestForThisInstallment = result.interest();
|
||||
|
||||
|
||||
+3
-3
@@ -288,7 +288,7 @@ public final class LoanApplicationTerms {
|
||||
|
||||
public PrincipalInterest calculateTotalInterestForPeriod(final PaymentPeriodsInOneYearCalculator calculator,
|
||||
final double interestCalculationGraceOnRepaymentPeriodFraction, final int periodNumber, final MathContext mc,
|
||||
final Money cumulatingInterestPaymentDueToGrace, final int daysInPeriod, final Money outstandingBalance) {
|
||||
final Money cumulatingInterestPaymentDueToGrace, final int daysInPeriodApplicableForInterest, final Money outstandingBalance) {
|
||||
|
||||
Money interestForInstallment = this.principal.zero();
|
||||
Money interestBroughtForwardDueToGrace = cumulatingInterestPaymentDueToGrace.copy();
|
||||
@@ -318,10 +318,10 @@ public final class LoanApplicationTerms {
|
||||
case DECLINING_BALANCE:
|
||||
|
||||
final Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(
|
||||
calculator, mc, daysInPeriod, outstandingBalance);
|
||||
calculator, mc, daysInPeriodApplicableForInterest, outstandingBalance);
|
||||
|
||||
final Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(
|
||||
calculator, interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriod, outstandingBalance, periodNumber);
|
||||
calculator, interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriodApplicableForInterest, outstandingBalance, periodNumber);
|
||||
|
||||
interestForInstallment = interestForThisInstallmentAfterGrace;
|
||||
if (interestForThisInstallmentAfterGrace.isGreaterThanZero()) {
|
||||
|
||||
Reference in New Issue
Block a user