diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java index dc6612469..6db6f9ef7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java @@ -38,6 +38,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener final List scheduledDates = this.scheduledDateGenerator.generate(loanApplicationTerms, isHolidayEnabled, holidays, workingDays); + final LocalDate loanEndDate = scheduledDates.get(scheduledDates.size() - 1); + loanApplicationTerms.updateLoanEndDate(loanEndDate); + // 2. determine the total charges due at time of disbursement final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loanCharges); @@ -141,8 +144,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(PaymentPeriodsInOneYearCalculator calculator, double interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest, - Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, int daysInPeriodApplicableForInterest, Money outstandingBalance, - LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc); + Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, int daysInPeriodApplicableForInterest, + Money outstandingBalance, LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc); protected final boolean isLastRepaymentPeriod(final int numberOfRepayments, final int periodNumber) { return periodNumber == numberOfRepayments; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java index e7fbe6be2..e51cf73b7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java @@ -18,12 +18,12 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener final int daysInPeriodApplicableForInterest, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc) { - Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, daysInPeriodApplicableForInterest, - outstandingBalance, periodNumber, mc); + Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, + daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc); final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator, - interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest, - outstandingBalance); + interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace, + daysInPeriodApplicableForInterest, outstandingBalance); Money interestForThisInstallment = result.interest(); // update cumulative fields for principal & interest diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java index 5399600c8..17104577e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java @@ -9,6 +9,7 @@ import java.math.BigDecimal; import java.math.MathContext; import java.util.Date; +import org.joda.time.Days; import org.joda.time.LocalDate; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; @@ -50,7 +51,7 @@ public final class LoanApplicationTerms { * Integer representing the number of 'repayment frequencies' or * installments where 'grace' should apply to the payment of interest in a * loans repayment period (installment). - * + * * Note: Interest is still calculated taking into account the full * loan term, the interest is simply offset to a later period. */ @@ -60,7 +61,7 @@ public final class LoanApplicationTerms { * Integer representing the number of 'repayment frequencies' or * installments where 'grace' should apply to the charging of interest in a * loans repayment period (installment). - * + * * Note: The loan is interest-free for the period of time * indicated. */ @@ -68,7 +69,7 @@ public final class LoanApplicationTerms { /** * Legacy method of support 'grace' on the charging of interest on a loan. - * + * *

* For the typical structured loan, its reasonable to use an integer to * indicate the number of 'repayment frequency' periods the 'grace' should @@ -82,6 +83,9 @@ public final class LoanApplicationTerms { private final LocalDate interestChargedFromDate; private final Money inArrearsTolerance; + // added + private LocalDate loanEndDate; + public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency, final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final AmortizationMethod amortizationMethod, @@ -216,7 +220,7 @@ public final class LoanApplicationTerms { /** * Calculates the total interest to be charged on loan taking into account * grace settings. - * + * */ public Money calculateTotalInterestCharged(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) { @@ -224,7 +228,7 @@ public final class LoanApplicationTerms { switch (this.interestMethod) { case FLAT: - final Money totalInterestChargedForLoanTerm = calculateTotalInterestDueWithoutGrace(calculator, mc); + final Money totalInterestChargedForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(calculator, mc); final Money totalInterestPerInstallment = calculateTotalInterestPerInstallmentWithoutGrace(calculator, mc); @@ -321,7 +325,8 @@ public final class LoanApplicationTerms { calculator, mc, daysInPeriodApplicableForInterest, outstandingBalance); final Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace( - calculator, interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriodApplicableForInterest, outstandingBalance, periodNumber); + calculator, interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriodApplicableForInterest, + outstandingBalance, periodNumber); interestForInstallment = interestForThisInstallmentAfterGrace; if (interestForThisInstallmentAfterGrace.isGreaterThanZero()) { @@ -359,7 +364,7 @@ public final class LoanApplicationTerms { * general method to calculate totalInterestDue discounting any grace * settings */ - private Money calculateTotalInterestDueWithoutGrace(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) { + private Money calculateTotalFlatInterestDueWithoutGrace(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) { Money totalInterestDue = this.principal.zero(); @@ -385,15 +390,43 @@ public final class LoanApplicationTerms { final long loanTermPeriodsInOneYear = calculatePeriodsInOneYear(calculator); final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal.valueOf(loanTermPeriodsInOneYear); - final BigDecimal loanTermFrequencyBigDecimal = BigDecimal.valueOf(this.loanTermFrequency); + final BigDecimal loanTermFrequencyBigDecimal = calculatePeriodsInLoanTerm(); return this.annualNominalInterestRate.divide(loanTermPeriodsInYearBigDecimal, mc).divide(divisor, mc) .multiply(loanTermFrequencyBigDecimal); } + private BigDecimal calculatePeriodsInLoanTerm() { + + BigDecimal periodsInLoanTerm = BigDecimal.valueOf(this.loanTermFrequency); + switch (this.interestCalculationPeriodMethod) { + case DAILY: + // number of days from 'ideal disbursement' to final date + + LocalDate loanStartDate = getExpectedDisbursementDate(); + if (getInterestChargedFromDate() != null && loanStartDate.isBefore(getInterestChargedFromLocalDate())) { + loanStartDate = getInterestChargedFromLocalDate(); + } + + final int periodsInLoanTermInteger = Days.daysBetween(loanStartDate, this.loanEndDate).getDays(); + periodsInLoanTerm = BigDecimal.valueOf(periodsInLoanTermInteger); + break; + case INVALID: + break; + case SAME_AS_REPAYMENT_PERIOD: + break; + } + + return periodsInLoanTerm; + } + + public void updateLoanEndDate(final LocalDate loanEndDate) { + this.loanEndDate = loanEndDate; + } + private Money calculateTotalInterestPerInstallmentWithoutGrace(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) { - final Money totalInterestForLoanTerm = calculateTotalInterestDueWithoutGrace(calculator, mc); + final Money totalInterestForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(calculator, mc); return totalInterestForLoanTerm.dividedBy(Long.valueOf(this.numberOfRepayments), mc.getRoundingMode()); } @@ -439,7 +472,7 @@ public final class LoanApplicationTerms { interestForInstallment = interestForInstallment.zero(); } else { - final Money totalInterestForLoanTerm = calculateTotalInterestDueWithoutGrace(calculator, mc); + final Money totalInterestForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(calculator, mc); final Money interestPerGracePeriod = calculateTotalInterestPerInstallmentWithoutGrace(calculator, mc); @@ -469,7 +502,19 @@ public final class LoanApplicationTerms { } private long calculatePeriodsInOneYear(final PaymentPeriodsInOneYearCalculator calculator) { - return calculator.calculate(this.repaymentPeriodFrequencyType).longValue(); + + long periodsInOneYear = calculator.calculate(this.repaymentPeriodFrequencyType).longValue(); + switch (this.interestCalculationPeriodMethod) { + case DAILY: + periodsInOneYear = calculator.calculate(PeriodFrequencyType.DAYS).longValue(); + break; + case INVALID: + break; + case SAME_AS_REPAYMENT_PERIOD: + break; + } + + return periodsInOneYear; } private int calculateNumberOfRepaymentsWithPrincipalPayment() {