package org.mifos.clientportfolio.newloan.domain;
import java.util.ArrayList;
import java.util.List;
import org.mifos.accounts.loan.util.helpers.InstallmentPrincipalAndInterest;
import org.mifos.accounts.productdefinition.util.helpers.GraceType;
import org.mifos.framework.util.helpers.Money;
import org.mifos.framework.util.helpers.MoneyUtils;
public class FlatLoanPrincipalWithInterestGenerator implements PrincipalWithInterestGenerator {
private final Money loanInterest;
public FlatLoanPrincipalWithInterestGenerator(Money loanInterest) {
this.loanInterest = loanInterest;
}
@Override
public List<InstallmentPrincipalAndInterest> generateEqualInstallments(LoanInterestCalculationDetails loanInterestCalculationDetails) {
GraceType graceType = loanInterestCalculationDetails.getGraceType();
Integer gracePeriodDuration = loanInterestCalculationDetails.getGracePeriodDuration();
Money loanAmount = loanInterestCalculationDetails.getLoanAmount();
Integer numberOfInstallments = loanInterestCalculationDetails.getNumberOfInstallments();
return allFlatInstallments_v2(loanInterest, graceType, loanAmount, numberOfInstallments, gracePeriodDuration);
}
/**
* Generate flat-interest installment variants based on the type of grace period.
* <ul>
* <li>If grace period is none, or applies to both principal and interest, the loan calculations are the same.
* <li>If grace period is for principal only, don't add new installments. The first grace installments are
* interest-only, and principal is paid off with the remaining installments. NOTE: Principal-only grace period
* should be disable for release 1.1.
* </ul>
*/
private List<InstallmentPrincipalAndInterest> allFlatInstallments_v2(final Money loanInterest, GraceType graceType, Money loanAmount, Integer numberOfInstallments, Integer gracePeriodDuration) {
List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>();
Money principalPerInstallment = loanAmount.divide(numberOfInstallments);
Money interestPerInstallment = loanInterest.divide(numberOfInstallments);
if (graceType == GraceType.NONE || graceType == GraceType.GRACEONALLREPAYMENTS) {
emiInstallments = generateFlatInstallmentsNoGrace_v2(principalPerInstallment, interestPerInstallment, numberOfInstallments);
} else {
// getGraceType() == GraceType.PRINCIPALONLYGRACE which is disabled.
emiInstallments = generateFlatInstallmentsInterestOnly_v2(loanInterest, numberOfInstallments, gracePeriodDuration);
emiInstallments.addAll(generateFlatInstallmentsAfterInterestOnlyGraceInstallments_v2(loanInterest, loanAmount, numberOfInstallments, gracePeriodDuration));
}
return emiInstallments;
}
/**
* Calculate the installments after grace period, in the case of principal-only grace type for a flat-interest loan.
* Divide interest evenly among all installments, but divide principle evenly among installments after the grace
* period.
*/
private List<InstallmentPrincipalAndInterest> generateFlatInstallmentsAfterInterestOnlyGraceInstallments_v2(final Money loanInterest, Money loanAmount, Integer numberOfInstallments, Integer gracePeriodDuration) {
List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>();
Money principalPerInstallment = loanAmount.divide(numberOfInstallments - gracePeriodDuration);
Money interestPerInstallment = loanInterest.divide(numberOfInstallments);
for (int i = gracePeriodDuration; i < numberOfInstallments; i++) {
InstallmentPrincipalAndInterest installment = new InstallmentPrincipalAndInterest(principalPerInstallment, interestPerInstallment);
emiInstallments.add(installment);
}
return emiInstallments;
}
/**
* Generate interest-only payments for the duration of the grace period. Interest is divided evenly among all
* installments, but only interest is paid during the grace period.
*/
private List<InstallmentPrincipalAndInterest> generateFlatInstallmentsInterestOnly_v2(final Money loanInterest, Integer numberOfInstallments, Integer gracePeriodDuration) {
List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>();
Money zeroPrincipal = MoneyUtils.zero(loanInterest.getCurrency());
Money interestPerInstallment = loanInterest.divide(numberOfInstallments);
for (int i = 0; i < gracePeriodDuration; i++) {
InstallmentPrincipalAndInterest installment = new InstallmentPrincipalAndInterest(zeroPrincipal, interestPerInstallment);
emiInstallments.add(installment);
}
return emiInstallments;
}
/**
* Divide principal and interest evenly among all installments, no grace period
*/
private List<InstallmentPrincipalAndInterest> generateFlatInstallmentsNoGrace_v2(Money principalPerInstallment, Money interestPerInstallment, Integer numberOfInstallments) {
List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>();
for (int i = 0; i < numberOfInstallments; i++) {
InstallmentPrincipalAndInterest installment = new InstallmentPrincipalAndInterest(principalPerInstallment, interestPerInstallment);
emiInstallments.add(installment);
}
return emiInstallments;
}
}