Reschedule repayment on holidays+extend term
This commit is contained in:
+3
-3
@@ -36,14 +36,14 @@ public class WorkingDaysApiConstants {
|
|||||||
public static final String rescheduleRepaymentTemplate = "rescheduleRepaymentTemplate";
|
public static final String rescheduleRepaymentTemplate = "rescheduleRepaymentTemplate";
|
||||||
public static final String localeParamName = "locale";
|
public static final String localeParamName = "locale";
|
||||||
public static final String extendTermForDailyRepayments = "extendTermForDailyRepayments";
|
public static final String extendTermForDailyRepayments = "extendTermForDailyRepayments";
|
||||||
|
public static final String extendTermForRepaymentsOnHolidays = "extendTermForRepaymentsOnHolidays";
|
||||||
|
|
||||||
|
|
||||||
public static final Set<String> WORKING_DAYS_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS =new HashSet<>(Arrays.asList(
|
public static final Set<String> WORKING_DAYS_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS =new HashSet<>(Arrays.asList(
|
||||||
recurrence,repayment_rescheduling_enum,localeParamName,extendTermForDailyRepayments
|
recurrence,repayment_rescheduling_enum,localeParamName,extendTermForDailyRepayments,extendTermForRepaymentsOnHolidays
|
||||||
));
|
));
|
||||||
public static final Set<String> WORKING_DAYS_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
|
public static final Set<String> WORKING_DAYS_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
|
||||||
recurrence,repayment_rescheduling_enum,extendTermForDailyRepayments
|
recurrence,repayment_rescheduling_enum,extendTermForDailyRepayments,extendTermForRepaymentsOnHolidays
|
||||||
));
|
));
|
||||||
|
|
||||||
public static final Set<String> WORKING_DAYS_TEMPLATE_PARAMETERS = new HashSet<>(Arrays.asList(rescheduleRepaymentTemplate));
|
public static final Set<String> WORKING_DAYS_TEMPLATE_PARAMETERS = new HashSet<>(Arrays.asList(rescheduleRepaymentTemplate));
|
||||||
|
|||||||
+4
-2
@@ -67,14 +67,16 @@ public class WorkingDayValidator {
|
|||||||
|
|
||||||
final Boolean extendTermForDailyRepayments = this.fromApiJsonHelper.extractBooleanNamed("extendTermForDailyRepayments", element);
|
final Boolean extendTermForDailyRepayments = this.fromApiJsonHelper.extractBooleanNamed("extendTermForDailyRepayments", element);
|
||||||
baseDataValidator.reset().parameter(WorkingDaysApiConstants.extendTermForDailyRepayments).value(extendTermForDailyRepayments).ignoreIfNull().validateForBooleanValue();
|
baseDataValidator.reset().parameter(WorkingDaysApiConstants.extendTermForDailyRepayments).value(extendTermForDailyRepayments).ignoreIfNull().validateForBooleanValue();
|
||||||
|
|
||||||
|
final Boolean extendTermForRepaymentsOnHolidays = this.fromApiJsonHelper.extractBooleanNamed("extendTermForRepaymentsOnHolidays", element);
|
||||||
|
baseDataValidator.reset().parameter(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays).value(extendTermForRepaymentsOnHolidays).ignoreIfNull().validateForBooleanValue();
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||||
if (!dataValidationErrors.isEmpty()) {
|
if (!dataValidationErrors.isEmpty()) {
|
||||||
//
|
|
||||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-3
@@ -31,28 +31,33 @@ public class WorkingDaysData {
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final EnumOptionData repaymentRescheduleType;
|
private final EnumOptionData repaymentRescheduleType;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final Boolean extendTermForDailyRepayments;
|
private final Boolean extendTermForDailyRepayments;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Boolean extendTermForRepaymentsOnHolidays;
|
||||||
|
|
||||||
// template date
|
// template date
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final Collection<EnumOptionData> repaymentRescheduleOptions;
|
private final Collection<EnumOptionData> repaymentRescheduleOptions;
|
||||||
|
|
||||||
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType, Boolean extendTermForDailyRepayments) {
|
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType, Boolean extendTermForDailyRepayments, Boolean extendTermForRepaymentsOnHolidays) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.recurrence = recurrence;
|
this.recurrence = recurrence;
|
||||||
this.repaymentRescheduleType = repaymentRescheduleType;
|
this.repaymentRescheduleType = repaymentRescheduleType;
|
||||||
this.repaymentRescheduleOptions = null;
|
this.repaymentRescheduleOptions = null;
|
||||||
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
||||||
|
this.extendTermForRepaymentsOnHolidays = extendTermForRepaymentsOnHolidays;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType,
|
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType,
|
||||||
Collection<EnumOptionData> repaymentRescheduleOptions, Boolean extendTermForDailyRepayments) {
|
Collection<EnumOptionData> repaymentRescheduleOptions, Boolean extendTermForDailyRepayments, Boolean extendTermForRepaymentsOnHolidays) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.recurrence = recurrence;
|
this.recurrence = recurrence;
|
||||||
this.repaymentRescheduleType = repaymentRescheduleType;
|
this.repaymentRescheduleType = repaymentRescheduleType;
|
||||||
this.repaymentRescheduleOptions = repaymentRescheduleOptions;
|
this.repaymentRescheduleOptions = repaymentRescheduleOptions;
|
||||||
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
||||||
|
this.extendTermForRepaymentsOnHolidays = extendTermForRepaymentsOnHolidays;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-1
@@ -41,15 +41,19 @@ public class WorkingDays extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
@Column(name = "extend_term_daily_repayments", nullable = false)
|
@Column(name = "extend_term_daily_repayments", nullable = false)
|
||||||
private Boolean extendTermForDailyRepayments;
|
private Boolean extendTermForDailyRepayments;
|
||||||
|
|
||||||
|
@Column(name = "extend_term_holiday_repayment", nullable = false)
|
||||||
|
private Boolean extendTermForRepaymentsOnHolidays;
|
||||||
|
|
||||||
protected WorkingDays() {
|
protected WorkingDays() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WorkingDays(final String recurrence, final Integer repaymentReschedulingType, final Boolean extendTermForDailyRepayments ) {
|
protected WorkingDays(final String recurrence, final Integer repaymentReschedulingType, final Boolean extendTermForDailyRepayments, final Boolean extendTermForRepaymentsOnHolidays) {
|
||||||
this.recurrence = recurrence;
|
this.recurrence = recurrence;
|
||||||
this.repaymentReschedulingType = repaymentReschedulingType;
|
this.repaymentReschedulingType = repaymentReschedulingType;
|
||||||
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
||||||
|
this.extendTermForRepaymentsOnHolidays = extendTermForRepaymentsOnHolidays;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,6 +78,8 @@ public class WorkingDays extends AbstractPersistable<Long> {
|
|||||||
return this.extendTermForDailyRepayments;
|
return this.extendTermForDailyRepayments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getExtendTermForRepaymentsOnHolidays() { return this.extendTermForRepaymentsOnHolidays; }
|
||||||
|
|
||||||
public Map<String, Object> update(final JsonCommand command) {
|
public Map<String, Object> update(final JsonCommand command) {
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
|
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
|
||||||
|
|
||||||
@@ -96,6 +102,13 @@ public class WorkingDays extends AbstractPersistable<Long> {
|
|||||||
actualChanges.put(WorkingDaysApiConstants.extendTermForDailyRepayments, newValue);
|
actualChanges.put(WorkingDaysApiConstants.extendTermForDailyRepayments, newValue);
|
||||||
this.extendTermForDailyRepayments = newValue;
|
this.extendTermForDailyRepayments = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command.isChangeInBooleanParameterNamed(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays, this.extendTermForRepaymentsOnHolidays)) {
|
||||||
|
final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays);
|
||||||
|
actualChanges.put(WorkingDaysApiConstants.extendTermForRepaymentsOnHolidays, newValue);
|
||||||
|
this.extendTermForRepaymentsOnHolidays = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -53,7 +53,8 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
|
|||||||
public WorkingDaysMapper() {
|
public WorkingDaysMapper() {
|
||||||
final StringBuilder sqlBuilder = new StringBuilder(100);
|
final StringBuilder sqlBuilder = new StringBuilder(100);
|
||||||
sqlBuilder.append("w.id as id,w.recurrence as recurrence,w.repayment_rescheduling_enum as status_enum,");
|
sqlBuilder.append("w.id as id,w.recurrence as recurrence,w.repayment_rescheduling_enum as status_enum,");
|
||||||
sqlBuilder.append("w.extend_term_daily_repayments as extendTermForDailyRepayments ");
|
sqlBuilder.append("w.extend_term_daily_repayments as extendTermForDailyRepayments,");
|
||||||
|
sqlBuilder.append("w.extend_term_holiday_repayment as extendTermForRepaymentsOnHolidays ");
|
||||||
sqlBuilder.append("from m_working_days w");
|
sqlBuilder.append("from m_working_days w");
|
||||||
|
|
||||||
this.schema = sqlBuilder.toString();
|
this.schema = sqlBuilder.toString();
|
||||||
@@ -70,8 +71,9 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
|
|||||||
final Integer statusEnum = JdbcSupport.getInteger(rs, "status_enum");
|
final Integer statusEnum = JdbcSupport.getInteger(rs, "status_enum");
|
||||||
final EnumOptionData status = WorkingDaysEnumerations.workingDaysStatusType(statusEnum);
|
final EnumOptionData status = WorkingDaysEnumerations.workingDaysStatusType(statusEnum);
|
||||||
final Boolean extendTermForDailyRepayments = rs.getBoolean("extendTermForDailyRepayments");
|
final Boolean extendTermForDailyRepayments = rs.getBoolean("extendTermForDailyRepayments");
|
||||||
|
final Boolean extendTermForRepaymentsOnHolidays = rs.getBoolean("extendTermForRepaymentsOnHolidays");
|
||||||
|
|
||||||
return new WorkingDaysData(id, recurrence, status,extendTermForDailyRepayments);
|
return new WorkingDaysData(id, recurrence, status, extendTermForDailyRepayments, extendTermForRepaymentsOnHolidays);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +95,6 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
|
|||||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY),
|
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY),
|
||||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY),
|
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY),
|
||||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY));
|
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY));
|
||||||
return new WorkingDaysData(null, null, null, repaymentRescheduleOptions, null);
|
return new WorkingDaysData(null, null, null, repaymentRescheduleOptions, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-9
@@ -18,9 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
|
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||||
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
|
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
|
||||||
import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType;
|
import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType;
|
||||||
|
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
||||||
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
@@ -29,11 +30,10 @@ import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
|||||||
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.joda.time.Days;
|
import org.joda.time.*;
|
||||||
import org.joda.time.LocalDate;
|
|
||||||
import org.joda.time.Months;
|
import java.util.ArrayList;
|
||||||
import org.joda.time.Weeks;
|
import java.util.List;
|
||||||
import org.joda.time.Years;
|
|
||||||
|
|
||||||
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
||||||
|
|
||||||
@@ -57,10 +57,10 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
boolean isFirstRepayment, final HolidayDetailDTO holidayDetailDTO) {
|
boolean isFirstRepayment, final HolidayDetailDTO holidayDetailDTO) {
|
||||||
final LocalDate firstRepaymentPeriodDate = loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate();
|
final LocalDate firstRepaymentPeriodDate = loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate();
|
||||||
LocalDate dueRepaymentPeriodDate = null;
|
LocalDate dueRepaymentPeriodDate = null;
|
||||||
|
Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
|
||||||
if (isFirstRepayment && firstRepaymentPeriodDate != null) {
|
if (isFirstRepayment && firstRepaymentPeriodDate != null) {
|
||||||
dueRepaymentPeriodDate = firstRepaymentPeriodDate;
|
dueRepaymentPeriodDate = firstRepaymentPeriodDate;
|
||||||
} else {
|
} else {
|
||||||
Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
|
|
||||||
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
||||||
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, null,
|
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, null,
|
||||||
null);
|
null);
|
||||||
@@ -96,10 +96,33 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
loanApplicationTerms.getNumberOfdays());
|
loanApplicationTerms.getNumberOfdays());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (currentCalendar == null && holidayDetailDTO.getWorkingDays().getExtendTermForRepaymentsOnHolidays()) {
|
||||||
|
boolean repaymentDateIsOnHoliday = false;
|
||||||
|
// compile the list of holidays into Intervals to see if this date lands on a holiday
|
||||||
|
final List<Interval> holidayInterval = new ArrayList<>();
|
||||||
|
for (Holiday holiday : holidayDetailDTO.getHolidays()) {
|
||||||
|
holidayInterval.add(new Interval(
|
||||||
|
holiday.getFromDateLocalDate().toDateTimeAtStartOfDay(),
|
||||||
|
holiday.getToDateLocalDate().toDateTime(LocalTime.parse("23:59:59"))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
while (intervalListContainsDate(holidayInterval, dueRepaymentPeriodDate)) {
|
||||||
|
LocalDate previousDate = dueRepaymentPeriodDate;
|
||||||
|
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
||||||
|
loanApplicationTerms.getRepaymentEvery(), dueRepaymentPeriodDate, loanApplicationTerms.getNthDay(),
|
||||||
|
loanApplicationTerms.getWeekDayType());
|
||||||
|
}
|
||||||
|
}
|
||||||
return dueRepaymentPeriodDate;
|
return dueRepaymentPeriodDate;
|
||||||
}
|
}
|
||||||
|
private boolean intervalListContainsDate(List<Interval> intervalList, LocalDate date) {
|
||||||
|
for (Interval interval : intervalList) {
|
||||||
|
if (interval.contains(date.toDateTime(LocalTime.parse("11:59:59")))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public LocalDate adjustRepaymentDate(final LocalDate dueRepaymentPeriodDate, final LoanApplicationTerms loanApplicationTerms,
|
public LocalDate adjustRepaymentDate(final LocalDate dueRepaymentPeriodDate, final LoanApplicationTerms loanApplicationTerms,
|
||||||
final HolidayDetailDTO holidayDetailDTO) {
|
final HolidayDetailDTO holidayDetailDTO) {
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
--
|
||||||
|
-- Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
-- or more contributor license agreements. See the NOTICE file
|
||||||
|
-- distributed with this work for additional information
|
||||||
|
-- regarding copyright ownership. The ASF licenses this file
|
||||||
|
-- to you under the Apache License, Version 2.0 (the
|
||||||
|
-- "License"); you may not use this file except in compliance
|
||||||
|
-- with the License. You may obtain a copy of the License at
|
||||||
|
--
|
||||||
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
--
|
||||||
|
-- Unless required by applicable law or agreed to in writing,
|
||||||
|
-- software distributed under the License is distributed on an
|
||||||
|
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
-- KIND, either express or implied. See the License for the
|
||||||
|
-- specific language governing permissions and limitations
|
||||||
|
-- under the License.
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE m_working_days ADD extend_term_holiday_repayment BOOLEAN NOT NULL DEFAULT 0;
|
||||||
Reference in New Issue
Block a user