support fees on specified dates for FLAT interest type loans and loan schedules.

This commit is contained in:
Keith Woodlock
2013-02-07 01:01:44 +00:00
parent 059c2d4529
commit 22698f09df
8 changed files with 226 additions and 211 deletions
@@ -225,7 +225,7 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo
createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, entryDate, principalAmount);
}
}
if (principalAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(interestAmount);
GLAccount interestAccount = getLinkedFinAccountForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS);
@@ -118,7 +118,8 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
for (LoanCharge loanCharge : charges) {
if (!loanCharge.isDueAtDisbursement()) {
if (loanCharge.isFeeCharge() && loanCharge.isNotFullyPaid() && amountRemaining.isGreaterThanZero()) {
amountRemaining = loanCharge.updatePaidAmountBy(amountRemaining);
final LoanCharge unpaidCharge = findEarliestUnpaidChargeFromUnOrderedSet(charges);
amountRemaining = unpaidCharge.updatePaidAmountBy(amountRemaining);
}
}
}
@@ -91,14 +91,14 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
principalPortion = currentInstallment.payPrincipalComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
@@ -130,18 +130,18 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
interestPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
} else {
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
// 1. pay of principal before interest.
principalPortion = currentInstallment.payPrincipalComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
@@ -742,6 +742,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final LocalDate submittedOn, final String externalId) {
final LoanScheduleData loanScheduleData = loanSchedule.generate();
// Have to set expectedDisbursementDate to avoid nullPointer so should be passed down to updateLoanSchedule method
if (loanSchedule.getDisbursementDate() != null) {
this.expectedDisbursedOnDate = loanSchedule.getDisbursementDate().toDate();
}
updateLoanSchedule(loanScheduleData);
LoanStatus from = null;
@@ -760,10 +766,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.submittedOnDate = submittedOn.toDate();
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
if (loanSchedule.getDisbursementDate() != null) {
this.expectedDisbursedOnDate = loanSchedule.getDisbursementDate().toDate();
}
if (loanSchedule.getRepaymentStartFromDate() != null) {
this.expectedFirstRepaymentOnDate = loanSchedule.getRepaymentStartFromDate().toDate();
}
@@ -12,13 +12,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
public interface AmortizationLoanScheduleGenerator {
LoanScheduleData generate(
ApplicationCurrency applicationCurrency,
LoanProductRelatedDetail loanScheduleInfo,
LocalDate disbursementDate,
LocalDate interestCalculatedFrom,
BigDecimal periodInterestRateForRepaymentPeriod,
LocalDate idealDisbursementDateBasedOnFirstRepaymentDate,
List<LocalDate> scheduledDates,
Set<LoanCharge> loanCharges);
LoanScheduleData generate(ApplicationCurrency applicationCurrency, LoanProductRelatedDetail loanScheduleInfo,
LocalDate disbursementDate, LocalDate interestCalculatedFrom, BigDecimal periodInterestRateForRepaymentPeriod,
LocalDate idealDisbursementDateBasedOnFirstRepaymentDate, List<LocalDate> scheduledDates, Set<LoanCharge> loanCharges);
}
@@ -17,178 +17,164 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleDat
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
/**
* Irregular payments for declining balance not supported
*/
public class EqualInstallmentsAmortizationLoanScheduleGenerator implements AmortizationLoanScheduleGenerator {
private final PeriodicInterestRateCalculator periodicInterestRateCalculator = new PeriodicInterestRateCalculator();
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
private final PmtCalculator pmtCalculator = new PmtCalculator();
@Override
public LoanScheduleData generate(
final ApplicationCurrency currency,
final LoanProductRelatedDetail loanScheduleInfo,
final LocalDate disbursementDate,
final LocalDate interestCalculatedFrom,
final BigDecimal periodInterestRateForRepaymentPeriod,
final LocalDate idealDisbursementDateBasedOnFirstRepaymentDate,
final List<LocalDate> scheduledDates,
final Set<LoanCharge> loanCharges) {
final Collection<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>();
// determine 'total payment' for each repayment based on pmt function (and hence the total due overall)
final MonetaryCurrency monetaryCurrency = loanScheduleInfo.getPrincipal().getCurrency();
final Money totalDuePerInstallment = this.pmtCalculator.calculatePaymentForOnePeriodFrom(loanScheduleInfo, periodInterestRateForRepaymentPeriod, monetaryCurrency);
final Money totalRepaymentDueForLoanTerm = this.pmtCalculator.calculateTotalRepaymentFrom(loanScheduleInfo, periodInterestRateForRepaymentPeriod, monetaryCurrency);
Money totalInterestDue = totalRepaymentDueForLoanTerm.minus(loanScheduleInfo.getPrincipal());
Money outstandingBalance = loanScheduleInfo.getPrincipal();
Money principalDisbursed = loanScheduleInfo.getPrincipal();
Money totalPrincipal = Money.zero(monetaryCurrency);
Money totalInterest = Money.zero(monetaryCurrency);
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator.calculateRepaymentPeriodAsAFractionOfDays(
loanScheduleInfo.getRepaymentPeriodFrequencyType(),
loanScheduleInfo.getRepayEvery(),
interestCalculatedFrom,
scheduledDates,
idealDisbursementDateBasedOnFirstRepaymentDate);
BigDecimal chargesDueAtTimeOfDisbursement = BigDecimal.ZERO;
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueAtDisbursement()) {
chargesDueAtTimeOfDisbursement = chargesDueAtTimeOfDisbursement.add(loanCharge.amount());
}
}
BigDecimal cumulativeChargesToDate = chargesDueAtTimeOfDisbursement;
// create entries of disbursement period on loan schedule
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate, principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement, false);
periods.add(disbursementPeriod);
int loanTermInDays = Integer.valueOf(0);
BigDecimal cumulativePrincipalDisbursed = loanScheduleInfo.getPrincipal().getAmount();
BigDecimal cumulativePrincipalDue = BigDecimal.ZERO;
BigDecimal cumulativeInterestExpected = BigDecimal.ZERO;
BigDecimal totalExpectedRepayment = chargesDueAtTimeOfDisbursement;
LocalDate startDate = disbursementDate;
int periodNumber = 1;
for (LocalDate scheduledDueDate : scheduledDates) {
private final PeriodicInterestRateCalculator periodicInterestRateCalculator = new PeriodicInterestRateCalculator();
private final PaymentPeriodsInOneYearCalculator paymentPeriodsInOneYearCalculator = new DefaultPaymentPeriodsInOneYearCalculator();
private final PmtCalculator pmtCalculator = new PmtCalculator();
// number of days from startDate to this scheduledDate
int daysInPeriod = Days.daysBetween(startDate, scheduledDueDate).getDays();
Money interestForInstallment = this.periodicInterestRateCalculator.calculateInterestOn(outstandingBalance, periodInterestRateForRepaymentPeriod, daysInPeriod, loanScheduleInfo);
Money principalForInstallment = this.periodicInterestRateCalculator.calculatePrincipalOn(totalDuePerInstallment, interestForInstallment, loanScheduleInfo);
if (interestCalculationGraceOnRepaymentPeriodFraction >= Integer.valueOf(1).doubleValue()) {
Money graceOnInterestForRepaymentPeriod = interestForInstallment;
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod);
interestCalculationGraceOnRepaymentPeriodFraction = interestCalculationGraceOnRepaymentPeriodFraction - Integer.valueOf(1).doubleValue();
} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25") && interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) {
Money graceOnInterestForRepaymentPeriod = interestForInstallment.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod);
interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf("0");
}
totalPrincipal = totalPrincipal.plus(principalForInstallment);
totalInterest = totalInterest.plus(interestForInstallment);
if (periodNumber == loanScheduleInfo.getNumberOfRepayments()) {
Money principalDifference = totalPrincipal.minus(loanScheduleInfo.getPrincipal());
if (principalDifference.isLessThanZero()) {
principalForInstallment = principalForInstallment.plus(principalDifference.abs());
} else if (principalDifference.isGreaterThanZero()) {
principalForInstallment = principalForInstallment.minus(principalDifference.abs());
}
final Money interestDifference = totalInterest.minus(totalInterestDue);
if (interestDifference.isLessThanZero()) {
interestForInstallment = interestForInstallment.plus(interestDifference.abs());
} else if (interestDifference.isGreaterThanZero()) {
interestForInstallment = interestForInstallment.minus(interestDifference.abs());
}
}
@Override
public LoanScheduleData generate(final ApplicationCurrency currency, final LoanProductRelatedDetail loanScheduleInfo,
final LocalDate disbursementDate, final LocalDate interestCalculatedFrom,
final BigDecimal periodInterestRateForRepaymentPeriod, final LocalDate idealDisbursementDateBasedOnFirstRepaymentDate,
final List<LocalDate> scheduledDates, final Set<LoanCharge> loanCharges) {
outstandingBalance = outstandingBalance.minus(principalForInstallment);
final Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(startDate, scheduledDueDate, loanCharges, monetaryCurrency);
final Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(startDate, scheduledDueDate, loanCharges, monetaryCurrency);
final Money totalInstallmentDue = principalForInstallment.plus(interestForInstallment).plus(feeChargesForInstallment).plus(penaltyChargesForInstallment);
cumulativeChargesToDate = cumulativeChargesToDate.add(feeChargesForInstallment.getAmount());
LoanSchedulePeriodData installment = LoanSchedulePeriodData.repaymentOnlyPeriod(periodNumber, startDate,
scheduledDueDate,
principalForInstallment.getAmount(),
outstandingBalance.getAmount(),
interestForInstallment.getAmount(),
feeChargesForInstallment.getAmount(),
penaltyChargesForInstallment.getAmount(),
totalInstallmentDue.getAmount());
final Collection<LoanSchedulePeriodData> periods = new ArrayList<LoanSchedulePeriodData>();
periods.add(installment);
// handle cumulative fields
loanTermInDays += daysInPeriod;
cumulativePrincipalDue = cumulativePrincipalDue.add(principalForInstallment.getAmount());
cumulativeInterestExpected = cumulativeInterestExpected.add(interestForInstallment.getAmount());
totalExpectedRepayment = totalExpectedRepayment.add(totalInstallmentDue.getAmount());
startDate = scheduledDueDate;
// determine 'total payment' for each repayment based on pmt function
// (and hence the total due overall)
final MonetaryCurrency monetaryCurrency = loanScheduleInfo.getPrincipal().getCurrency();
final Money totalDuePerInstallment = this.pmtCalculator.calculatePaymentForOnePeriodFrom(loanScheduleInfo,
periodInterestRateForRepaymentPeriod, monetaryCurrency);
final Money totalRepaymentDueForLoanTerm = this.pmtCalculator.calculateTotalRepaymentFrom(loanScheduleInfo,
periodInterestRateForRepaymentPeriod, monetaryCurrency);
periodNumber++;
}
final BigDecimal cumulativePrincipalOutstanding = cumulativePrincipalDisbursed.subtract(cumulativePrincipalDue);
CurrencyData currencyData = new CurrencyData(
currency.getCode(),
currency.getName(),
monetaryCurrency.getDigitsAfterDecimal(),
currency.getDisplaySymbol(),
currency.getNameCode());
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
}
Money totalInterestDue = totalRepaymentDueForLoanTerm.minus(loanScheduleInfo.getPrincipal());
Money outstandingBalance = loanScheduleInfo.getPrincipal();
Money principalDisbursed = loanScheduleInfo.getPrincipal();
Money totalPrincipal = Money.zero(monetaryCurrency);
Money totalInterest = Money.zero(monetaryCurrency);
private Money cumulativeFeeChargesDueWithin(
final LocalDate periodStart,
final LocalDate periodEnd,
final Set<LoanCharge> loanCharges,
final MonetaryCurrency monetaryCurrency) {
Money cumulative = Money.zero(monetaryCurrency);
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueForCollectionBetween(periodStart, periodEnd) && loanCharge.isFeeCharge()) {
cumulative = cumulative.plus(loanCharge.amount());
}
}
return cumulative;
}
private Money cumulativePenaltyChargesDueWithin(
final LocalDate periodStart,
final LocalDate periodEnd,
final Set<LoanCharge> loanCharges,
final MonetaryCurrency monetaryCurrency) {
Money cumulative = Money.zero(monetaryCurrency);
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueForCollectionBetween(periodStart, periodEnd) && loanCharge.isPenaltyCharge()) {
cumulative = cumulative.plus(loanCharge.amount());
}
}
return cumulative;
}
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
.calculateRepaymentPeriodAsAFractionOfDays(loanScheduleInfo.getRepaymentPeriodFrequencyType(),
loanScheduleInfo.getRepayEvery(), interestCalculatedFrom, scheduledDates,
idealDisbursementDateBasedOnFirstRepaymentDate);
BigDecimal chargesDueAtTimeOfDisbursement = BigDecimal.ZERO;
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueAtDisbursement()) {
chargesDueAtTimeOfDisbursement = chargesDueAtTimeOfDisbursement.add(loanCharge.amount());
}
}
BigDecimal cumulativeChargesToDate = chargesDueAtTimeOfDisbursement;
// create entries of disbursement period on loan schedule
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursementDate,
principalDisbursed.getAmount(), chargesDueAtTimeOfDisbursement, false);
periods.add(disbursementPeriod);
int loanTermInDays = Integer.valueOf(0);
BigDecimal cumulativePrincipalDisbursed = loanScheduleInfo.getPrincipal().getAmount();
BigDecimal cumulativePrincipalDue = BigDecimal.ZERO;
BigDecimal cumulativeInterestExpected = BigDecimal.ZERO;
BigDecimal totalExpectedRepayment = chargesDueAtTimeOfDisbursement;
LocalDate startDate = disbursementDate;
int periodNumber = 1;
for (LocalDate scheduledDueDate : scheduledDates) {
// number of days from startDate to this scheduledDate
int daysInPeriod = Days.daysBetween(startDate, scheduledDueDate).getDays();
Money interestForInstallment = this.periodicInterestRateCalculator.calculateInterestOn(outstandingBalance,
periodInterestRateForRepaymentPeriod, daysInPeriod, loanScheduleInfo);
Money principalForInstallment = this.periodicInterestRateCalculator.calculatePrincipalOn(totalDuePerInstallment,
interestForInstallment, loanScheduleInfo);
if (interestCalculationGraceOnRepaymentPeriodFraction >= Integer.valueOf(1).doubleValue()) {
Money graceOnInterestForRepaymentPeriod = interestForInstallment;
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod);
interestCalculationGraceOnRepaymentPeriodFraction = interestCalculationGraceOnRepaymentPeriodFraction
- Integer.valueOf(1).doubleValue();
} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25")
&& interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) {
Money graceOnInterestForRepaymentPeriod = interestForInstallment
.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
interestForInstallment = interestForInstallment.minus(graceOnInterestForRepaymentPeriod);
totalInterestDue = totalInterestDue.minus(graceOnInterestForRepaymentPeriod);
interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf("0");
}
totalPrincipal = totalPrincipal.plus(principalForInstallment);
totalInterest = totalInterest.plus(interestForInstallment);
if (periodNumber == loanScheduleInfo.getNumberOfRepayments()) {
Money principalDifference = totalPrincipal.minus(loanScheduleInfo.getPrincipal());
if (principalDifference.isLessThanZero()) {
principalForInstallment = principalForInstallment.plus(principalDifference.abs());
} else if (principalDifference.isGreaterThanZero()) {
principalForInstallment = principalForInstallment.minus(principalDifference.abs());
}
final Money interestDifference = totalInterest.minus(totalInterestDue);
if (interestDifference.isLessThanZero()) {
interestForInstallment = interestForInstallment.plus(interestDifference.abs());
} else if (interestDifference.isGreaterThanZero()) {
interestForInstallment = interestForInstallment.minus(interestDifference.abs());
}
}
outstandingBalance = outstandingBalance.minus(principalForInstallment);
final Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(startDate, scheduledDueDate, loanCharges, monetaryCurrency);
final Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(startDate, scheduledDueDate, loanCharges,
monetaryCurrency);
final Money totalInstallmentDue = principalForInstallment.plus(interestForInstallment).plus(feeChargesForInstallment)
.plus(penaltyChargesForInstallment);
cumulativeChargesToDate = cumulativeChargesToDate.add(feeChargesForInstallment.getAmount());
LoanSchedulePeriodData installment = LoanSchedulePeriodData.repaymentOnlyPeriod(periodNumber, startDate, scheduledDueDate,
principalForInstallment.getAmount(), outstandingBalance.getAmount(), interestForInstallment.getAmount(),
feeChargesForInstallment.getAmount(), penaltyChargesForInstallment.getAmount(), totalInstallmentDue.getAmount());
periods.add(installment);
// handle cumulative fields
loanTermInDays += daysInPeriod;
cumulativePrincipalDue = cumulativePrincipalDue.add(principalForInstallment.getAmount());
cumulativeInterestExpected = cumulativeInterestExpected.add(interestForInstallment.getAmount());
totalExpectedRepayment = totalExpectedRepayment.add(totalInstallmentDue.getAmount());
startDate = scheduledDueDate;
periodNumber++;
}
final BigDecimal cumulativePrincipalOutstanding = cumulativePrincipalDisbursed.subtract(cumulativePrincipalDue);
CurrencyData currencyData = new CurrencyData(currency.getCode(), currency.getName(), monetaryCurrency.getDigitsAfterDecimal(),
currency.getDisplaySymbol(), currency.getNameCode());
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
}
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
final MonetaryCurrency monetaryCurrency) {
Money cumulative = Money.zero(monetaryCurrency);
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueForCollectionBetween(periodStart, periodEnd) && loanCharge.isFeeCharge()) {
cumulative = cumulative.plus(loanCharge.amount());
}
}
return cumulative;
}
private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd,
final Set<LoanCharge> loanCharges, final MonetaryCurrency monetaryCurrency) {
Money cumulative = Money.zero(monetaryCurrency);
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueForCollectionBetween(periodStart, periodEnd) && loanCharge.isPenaltyCharge()) {
cumulative = cumulative.plus(loanCharge.amount());
}
}
return cumulative;
}
}
@@ -103,11 +103,15 @@ public class FlatMethodLoanScheduleGenerator implements LoanScheduleGenerator {
outstandingBalance = outstandingBalance.minus(principalPerInstallment);
Money feeChargesForInstallment = Money.zero(monetaryCurrency);
Money penaltyChargesForInstallment = Money.zero(monetaryCurrency);
final Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(startDate, scheduledDueDate, loanCharges, monetaryCurrency);
final Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(startDate, scheduledDueDate, loanCharges,
monetaryCurrency);
Money totalInstallmentDue = principalPerInstallment.plus(interestPerInstallment).plus(feeChargesForInstallment)
final Money totalInstallmentDue = principalPerInstallment //
.plus(interestPerInstallment) //
.plus(feeChargesForInstallment) //
.plus(penaltyChargesForInstallment);
cumulativeChargesToDate = cumulativeChargesToDate.add(feeChargesForInstallment.getAmount()).add(
penaltyChargesForInstallment.getAmount());
@@ -135,4 +139,32 @@ public class FlatMethodLoanScheduleGenerator implements LoanScheduleGenerator {
return new LoanScheduleData(currencyData, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue,
cumulativePrincipalOutstanding, cumulativeInterestExpected, cumulativeChargesToDate, totalExpectedRepayment);
}
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
final MonetaryCurrency monetaryCurrency) {
Money cumulative = Money.zero(monetaryCurrency);
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueForCollectionBetween(periodStart, periodEnd) && loanCharge.isFeeCharge()) {
cumulative = cumulative.plus(loanCharge.amount());
}
}
return cumulative;
}
private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd,
final Set<LoanCharge> loanCharges, final MonetaryCurrency monetaryCurrency) {
Money cumulative = Money.zero(monetaryCurrency);
for (LoanCharge loanCharge : loanCharges) {
if (loanCharge.isDueForCollectionBetween(periodStart, periodEnd) && loanCharge.isPenaltyCharge()) {
cumulative = cumulative.plus(loanCharge.amount());
}
}
return cumulative;
}
}