Repository: incubator-fineract Updated Branches: refs/heads/develop b4a43e6e9 -> 0b81e8023
[MIFOSX-2652] Correcting repayment schedule for the loans with variable installments enabled Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/0b81e802 Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/0b81e802 Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/0b81e802 Branch: refs/heads/develop Commit: 0b81e8023305e9cbd06f2b0c3c6335b01f441077 Parents: b4a43e6 Author: Vishwa <vishwan...@confluxtechnologies.com> Authored: Fri May 13 12:37:53 2016 +0530 Committer: Vishwa <vishwan...@confluxtechnologies.com> Committed: Fri May 13 12:37:53 2016 +0530 ---------------------------------------------------------------------- .../data/LoanTermVariationsDataWrapper.java | 5 + .../domain/AbstractLoanScheduleGenerator.java | 99 +++++++++++++++++--- ...LoanApplicationCommandFromApiJsonHelper.java | 3 +- 3 files changed, 92 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/0b81e802/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java index 510dd1d..65730e7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java @@ -120,4 +120,9 @@ public class LoanTermVariationsDataWrapper { return data; } + public boolean hasExceptionVariation(final LocalDate date, ListIterator<LoanTermVariationsData> exceptionDataListIterator) { + ListIterator<LoanTermVariationsData> iterator = exceptionDataListIterator; + return hasNext(date, iterator); + } + } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/0b81e802/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java index 474b852..080689e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; @@ -957,6 +958,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener boolean skipPeriod = false; boolean recalculateAmounts = false; LocalDate modifiedScheduledDueDate = scheduledDueDate; + ArrayList<LoanTermVariationsData> variationsData = null; // due date changes should be applied only for that dueDate if (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(scheduledDueDate)) { @@ -1019,7 +1021,48 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener } } - LoanTermVariationParams termVariationParams = new LoanTermVariationParams(skipPeriod, recalculateAmounts, modifiedScheduledDueDate); + LoanTermVariationParams termVariationParams = new LoanTermVariationParams(skipPeriod, recalculateAmounts, modifiedScheduledDueDate, + variationsData); + return termVariationParams; + } + + /** + * @param loanApplicationTerms + * @param scheduledDueDate + * @param exceptionDataListIterator + * @return + */ + private LoanTermVariationParams applyExceptionLoanTermVariations(final LoanApplicationTerms loanApplicationTerms, + final LocalDate scheduledDueDate, final ListIterator<LoanTermVariationsData> exceptionDataListIterator) { + boolean skipPeriod = false; + boolean recalculateAmounts = false; + LocalDate modifiedScheduledDueDate = scheduledDueDate; + ArrayList<LoanTermVariationsData> variationsData = new ArrayList<>(); + + while (loanApplicationTerms.getLoanTermVariations().hasExceptionVariation(modifiedScheduledDueDate, exceptionDataListIterator)) { + LoanTermVariationsData loanTermVariationsData = exceptionDataListIterator.next(); + if (loanTermVariationsData.isProcessed()) { + continue; + } + switch (loanTermVariationsData.getTermVariationType()) { + case INSERT_INSTALLMENT: + modifiedScheduledDueDate = loanTermVariationsData.getTermApplicableFrom(); + variationsData.add(loanTermVariationsData) ; + break; + case DELETE_INSTALLMENT: + if (loanTermVariationsData.getTermApplicableFrom().isEqual(modifiedScheduledDueDate)) { + skipPeriod = true; + variationsData.add(loanTermVariationsData) ; + } + + break; + default: + break; + + } + } + LoanTermVariationParams termVariationParams = new LoanTermVariationParams(skipPeriod, recalculateAmounts, modifiedScheduledDueDate, + variationsData); return termVariationParams; } @@ -2276,6 +2319,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener } int loanTermInDays = 0; + List<LoanTermVariationsData> exceptionDataList = loanApplicationTerms.getLoanTermVariations().getExceptionData(); + final ListIterator<LoanTermVariationsData> exceptionDataListIterator = exceptionDataList.listIterator(); + LoanTermVariationParams loanTermVariationParams = null; + // Block process the installment and creates the period if it falls // before reschedule from date // This will create the recalculation details by applying the @@ -2289,23 +2336,42 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener break; } LocalDate previousRepaymentDate = actualRepaymentDate; - actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms, - isFirstRepayment, holidayDetailDTO); - isFirstRepayment = false; - lastInstallmentDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms, - holidayDetailDTO); + ArrayList<LoanTermVariationsData> dueDateVariationsDataList = new ArrayList<>(); + + // check for date changes + while (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(lastInstallmentDate)) { + LoanTermVariationsData variation = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation(); + if (!variation.isSpecificToInstallment()) { + actualRepaymentDate = variation.getDateValue(); + } + dueDateVariationsDataList.add(variation); + } + + do { + actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, + loanApplicationTerms, isFirstRepayment, holidayDetailDTO); + isFirstRepayment = false; + lastInstallmentDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms, + holidayDetailDTO); + loanTermVariationParams = applyExceptionLoanTermVariations(loanApplicationTerms, lastInstallmentDate, + exceptionDataListIterator); + } while (loanTermVariationParams != null && loanTermVariationParams.isSkipPeriod()); + if (!lastInstallmentDate.isBefore(rescheduleFrom)) { actualRepaymentDate = previousRepaymentDate; break; } periodNumber++; - // check for date changes - while (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(lastInstallmentDate)) { - LoanTermVariationsData variation = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation(); - if (!variation.isSpecificToInstallment()) { - actualRepaymentDate = variation.getDateValue(); + + for (LoanTermVariationsData dueDateVariation : dueDateVariationsDataList) { + dueDateVariation.setProcessed(true); + } + + if (loanTermVariationParams != null && loanTermVariationParams.isSkipPeriod()) { + ArrayList<LoanTermVariationsData> variationsDataList = loanTermVariationParams.getVariationsDataList(); + for (LoanTermVariationsData variationsData : variationsDataList) { + variationsData.setProcessed(true); } - variation.setProcessed(true); } } @@ -2690,11 +2756,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener private final boolean skipPeriod; private final boolean recalculateAmounts; private final LocalDate scheduledDueDate; + private final ArrayList<LoanTermVariationsData> variationsData; - public LoanTermVariationParams(final boolean skipPeriod, final boolean recalculateAmounts, final LocalDate scheduledDueDate) { + public LoanTermVariationParams(final boolean skipPeriod, final boolean recalculateAmounts, final LocalDate scheduledDueDate, + final ArrayList<LoanTermVariationsData> variationsData) { this.skipPeriod = skipPeriod; this.recalculateAmounts = recalculateAmounts; this.scheduledDueDate = scheduledDueDate; + this.variationsData = variationsData; } public boolean isSkipPeriod() { @@ -2709,6 +2778,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener return this.scheduledDueDate; } + public ArrayList<LoanTermVariationsData> getVariationsDataList() { + return this.variationsData; + } + } private final class ScheduleCurrentPeriodParams { http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/0b81e802/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java index 0eaf4af..f2dd3d9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java @@ -762,8 +762,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { repaymentsStartingFromDateParameterName, element); baseDataValidator.reset().parameter(repaymentsStartingFromDateParameterName).value(repaymentsStartingFromDate).ignoreIfNull(); if (!existingLoanApplication.getLoanTermVariations().isEmpty()) { - baseDataValidator.reset().parameter(repaymentsStartingFromDateParameterName).value(repaymentsStartingFromDate) - .failWithCode("invalid.due.to.variable.installments"); + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("cannot.modify.application.due.to.variable.installments"); } }