package org.mifos.clientportfolio.newloan.domain; import static org.mifos.accounts.loan.util.helpers.LoanConstants.PRORATE_RULE; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.mifos.accounts.loan.util.helpers.InstallmentPrincipalAndInterest; import org.mifos.accounts.productdefinition.util.helpers.GraceType; import org.mifos.config.business.ConfigurationKeyValue; import org.mifos.config.persistence.ConfigurationPersistence; import org.mifos.framework.util.helpers.Money; import org.mifos.framework.util.helpers.MoneyUtils; public class DecliningBalanceEqualPrincipalWithInterestGenerator implements PrincipalWithInterestGenerator { @Override public List<InstallmentPrincipalAndInterest> generateEqualInstallments(LoanInterestCalculationDetails loanInterestCalculationDetails) { Money loanAmount = loanInterestCalculationDetails.getLoanAmount(); Integer numberOfInstallments = loanInterestCalculationDetails.getNumberOfInstallments(); Double interestFractionalRatePerInstallment = loanInterestCalculationDetails.getInterestFractionalRatePerInstallment(); GraceType graceType = loanInterestCalculationDetails.getGraceType(); Integer gracePeriodDuration = loanInterestCalculationDetails.getGracePeriodDuration(); //For M5193 int prorateValue = 0; List<InstallmentPrincipalAndInterest> lstInstallmntPricplIntrst = null; LocalDate disbursalDateInLocalDate=loanInterestCalculationDetails.getDisbursementDate(); DateTime disbursalDate=disbursalDateInLocalDate.toDateTimeAtStartOfDay(); List<DateTime> scheduledDates=loanInterestCalculationDetails.getLoanScheduleDates(); if(scheduledDates.size() > 2){ //chek whether loanscheduledDates are there DateTime firstRepaymentDay=scheduledDates.get(0); long differenceOfTwoDatesinMilliseconds=(firstRepaymentDay.toDate().getTime()-disbursalDate.toDate().getTime()); long noOfDays=differenceOfTwoDatesinMilliseconds/(1000*60*60*24); int noOfDaysBetweenFirstRepaymentDayAndDisbursalDate=(int)noOfDays; DateTime secondRepaymentDay=scheduledDates.get(1); long duration=(secondRepaymentDay.toDate().getTime()-firstRepaymentDay.toDate().getTime())/(1000*60*60*24); int noOfDaysInOneSchedule=(int)duration; prorateValue = new ConfigurationPersistence().getConfigurationValueInteger(PRORATE_RULE); if (prorateValue==1) lstInstallmntPricplIntrst = allDecliningEPIInstallments_v2(loanAmount, numberOfInstallments, interestFractionalRatePerInstallment, graceType, gracePeriodDuration,noOfDaysBetweenFirstRepaymentDayAndDisbursalDate,noOfDaysInOneSchedule); } if (prorateValue != 1){ lstInstallmntPricplIntrst = allDecliningEPIInstallments_v2(loanAmount, numberOfInstallments, interestFractionalRatePerInstallment, graceType, gracePeriodDuration); } return lstInstallmntPricplIntrst;} //for M5193 private List<InstallmentPrincipalAndInterest> allDecliningEPIInstallments_v2(Money loanAmount, Integer numberOfInstallments, Double interestFractionalRatePerInstallment, GraceType graceType, Integer gracePeriodDuration,Integer days,Integer durationInDays) { List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>(); if (graceType == GraceType.NONE || graceType == GraceType.GRACEONALLREPAYMENTS) { emiInstallments = generateDecliningEPIInstallmentsNoGrace_v2(numberOfInstallments, loanAmount, interestFractionalRatePerInstallment); } else { emiInstallments = generateDecliningInstallmentsInterestOnly_v2(loanAmount, gracePeriodDuration, interestFractionalRatePerInstallment,days,durationInDays); emiInstallments.addAll(generateDecliningEPIInstallmentsNoGrace_v2(numberOfInstallments - gracePeriodDuration, loanAmount, interestFractionalRatePerInstallment)); } return emiInstallments; } private List<InstallmentPrincipalAndInterest> generateDecliningInstallmentsInterestOnly_v2(Money loanAmount, Integer gracePeriodDuration, Double interestFractionalRatePerInstallment,Integer days,Integer durationInDays) { List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>(); Money zeroPrincipal = MoneyUtils.zero(loanAmount.getCurrency()); for (int i = 0; i < gracePeriodDuration; i++) { if (i<1) { int noOfDaysBetweenDisbursaldateAndNextMeetingDate=days; Money interestPerInstallment = loanAmount.multiply(interestFractionalRatePerInstallment,noOfDaysBetweenDisbursaldateAndNextMeetingDate,durationInDays); InstallmentPrincipalAndInterest installment = new InstallmentPrincipalAndInterest(zeroPrincipal, interestPerInstallment); emiInstallments.add(installment); } else{ InstallmentPrincipalAndInterest installment = new InstallmentPrincipalAndInterest(zeroPrincipal, loanAmount.multiply(interestFractionalRatePerInstallment)); emiInstallments.add(installment); } } return emiInstallments; } private List<InstallmentPrincipalAndInterest> allDecliningEPIInstallments_v2(Money loanAmount, Integer numberOfInstallments, Double interestFractionalRatePerInstallment, GraceType graceType, Integer gracePeriodDuration) { List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>(); if (graceType == GraceType.NONE || graceType == GraceType.GRACEONALLREPAYMENTS) { emiInstallments = generateDecliningEPIInstallmentsNoGrace_v2(numberOfInstallments, loanAmount, interestFractionalRatePerInstallment); } else { emiInstallments = generateDecliningInstallmentsInterestOnly_v2(loanAmount, gracePeriodDuration, interestFractionalRatePerInstallment); emiInstallments.addAll(generateDecliningEPIInstallmentsNoGrace_v2(numberOfInstallments - gracePeriodDuration, loanAmount, interestFractionalRatePerInstallment)); } return emiInstallments; } /** * Generate interest-only payments for the duration of the grace period. Interest paid is on the outstanding * balance, which during the grace period is the entire principal amount. */ private List<InstallmentPrincipalAndInterest> generateDecliningInstallmentsInterestOnly_v2(Money loanAmount, Integer gracePeriodDuration, Double interestFractionalRatePerInstallment) { List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>(); Money zeroPrincipal = MoneyUtils.zero(loanAmount.getCurrency()); Money interestPerInstallment = loanAmount.multiply(interestFractionalRatePerInstallment); for (int i = 0; i < gracePeriodDuration; i++) { InstallmentPrincipalAndInterest installment = new InstallmentPrincipalAndInterest(zeroPrincipal, interestPerInstallment); emiInstallments.add(installment); } return emiInstallments; } private List<InstallmentPrincipalAndInterest> generateDecliningEPIInstallmentsNoGrace_v2(final int numInstallments, Money loanAmount, Double interestFractionalRatePerInstallment) { List<InstallmentPrincipalAndInterest> emiInstallments = new ArrayList<InstallmentPrincipalAndInterest>(); Money principalBalance = loanAmount; Money principalPerPeriod = principalBalance.divide(new BigDecimal(numInstallments)); double interestRate = interestFractionalRatePerInstallment; for (int i = 0; i < numInstallments; i++) { Money interestThisPeriod = principalBalance.multiply(interestRate); InstallmentPrincipalAndInterest installment = new InstallmentPrincipalAndInterest(principalPerPeriod, interestThisPeriod); emiInstallments.add(installment); principalBalance = principalBalance.subtract(principalPerPeriod); } return emiInstallments; } }