diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java index 6c3f1e37d..df8a4634c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarHelper.java @@ -312,30 +312,41 @@ public class CalendarHelper { public static LocalDate getNewRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate, final LocalDate oldRepaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays){ final Recur recur = CalendarHelper.getICalRecur(recurringRule); if (recur == null) { return null; } - if(isValidRecurringDate(recur, seedDate, oldRepaymentDate)){ return oldRepaymentDate; } - /* Recurring dates should follow loanRepaymentInterval. - e.g. The weekly meeting will have interval of 1, if the loan product with fortnightly frequency will have interval of 2, - to generate right set of meeting dates reset interval same as loan repayment interval. - */ - recur.setInterval(loanRepaymentInterval); - - /*Recurring dates should follow loanRepayment frequency. - //e.g. daily meeting frequency should support all loan products with any type of frequency. - to generate right set of meeting dates reset frequency same as loan repayment frequency. - */ - if(recur.getFrequency().equals(Recur.DAILY)){ - recur.setFrequency(frequency); - } - - LocalDate newRepaymentDate = getNextRecurringDate(recur, seedDate, oldRepaymentDate); - LocalDate nextRepaymentDate = getNextRecurringDate(recur, seedDate, newRepaymentDate); - - newRepaymentDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(newRepaymentDate, nextRepaymentDate, workingDays); - - return newRepaymentDate; + return getNextRepaymentMeetingDate(recurringRule, seedDate, oldRepaymentDate, loanRepaymentInterval, frequency, workingDays); + } + + public static LocalDate getNextRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate, final LocalDate repaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays){ + + final Recur recur = CalendarHelper.getICalRecur(recurringRule); + if (recur == null) { return null; } + LocalDate tmpDate = repaymentDate; + if(isValidRecurringDate(recur, seedDate, repaymentDate)){ + tmpDate = repaymentDate.plusDays(1); + } + /* Recurring dates should follow loanRepaymentInterval. + * + e.g. The weekly meeting will have interval of 1, if the loan product with fortnightly frequency will have interval of 2, + to generate right set of meeting dates reset interval same as loan repayment interval. + */ + recur.setInterval(loanRepaymentInterval); + + /*Recurring dates should follow loanRepayment frequency. + //e.g. daily meeting frequency should support all loan products with any type of frequency. + to generate right set of meeting dates reset frequency same as loan repayment frequency. + */ + if(recur.getFrequency().equals(Recur.DAILY)){ + recur.setFrequency(frequency); + } + + LocalDate newRepaymentDate = getNextRecurringDate(recur, seedDate, tmpDate); + LocalDate nextRepaymentDate = getNextRecurringDate(recur, seedDate, newRepaymentDate); + + newRepaymentDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(newRepaymentDate, nextRepaymentDate, workingDays); + + return newRepaymentDate; } public static boolean isFrequencySame(final String oldRRule, final String newRRule) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index 863813f9f..fc69b1dd5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -2395,23 +2395,33 @@ public class Loan extends AbstractPersistable { public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule, final boolean isHolidayEnabled, final List holidays, final WorkingDays workingDays) { - //update repayment dates of repayment schedule installaments - LocalDate tmpFromDate = this.getDisbursementDate();//first repayment's from date is same as disbursement date. + + LocalDate tmpFromDate = this.getDisbursementDate(); + final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType(); + final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery(); + final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType); + LocalDate newRepaymentDate = null; for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) { final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate(); // FIXME: AA this won't update repayment dates before current date. if (oldDueDate.isAfter(meetingStartDate) && oldDueDate.isAfter(DateUtils.getLocalDateOfTenant())) { - final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType(); - final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType); - final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery(); - // reset repayment date with new meeting date - newRepaymentDate = CalendarHelper.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate, loanRepaymentInterval, frequency, workingDays); - if(isHolidayEnabled){ + newRepaymentDate = CalendarHelper.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate, + loanRepaymentInterval, frequency, workingDays); + + final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType, + loanRepaymentInterval, tmpFromDate); + + if (newRepaymentDate.isAfter(maxDateLimitForNewRepayment)) { + newRepaymentDate = CalendarHelper.getNextRepaymentMeetingDate(recuringRule, meetingStartDate, tmpFromDate, + loanRepaymentInterval, frequency, workingDays); + } + + if (isHolidayEnabled) { newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays); } - + loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate); // reset from date to get actual daysInPeriod loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate); @@ -2423,6 +2433,29 @@ public class Loan extends AbstractPersistable { } } + private LocalDate getMaxDateLimitForNewRepayment(final PeriodFrequencyType periodFrequencyType, final Integer loanRepaymentInterval, + final LocalDate startDate) { + LocalDate dueRepaymentPeriodDate = startDate; + final Integer repaidEvery = 2*loanRepaymentInterval; + switch (periodFrequencyType) { + case DAYS: + dueRepaymentPeriodDate = startDate.plusDays(repaidEvery); + break; + case WEEKS: + dueRepaymentPeriodDate = startDate.plusWeeks(repaidEvery); + break; + case MONTHS: + dueRepaymentPeriodDate = startDate.plusMonths(repaidEvery); + break; + case YEARS: + dueRepaymentPeriodDate = startDate.plusYears(repaidEvery); + break; + case INVALID: + break; + } + return dueRepaymentPeriodDate.minusDays(1);//get 2n-1 range date from startDate + } + public void applyHolidayToRepaymentScheduleDates(final Holiday holiday) { // first repayment's from date is same as disbursement date. LocalDate tmpFromDate = this.getDisbursementDate();