MIFOSX-672: fix issue with FLAT interest calculation not correctly calculation prinicpal balance for final installments.
This commit is contained in:
+22
-31
@@ -171,15 +171,10 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
Money adjusted = principalForPeriod;
|
Money adjusted = principalForPeriod;
|
||||||
|
|
||||||
// adjust cumulative fields for principal & interest if needed
|
final Money totalPrincipalRemaining = this.principal.minus(totalCumulativePrincipalToDate);
|
||||||
if (this.principal.getAmount().subtract(totalCumulativePrincipalToDate.getAmount()).add(principalForPeriod.getAmount()).compareTo(principalForPeriod.getAmount()) == -1) {
|
if (totalPrincipalRemaining.isLessThanZero()) {
|
||||||
adjusted = adjusted.minus(adjusted);
|
// paid too much principal, subtract amount that overpays from principal paid for period.
|
||||||
MonetaryCurrency monetaryCurrency = new MonetaryCurrency(adjusted.getCurrencyCode(), 0, adjusted.getCurrencyInMultiplesOf());
|
adjusted = principalForPeriod.minus(totalPrincipalRemaining.abs());
|
||||||
BigDecimal diff = this.principal.getAmount().subtract(totalCumulativePrincipalToDate.getAmount()).add(principalForPeriod.getAmount());
|
|
||||||
if(diff.doubleValue()<0){
|
|
||||||
diff = BigDecimal.ZERO;
|
|
||||||
}
|
|
||||||
adjusted = adjusted.plus(Money.of(monetaryCurrency,diff));
|
|
||||||
} else if (isLastRepaymentPeriod(this.numberOfRepayments, periodNumber)) {
|
} else if (isLastRepaymentPeriod(this.numberOfRepayments, periodNumber)) {
|
||||||
|
|
||||||
final Money difference = totalCumulativePrincipalToDate.minus(this.principal);
|
final Money difference = totalCumulativePrincipalToDate.minus(this.principal);
|
||||||
@@ -197,15 +192,11 @@ public final class LoanApplicationTerms {
|
|||||||
final Money totalInterestDueForLoan, final int periodNumber) {
|
final Money totalInterestDueForLoan, final int periodNumber) {
|
||||||
|
|
||||||
Money adjusted = interestForThisPeriod;
|
Money adjusted = interestForThisPeriod;
|
||||||
if (totalInterestDueForLoan.getAmount().subtract(totalCumulativeInterestToDate.getAmount()).add(interestForThisPeriod.getAmount())
|
|
||||||
.compareTo(interestForThisPeriod.getAmount()) == -1) {
|
final Money totalInterestRemaining = totalInterestDueForLoan.minus(totalCumulativeInterestToDate);
|
||||||
adjusted = adjusted.minus(adjusted);
|
if (totalInterestRemaining.isLessThanZero()) {
|
||||||
MonetaryCurrency monetaryCurrency = new MonetaryCurrency(adjusted.getCurrencyCode(), 0, adjusted.getCurrencyInMultiplesOf());
|
// paid too much interest, subtract amount that overpays from interest paid for period.
|
||||||
BigDecimal diff = totalInterestDueForLoan.getAmount().subtract(totalCumulativeInterestToDate.getAmount()).add(interestForThisPeriod.getAmount());
|
adjusted = interestForThisPeriod.minus(totalInterestRemaining.abs());
|
||||||
if(diff.doubleValue()<0){
|
|
||||||
diff = BigDecimal.ZERO;
|
|
||||||
}
|
|
||||||
adjusted = adjusted.plus(Money.of(monetaryCurrency,diff));
|
|
||||||
} else if (isLastRepaymentPeriod(this.numberOfRepayments, periodNumber)) {
|
} else if (isLastRepaymentPeriod(this.numberOfRepayments, periodNumber)) {
|
||||||
final Money interestDifference = totalCumulativeInterestToDate.minus(totalInterestDueForLoan);
|
final Money interestDifference = totalCumulativeInterestToDate.minus(totalInterestDueForLoan);
|
||||||
if (interestDifference.isLessThanZero()) {
|
if (interestDifference.isLessThanZero()) {
|
||||||
@@ -270,7 +261,7 @@ public final class LoanApplicationTerms {
|
|||||||
switch (this.amortizationMethod) {
|
switch (this.amortizationMethod) {
|
||||||
case EQUAL_INSTALLMENTS:
|
case EQUAL_INSTALLMENTS:
|
||||||
// equal installments
|
// equal installments
|
||||||
int periodsElapsed = periodNumber - 1;
|
final int periodsElapsed = periodNumber - 1;
|
||||||
final BigDecimal periodicInterestRateForRepaymentPeriod = periodicInterestRate(calculator, mc);
|
final BigDecimal periodicInterestRateForRepaymentPeriod = periodicInterestRate(calculator, mc);
|
||||||
|
|
||||||
final Money totalPmtForThisInstallment = calculateTotalDueForEqualInstallmentRepaymentPeriod(
|
final Money totalPmtForThisInstallment = calculateTotalDueForEqualInstallmentRepaymentPeriod(
|
||||||
@@ -313,7 +304,7 @@ public final class LoanApplicationTerms {
|
|||||||
case EQUAL_PRINCIPAL:
|
case EQUAL_PRINCIPAL:
|
||||||
// interest follows time-value of money and is brought
|
// interest follows time-value of money and is brought
|
||||||
// forward to next applicable interest payment period
|
// forward to next applicable interest payment period
|
||||||
PrincipalInterest result = calculateTotalFlatInterestForPeriod(calculator, periodNumber, mc,
|
final PrincipalInterest result = calculateTotalFlatInterestForPeriod(calculator, periodNumber, mc,
|
||||||
interestBroughtForwardDueToGrace);
|
interestBroughtForwardDueToGrace);
|
||||||
interestForInstallment = result.interest();
|
interestForInstallment = result.interest();
|
||||||
interestBroughtForwardDueToGrace = result.interestPaymentDueToGrace();
|
interestBroughtForwardDueToGrace = result.interestPaymentDueToGrace();
|
||||||
@@ -324,10 +315,10 @@ public final class LoanApplicationTerms {
|
|||||||
break;
|
break;
|
||||||
case DECLINING_BALANCE:
|
case DECLINING_BALANCE:
|
||||||
|
|
||||||
Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator,
|
final Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator,
|
||||||
mc, daysInPeriod, outstandingBalance);
|
mc, daysInPeriod, outstandingBalance);
|
||||||
|
|
||||||
Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(calculator,
|
final Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(calculator,
|
||||||
interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriod, outstandingBalance, periodNumber);
|
interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriod, outstandingBalance, periodNumber);
|
||||||
|
|
||||||
interestForInstallment = interestForThisInstallmentAfterGrace;
|
interestForInstallment = interestForThisInstallmentAfterGrace;
|
||||||
@@ -359,7 +350,7 @@ public final class LoanApplicationTerms {
|
|||||||
final double paymentPerRepaymentPeriod = paymentPerPeriod(periodicInterestRate, this.principal, periodsElapsed);
|
final double paymentPerRepaymentPeriod = paymentPerPeriod(periodicInterestRate, this.principal, periodsElapsed);
|
||||||
final double totalRepayment = paymentPerRepaymentPeriod * this.numberOfRepayments;
|
final double totalRepayment = paymentPerRepaymentPeriod * this.numberOfRepayments;
|
||||||
|
|
||||||
return Money.of(principal.getCurrency(), BigDecimal.valueOf(totalRepayment));
|
return Money.of(this.principal.getCurrency(), BigDecimal.valueOf(totalRepayment));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -448,12 +439,12 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
final Money totalInterestForLoanTerm = calculateTotalInterestDueWithoutGrace(calculator, mc);
|
final Money totalInterestForLoanTerm = calculateTotalInterestDueWithoutGrace(calculator, mc);
|
||||||
|
|
||||||
Money interestPerGracePeriod = calculateTotalInterestPerInstallmentWithoutGrace(calculator, mc);
|
final Money interestPerGracePeriod = calculateTotalInterestPerInstallmentWithoutGrace(calculator, mc);
|
||||||
|
|
||||||
Money totalInterestFree = interestPerGracePeriod.multipliedBy(getInterestChargingGrace());
|
final Money totalInterestFree = interestPerGracePeriod.multipliedBy(getInterestChargingGrace());
|
||||||
Money realTotalInterestForLoan = totalInterestForLoanTerm.minus(totalInterestFree);
|
final Money realTotalInterestForLoan = totalInterestForLoanTerm.minus(totalInterestFree);
|
||||||
|
|
||||||
Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.numberOfRepayments);
|
final Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.numberOfRepayments);
|
||||||
|
|
||||||
interestForInstallment = realTotalInterestForLoan
|
interestForInstallment = realTotalInterestForLoan
|
||||||
.dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods), mc.getRoundingMode());
|
.dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods), mc.getRoundingMode());
|
||||||
@@ -548,10 +539,10 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
switch (this.interestCalculationPeriodMethod) {
|
switch (this.interestCalculationPeriodMethod) {
|
||||||
case DAILY:
|
case DAILY:
|
||||||
BigDecimal dailyInterestRate = this.annualNominalInterestRate.divide(BigDecimal.valueOf(Long.valueOf(365)), mc)
|
final BigDecimal dailyInterestRate = this.annualNominalInterestRate.divide(BigDecimal.valueOf(Long.valueOf(365)), mc)
|
||||||
.divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc).multiply(BigDecimal.valueOf(this.repaymentEvery));
|
.divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc).multiply(BigDecimal.valueOf(this.repaymentEvery));
|
||||||
|
|
||||||
BigDecimal equivalentInterestRateForPeriod = dailyInterestRate.multiply(BigDecimal.valueOf(Long.valueOf(daysInPeriod)));
|
final BigDecimal equivalentInterestRateForPeriod = dailyInterestRate.multiply(BigDecimal.valueOf(Long.valueOf(daysInPeriod)));
|
||||||
|
|
||||||
interestDue = outstandingBalance.multiplyRetainScale(equivalentInterestRateForPeriod, mc.getRoundingMode());
|
interestDue = outstandingBalance.multiplyRetainScale(equivalentInterestRateForPeriod, mc.getRoundingMode());
|
||||||
break;
|
break;
|
||||||
@@ -589,7 +580,7 @@ public final class LoanApplicationTerms {
|
|||||||
} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25")
|
} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25")
|
||||||
&& interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) {
|
&& interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) {
|
||||||
|
|
||||||
Money graceOnInterestForRepaymentPeriod = interest.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
|
final Money graceOnInterestForRepaymentPeriod = interest.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
|
||||||
interest = interest.minus(graceOnInterestForRepaymentPeriod);
|
interest = interest.minus(graceOnInterestForRepaymentPeriod);
|
||||||
fraction = Double.valueOf("0");
|
fraction = Double.valueOf("0");
|
||||||
}
|
}
|
||||||
@@ -616,7 +607,7 @@ public final class LoanApplicationTerms {
|
|||||||
private Money calculatePrincipalDueForInstallment(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc,
|
private Money calculatePrincipalDueForInstallment(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc,
|
||||||
final int periodNumber, final Money totalDuePerInstallment, final int daysInPeriod, final Money outstandingBalance) {
|
final int periodNumber, final Money totalDuePerInstallment, final int daysInPeriod, final Money outstandingBalance) {
|
||||||
|
|
||||||
Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator, mc,
|
final Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator, mc,
|
||||||
daysInPeriod, outstandingBalance);
|
daysInPeriod, outstandingBalance);
|
||||||
|
|
||||||
Money principal = totalDuePerInstallment.minus(interestForThisInstallmentBeforeGrace);
|
Money principal = totalDuePerInstallment.minus(interestForThisInstallmentBeforeGrace);
|
||||||
|
|||||||
Reference in New Issue
Block a user