Repository: fineract Updated Branches: refs/heads/develop 0373ce467 -> c3a602ced
holiday changes for next repayment date Project: http://git-wip-us.apache.org/repos/asf/fineract/repo Commit: http://git-wip-us.apache.org/repos/asf/fineract/commit/b9017e2b Tree: http://git-wip-us.apache.org/repos/asf/fineract/tree/b9017e2b Diff: http://git-wip-us.apache.org/repos/asf/fineract/diff/b9017e2b Branch: refs/heads/develop Commit: b9017e2be2aa5e697c103c74a8b754a4c6bf19f5 Parents: 6946f1c Author: nazeer shaik <nazeer.sh...@confluxtechnologies.com> Authored: Thu Jul 20 17:10:11 2017 +0530 Committer: nazeer shaik <nazeer.sh...@confluxtechnologies.com> Committed: Thu Jul 20 17:10:11 2017 +0530 ---------------------------------------------------------------------- .../holiday/api/HolidayApiConstants.java | 1 + .../holiday/api/HolidaysApiResource.java | 9 + .../organisation/holiday/data/HolidayData.java | 4 +- .../holiday/data/HolidayDataValidator.java | 22 ++- .../organisation/holiday/domain/Holiday.java | 36 +++- .../holiday/domain/RescheduleType.java | 64 +++++++ .../holiday/service/HolidayEnumerations.java | 26 +++ .../service/HolidayReadPlatformService.java | 4 + .../service/HolidayReadPlatformServiceImpl.java | 16 +- .../holiday/service/HolidayUtil.java | 17 ++ ...ayWritePlatformServiceJpaRepositoryImpl.java | 68 ++++--- .../data/AdjustedDateDetailsDTO.java | 76 ++++++++ .../domain/RepaymentRescheduleType.java | 7 +- .../workingdays/service/WorkingDaysUtil.java | 12 ++ .../calendar/service/CalendarUtils.java | 108 +++++++++++ .../domain/AbstractLoanScheduleGenerator.java | 55 ++---- .../domain/DefaultScheduledDateGenerator.java | 179 ++++++++++++------- .../domain/LoanApplicationTerms.java | 6 +- .../domain/ScheduledDateGenerator.java | 9 +- ...oanReschedulePreviewPlatformServiceImpl.java | 4 +- ...scheduleRequestWritePlatformServiceImpl.java | 4 +- ...anWritePlatformServiceJpaRepositoryImpl.java | 2 +- .../core_db/V331__holiday_schema_changes.sql | 23 +++ 23 files changed, 594 insertions(+), 158 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidayApiConstants.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidayApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidayApiConstants.java index 27fa538..dc019a5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidayApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidayApiConstants.java @@ -41,6 +41,7 @@ public class HolidayApiConstants { public static final String repaymentsRescheduledToParamName = "repaymentsRescheduledTo"; public static final String processed = "processed"; public static final String status = "status"; + public static final String reschedulingType = "reschedulingType"; protected static final Set<String> HOLIDAY_RESPONSE_DATA_PARAMETERS = new HashSet<>( Arrays.asList(idParamName, nameParamName, fromDateParamName, descriptionParamName, toDateParamName, http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java index 061f225..e8b22d3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java @@ -180,4 +180,13 @@ public class HolidaysApiResource { final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, holidays, HOLIDAY_RESPONSE_DATA_PARAMETERS); } + + @GET + @Path("/template") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public String retrieveRepaymentScheduleUpdationTyeOptions(@Context final UriInfo uriInfo){ + this.context.authenticatedUser().validateHasReadPermission(HOLIDAY_RESOURCE_NAME); + return this.toApiJsonSerializer.serialize(this.holidayReadPlatformService.retrieveRepaymentScheduleUpdationTyeOptions()); + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayData.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayData.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayData.java index 70f9839..12c2d0a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayData.java @@ -39,9 +39,10 @@ public class HolidayData { private final Long officeId; @SuppressWarnings("unused") private final EnumOptionData status; + private final Integer reschedulingType; public HolidayData(final Long id, final String name, final String description, final LocalDate fromDate, final LocalDate toDate, - final LocalDate repaymentsRescheduledTo, final EnumOptionData status) { + final LocalDate repaymentsRescheduledTo, final EnumOptionData status, final Integer reschedulingType) { this.id = id; this.name = name; this.description = description; @@ -50,5 +51,6 @@ public class HolidayData { this.repaymentsRescheduledTo = repaymentsRescheduledTo; this.officeId = null; this.status = status; + this.reschedulingType = reschedulingType; } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayDataValidator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayDataValidator.java index e99eafb..755292c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/data/HolidayDataValidator.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -33,6 +34,7 @@ import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.organisation.holiday.api.HolidayApiConstants; +import org.apache.fineract.organisation.holiday.domain.RescheduleType; import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -50,7 +52,8 @@ public class HolidayDataValidator { Arrays.asList(HolidayApiConstants.localeParamName, HolidayApiConstants.dateFormatParamName, HolidayApiConstants.nameParamName, HolidayApiConstants.fromDateParamName, HolidayApiConstants.toDateParamName, HolidayApiConstants.descriptionParamName, - HolidayApiConstants.officesParamName, HolidayApiConstants.repaymentsRescheduledToParamName)); + HolidayApiConstants.officesParamName, HolidayApiConstants.repaymentsRescheduledToParamName, + HolidayApiConstants.reschedulingType)); @Autowired public HolidayDataValidator(final FromJsonHelper fromApiJsonHelper) { @@ -79,11 +82,18 @@ public class HolidayDataValidator { final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.toDateParamName, element); baseDataValidator.reset().parameter(HolidayApiConstants.toDateParamName).value(toDate).notNull(); - - final LocalDate repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed( - HolidayApiConstants.repaymentsRescheduledToParamName, element); - baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledToParamName).value(repaymentsRescheduledTo).notNull(); - + + Integer reschedulingType = null; + if(this.fromApiJsonHelper.parameterExists(HolidayApiConstants.reschedulingType, element)){ + reschedulingType = this.fromApiJsonHelper.extractIntegerNamed(HolidayApiConstants.reschedulingType, element, Locale.ENGLISH); + } + + LocalDate repaymentsRescheduledTo = null; + if(reschedulingType == null || reschedulingType.equals(RescheduleType.RESCHEDULETOSPECIFICDATE.getValue())){ + repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed( + HolidayApiConstants.repaymentsRescheduledToParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledToParamName).value(repaymentsRescheduledTo).notNull(); + } Set<Long> offices = null; final JsonObject topLevelJsonElement = element.getAsJsonObject(); http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/Holiday.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/Holiday.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/Holiday.java index be79b25..c25a3bf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/Holiday.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/Holiday.java @@ -73,9 +73,12 @@ public class Holiday extends AbstractPersistableCustom<Long> { @Temporal(TemporalType.DATE) private Date toDate; - @Column(name = "repayments_rescheduled_to", nullable = false) + @Column(name = "repayments_rescheduled_to", nullable = true) @Temporal(TemporalType.DATE) private Date repaymentsRescheduledTo; + + @Column(name = "rescheduling_type", nullable = false) + private int reschedulingType; @Column(name = "status_enum", nullable = false) private Integer status; @@ -94,13 +97,21 @@ public class Holiday extends AbstractPersistableCustom<Long> { final String name = command.stringValueOfParameterNamed(HolidayApiConstants.nameParamName); final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDateParamName); final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDateParamName); - final LocalDate repaymentsRescheduledTo = command - .localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName); + Integer reschedulingType = null; + if(command.parameterExists(HolidayApiConstants.reschedulingType)){ + reschedulingType = command.integerValueOfParameterNamed(HolidayApiConstants.reschedulingType); + } + LocalDate repaymentsRescheduledTo = null; + if(reschedulingType == null || reschedulingType.equals(RescheduleType.RESCHEDULETOSPECIFICDATE.getValue())){ + repaymentsRescheduledTo = command + .localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName); + } final Integer status = HolidayStatusType.PENDING_FOR_ACTIVATION.getValue(); final boolean processed = false;// default it to false. Only batch job // should update this field. final String description = command.stringValueOfParameterNamed(HolidayApiConstants.descriptionParamName); - return new Holiday(name, fromDate, toDate, repaymentsRescheduledTo, status, processed, description, offices); + + return new Holiday(name, fromDate, toDate, repaymentsRescheduledTo, status, processed, description, offices, reschedulingType); } public Map<String, Object> update(final JsonCommand command) { @@ -125,6 +136,16 @@ public class Holiday extends AbstractPersistableCustom<Long> { actualChanges.put(descriptionParamName, newValue); this.description = StringUtils.defaultIfEmpty(newValue, null); } + + + if (command.isChangeInIntegerParameterNamed(HolidayApiConstants.reschedulingType,this.reschedulingType)) { + final Integer newValue =command.integerValueOfParameterNamed(HolidayApiConstants.reschedulingType); + actualChanges.put(HolidayApiConstants.reschedulingType, newValue); + this.reschedulingType = RescheduleType.fromInt(newValue).getValue(); + if(newValue.equals(RescheduleType.RESCHEDULETONEXTREPAYMENTDATE.getValue())){ + this.repaymentsRescheduledTo = null; + } + } if (currentStatus.isPendingActivation()) { if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDateLocalDate())) { @@ -205,7 +226,7 @@ public class Holiday extends AbstractPersistableCustom<Long> { } private Holiday(final String name, final LocalDate fromDate, final LocalDate toDate, final LocalDate repaymentsRescheduledTo, - final Integer status, final boolean processed, final String description, final Set<Office> offices) { + final Integer status, final boolean processed, final String description, final Set<Office> offices, final int reschedulingType) { if (StringUtils.isNotBlank(name)) { this.name = name.trim(); } @@ -234,6 +255,7 @@ public class Holiday extends AbstractPersistableCustom<Long> { if (offices != null) { this.offices = offices; } + this.reschedulingType = reschedulingType; } protected Holiday() {} @@ -298,4 +320,8 @@ public class Holiday extends AbstractPersistableCustom<Long> { } this.status = HolidayStatusType.DELETED.getValue(); } + + public RescheduleType getReScheduleType() { + return RescheduleType.fromInt(this.reschedulingType); + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java new file mode 100644 index 0000000..a87b658 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/domain/RescheduleType.java @@ -0,0 +1,64 @@ +/** + * 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. + */ +package org.apache.fineract.organisation.holiday.domain; + +public enum RescheduleType { + + INVALID(0, "rescheduletype.invalid"), RESCHEDULETOSPECIFICDATE(2, "rescheduletype.rescheduletospecificdate"), // + RESCHEDULETONEXTREPAYMENTDATE(1, "rescheduletype.rescheduletonextrepaymentdate"); + + private final Integer value; + private final String code; + + private RescheduleType(Integer value, String code) { + this.value = value; + this.code = code; + } + + public static RescheduleType fromInt(int rescheduleTypeValue) { + RescheduleType enumerration = RescheduleType.INVALID; + switch (rescheduleTypeValue) { + case 1: + enumerration = RescheduleType.RESCHEDULETONEXTREPAYMENTDATE; + break; + case 2: + enumerration = RescheduleType.RESCHEDULETOSPECIFICDATE; + break; + } + return enumerration; + } + + public boolean isRescheduleToSpecificDate(){ + return this.value.equals(RescheduleType.RESCHEDULETOSPECIFICDATE.getValue()); + } + + public boolean isResheduleToNextRepaymentDate(){ + return this.value.equals(RescheduleType.RESCHEDULETONEXTREPAYMENTDATE.getValue()); + } + + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayEnumerations.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayEnumerations.java index 43e22d0..176a3c8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayEnumerations.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayEnumerations.java @@ -20,6 +20,7 @@ package org.apache.fineract.organisation.holiday.service; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.organisation.holiday.domain.HolidayStatusType; +import org.apache.fineract.organisation.holiday.domain.RescheduleType; public class HolidayEnumerations { @@ -49,4 +50,29 @@ public class HolidayEnumerations { } return optionData; } + + public static EnumOptionData rescheduleType(final int id) { + return rescheduleType(RescheduleType.fromInt(id)); + } + + + public static EnumOptionData rescheduleType(final RescheduleType type) { + EnumOptionData optionData = null; + switch (type) { + case RESCHEDULETONEXTREPAYMENTDATE: + optionData = new EnumOptionData(RescheduleType.RESCHEDULETONEXTREPAYMENTDATE.getValue().longValue(), + RescheduleType.RESCHEDULETONEXTREPAYMENTDATE.getCode(), "Reschedule to next repayment date"); + break; + case RESCHEDULETOSPECIFICDATE: + optionData = new EnumOptionData(RescheduleType.RESCHEDULETOSPECIFICDATE.getValue().longValue(), + RescheduleType.RESCHEDULETOSPECIFICDATE.getCode(), "Reschedule to specified date"); + break; + + default: + optionData = new EnumOptionData(RescheduleType.INVALID.getValue().longValue(), + RescheduleType.INVALID.getCode(), "Invalid"); + break; + } + return optionData; + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformService.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformService.java index 309af96..9ca4b3f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformService.java @@ -20,7 +20,9 @@ package org.apache.fineract.organisation.holiday.service; import java.util.Collection; import java.util.Date; +import java.util.List; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.organisation.holiday.data.HolidayData; public interface HolidayReadPlatformService { @@ -28,4 +30,6 @@ public interface HolidayReadPlatformService { Collection<HolidayData> retrieveAllHolidaysBySearchParamerters(final Long officeId, Date fromDate, Date toDate); HolidayData retrieveHoliday(final Long holidayId); + + List<EnumOptionData> retrieveRepaymentScheduleUpdationTyeOptions(); } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformServiceImpl.java index 2601d21..96ccb72 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayReadPlatformServiceImpl.java @@ -25,12 +25,14 @@ import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collection; import java.util.Date; +import java.util.List; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.holiday.data.HolidayData; +import org.apache.fineract.organisation.holiday.domain.RescheduleType; import org.apache.fineract.organisation.holiday.exception.HolidayNotFoundException; import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; @@ -58,7 +60,7 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic public HolidayMapper() { final StringBuilder sqlBuilder = new StringBuilder(200); sqlBuilder.append("h.id as id, h.name as name, h.description as description, h.from_date as fromDate, h.to_date as toDate, "); - sqlBuilder.append("h.repayments_rescheduled_to as repaymentsScheduleTO, h.status_enum as statusEnum "); + sqlBuilder.append("h.repayments_rescheduled_to as repaymentsScheduleTO, h.rescheduling_type as reschedulingType, h.status_enum as statusEnum "); sqlBuilder.append("from m_holiday h "); this.schema = sqlBuilder.toString(); } @@ -76,9 +78,10 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic final LocalDate toDate = JdbcSupport.getLocalDate(rs, "toDate"); final LocalDate repaymentsScheduleTO = JdbcSupport.getLocalDate(rs, "repaymentsScheduleTO"); final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum"); + final Integer reschedulingType = JdbcSupport.getInteger(rs, "reschedulingType"); final EnumOptionData status = HolidayEnumerations.holidayStatusType(statusEnum); - return new HolidayData(id, name, description, fromDate, toDate, repaymentsScheduleTO, status); + return new HolidayData(id, name, description, fromDate, toDate, repaymentsScheduleTO, status, reschedulingType); } } @@ -133,5 +136,14 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic throw new HolidayNotFoundException(holidayId); } } + + @Override + public List<EnumOptionData> retrieveRepaymentScheduleUpdationTyeOptions(){ + + final List<EnumOptionData> repSchUpdationTypeOptions = Arrays.asList( + HolidayEnumerations.rescheduleType(RescheduleType.RESCHEDULETOSPECIFICDATE), + HolidayEnumerations.rescheduleType(RescheduleType.RESCHEDULETONEXTREPAYMENTDATE)); + return repSchUpdationTypeOptions; + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayUtil.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayUtil.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayUtil.java index c026ac1..ba729f0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayUtil.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayUtil.java @@ -21,6 +21,7 @@ package org.apache.fineract.organisation.holiday.service; import java.util.List; import org.apache.fineract.organisation.holiday.domain.Holiday; +import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO; import org.joda.time.LocalDate; public class HolidayUtil { @@ -56,4 +57,20 @@ public class HolidayUtil { return false; } + + public static Holiday getApplicableHoliday(final LocalDate repaymentDate, final List<Holiday> holidays) { + Holiday referedHoliday = null; + for (final Holiday holiday : holidays) { + if (!repaymentDate.isBefore(holiday.getFromDateLocalDate()) && !repaymentDate.isAfter(holiday.getToDateLocalDate())) { + referedHoliday = holiday; + } + } + return referedHoliday; + } + public static void updateRepaymentRescheduleDateToWorkingDayIfItIsHoliday(final AdjustedDateDetailsDTO adjustedDateDetailsDTO, + final Holiday holiday) { + if (holiday.getReScheduleType().isRescheduleToSpecificDate()) { + adjustedDateDetailsDTO.setChangedScheduleDate(holiday.getRepaymentsRescheduledToLocalDate()); + } + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java index 6bce676..6ff9818 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java @@ -194,9 +194,18 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit private void validateInputDates(final JsonCommand command) { final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDateParamName); final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDateParamName); - final LocalDate repaymentsRescheduledTo = command - .localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName); - this.validateInputDates(fromDate, toDate, repaymentsRescheduledTo); + Integer reshedulingType = null; + if(command.parameterExists(HolidayApiConstants.reschedulingType)){ + reshedulingType = command.integerValueOfParameterNamed(HolidayApiConstants.reschedulingType); + } + LocalDate repaymentsRescheduledTo = null; + if(reshedulingType != null && reshedulingType.equals(2)){ + repaymentsRescheduledTo = command + .localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName); + } + if(repaymentsRescheduledTo != null){ + this.validateInputDates(fromDate, toDate, repaymentsRescheduledTo); + } } private void validateInputDates(final LocalDate fromDate, final LocalDate toDate, final LocalDate repaymentsRescheduledTo) { @@ -208,37 +217,40 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit throw new HolidayDateException("to.date.cannot.be.before.from.date", defaultUserMessage, fromDate.toString(), toDate.toString()); } + if(repaymentsRescheduledTo != null){ + if ((repaymentsRescheduledTo.isEqual(fromDate) || repaymentsRescheduledTo.isEqual(toDate) + || (repaymentsRescheduledTo.isAfter(fromDate) && repaymentsRescheduledTo.isBefore(toDate)))) { - if (repaymentsRescheduledTo.isEqual(fromDate) || repaymentsRescheduledTo.isEqual(toDate) - || (repaymentsRescheduledTo.isAfter(fromDate) && repaymentsRescheduledTo.isBefore(toDate))) { + defaultUserMessage = "Repayments rescheduled date should be before from date or after to date."; + throw new HolidayDateException("repayments.rescheduled.date.should.be.before.from.date.or.after.to.date", defaultUserMessage, + repaymentsRescheduledTo.toString()); + } - defaultUserMessage = "Repayments rescheduled date should be before from date or after to date."; - throw new HolidayDateException("repayments.rescheduled.date.should.be.before.from.date.or.after.to.date", defaultUserMessage, - repaymentsRescheduledTo.toString()); - } + final WorkingDays workingDays = this.daysRepositoryWrapper.findOne(); + final Boolean isRepaymentOnWorkingDay = WorkingDaysUtil.isWorkingDay(workingDays, repaymentsRescheduledTo); - final WorkingDays workingDays = this.daysRepositoryWrapper.findOne(); - final Boolean isRepaymentOnWorkingDay = WorkingDaysUtil.isWorkingDay(workingDays, repaymentsRescheduledTo); + if (!isRepaymentOnWorkingDay) { + defaultUserMessage = "Repayments rescheduled date should not fall on non working days"; + throw new HolidayDateException("repayments.rescheduled.date.should.not.fall.on.non.working.day", defaultUserMessage, + repaymentsRescheduledTo.toString()); + } - if (!isRepaymentOnWorkingDay) { - defaultUserMessage = "Repayments rescheduled date should not fall on non working days"; - throw new HolidayDateException("repayments.rescheduled.date.should.not.fall.on.non.working.day", defaultUserMessage, - repaymentsRescheduledTo.toString()); + // validate repaymentsRescheduledTo date + // 1. should be within a 7 days date range. + // 2. Alternative date should not be an exist holiday.//TBD + // 3. Holiday should not be on an repaymentsRescheduledTo date of + // another holiday.//TBD + + // restricting repaymentsRescheduledTo date to be within 7 days range + // before or after from date and to date. + if (repaymentsRescheduledTo.isBefore(fromDate.minusDays(7)) || repaymentsRescheduledTo.isAfter(toDate.plusDays(7))) { + defaultUserMessage = "Repayments Rescheduled to date must be within 7 days before or after from and to dates"; + throw new HolidayDateException("repayments.rescheduled.to.must.be.within.range", defaultUserMessage, fromDate.toString(), + toDate.toString(), repaymentsRescheduledTo.toString()); + } } - // validate repaymentsRescheduledTo date - // 1. should be within a 7 days date range. - // 2. Alternative date should not be an exist holiday.//TBD - // 3. Holiday should not be on an repaymentsRescheduledTo date of - // another holiday.//TBD - - // restricting repaymentsRescheduledTo date to be within 7 days range - // before or after from date and to date. - if (repaymentsRescheduledTo.isBefore(fromDate.minusDays(7)) || repaymentsRescheduledTo.isAfter(toDate.plusDays(7))) { - defaultUserMessage = "Repayments Rescheduled to date must be within 7 days before or after from and to dates"; - throw new HolidayDateException("repayments.rescheduled.to.must.be.within.range", defaultUserMessage, fromDate.toString(), - toDate.toString(), repaymentsRescheduledTo.toString()); - } + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/AdjustedDateDetailsDTO.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/AdjustedDateDetailsDTO.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/AdjustedDateDetailsDTO.java new file mode 100644 index 0000000..916c2fd --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/data/AdjustedDateDetailsDTO.java @@ -0,0 +1,76 @@ +/** + * 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. + */ +package org.apache.fineract.organisation.workingdays.data; + +import org.joda.time.LocalDate; + + +public class AdjustedDateDetailsDTO { + + /** + * Variable tracks the current schedule date that has been changed + */ + LocalDate changedScheduleDate; + /** + * Variable tracks If the meeting has been changed , i.e future schedule + * also changes along with the current repayments date. + */ + LocalDate changedActualRepaymentDate; + + /** + * Variable tracks the next repayment period due date + */ + LocalDate nextRepaymentPeriodDueDate; + + public AdjustedDateDetailsDTO(final LocalDate changedScheduleDate, final LocalDate changedActualRepaymentDate) { + this.changedScheduleDate = changedScheduleDate; + this.changedActualRepaymentDate = changedActualRepaymentDate; + } + + public AdjustedDateDetailsDTO(final LocalDate changedScheduleDate, final LocalDate changedActualRepaymentDate, + final LocalDate nextRepaymentPeriodDueDate) { + this.changedScheduleDate = changedScheduleDate; + this.changedActualRepaymentDate = changedActualRepaymentDate; + this.nextRepaymentPeriodDueDate = nextRepaymentPeriodDueDate; + } + + public LocalDate getChangedScheduleDate() { + return this.changedScheduleDate; + } + + public LocalDate getChangedActualRepaymentDate() { + return this.changedActualRepaymentDate; + } + + public void setChangedScheduleDate(final LocalDate changedScheduleDate) { + this.changedScheduleDate = changedScheduleDate; + } + + public void setChangedActualRepaymentDate(final LocalDate changedActualRepaymentDate) { + this.changedActualRepaymentDate = changedActualRepaymentDate; + } + + public LocalDate getNextRepaymentPeriodDueDate() { + return this.nextRepaymentPeriodDueDate; + } + + public void setNextRepaymentPeriodDueDate(final LocalDate nextRepaymentPeriodDueDate) { + this.nextRepaymentPeriodDueDate = nextRepaymentPeriodDueDate; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/domain/RepaymentRescheduleType.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/domain/RepaymentRescheduleType.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/domain/RepaymentRescheduleType.java index 0194cd7..d658f92 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/domain/RepaymentRescheduleType.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/domain/RepaymentRescheduleType.java @@ -26,7 +26,8 @@ public enum RepaymentRescheduleType { INVALID(0, "RepaymentRescheduleType.invalid"), SAME_DAY(1, "RepaymentRescheduleType.same.day"), MOVE_TO_NEXT_WORKING_DAY(2, "RepaymentRescheduleType.move.to.next.working.day"), MOVE_TO_NEXT_REPAYMENT_MEETING_DAY(3, "RepaymentRescheduleType.move.to.next.repayment.meeting.day"), MOVE_TO_PREVIOUS_WORKING_DAY(4, - "RepaymentRescheduleType.move.to.previous.working.day"); + "RepaymentRescheduleType.move.to.previous.working.day"), + MOVE_TO_NEXT_MEETING_DAY(5, "RepaymentRescheduleType.move.to.next.meeting.day"); private final Integer value; private final String code; @@ -43,6 +44,10 @@ public enum RepaymentRescheduleType { public String getCode() { return this.code; } + + public boolean isMoveToNextRepaymentDay() { + return this.value.equals(RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY.getValue()); + } private static final Map<Integer, RepaymentRescheduleType> intToEnumMap = new HashMap<>(); private static int minValue; http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysUtil.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysUtil.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysUtil.java index ac0fc39..605a891 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysUtil.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/workingdays/service/WorkingDaysUtil.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.organisation.workingdays.service; +import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO; import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType; import org.apache.fineract.organisation.workingdays.domain.WorkingDays; import org.apache.fineract.portfolio.calendar.service.CalendarUtils; @@ -56,4 +57,15 @@ public class WorkingDaysUtil { public static boolean isNonWorkingDay(final WorkingDays workingDays, final LocalDate date) { return !isWorkingDay(workingDays, date); } + + public static void updateWorkingDayIfRepaymentDateIsNonWorkingDay(final AdjustedDateDetailsDTO adjustedDateDetailsDTO, final WorkingDays workingDays) { + final LocalDate changedScheduleDate = getOffSetDateIfNonWorkingDay(adjustedDateDetailsDTO.getChangedScheduleDate(), + adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate(), workingDays); + adjustedDateDetailsDTO.setChangedScheduleDate(changedScheduleDate); + } + + public static RepaymentRescheduleType getRepaymentRescheduleType(final WorkingDays workingDays, final LocalDate date) { + RepaymentRescheduleType rescheduleType = RepaymentRescheduleType.fromInt(workingDays.getRepaymentReschedulingType()); + return rescheduleType; + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java index 6360380..c7f10cb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarUtils.java @@ -700,4 +700,112 @@ public class CalendarUtils { } return monthOnDay; } + + public static LocalDate getNextRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate, + final LocalDate repaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays, + boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays, boolean applyWorkingDays) { + boolean isCalledFirstTime = true; + return getNextRepaymentMeetingDate(recurringRule, seedDate, repaymentDate, loanRepaymentInterval, frequency, + workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays, isCalledFirstTime, applyWorkingDays); + } + + public static LocalDate getNextRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate, + final LocalDate repaymentDate, final Integer loanRepaymentInterval, final String frequency, + boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays) { + boolean isCalledFirstTime = true; + final WorkingDays workingDays = null; + boolean applyWorkingDays = false; + return getNextRepaymentMeetingDate(recurringRule, seedDate, repaymentDate, loanRepaymentInterval, frequency, + workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays, isCalledFirstTime, applyWorkingDays); + } + + public static LocalDate getNextRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate, + final LocalDate repaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays, + boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays, boolean isCalledFirstTime, boolean applyWorkingDays) { + + final Recur recur = CalendarUtils.getICalRecur(recurringRule); + if (recur == null) { return null; } + LocalDate tmpDate = repaymentDate; + + final Integer repaymentInterval = getMeetingIntervalFromFrequency(loanRepaymentInterval, frequency, recur); + /* + * 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. + */ + int meetingInterval = recur.getInterval(); + if(meetingInterval < 1){ + meetingInterval = 1; + } + int rep = repaymentInterval<meetingInterval ? 1: repaymentInterval / meetingInterval ; + + /* + * 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); + } + + /** + * Below code modified as discussed with Pramod N + */ + LocalDate newRepaymentDate = tmpDate; + int newRepayment = rep; + while (newRepayment > 0) { + newRepaymentDate = getNextRecurringDate(recur, seedDate, newRepaymentDate); + newRepayment--; + } + + LocalDate nextRepaymentDate = null; + if (applyWorkingDays) { + if (WorkingDaysUtil.isNonWorkingDay(workingDays, newRepaymentDate) + && WorkingDaysUtil.getRepaymentRescheduleType(workingDays, newRepaymentDate).isMoveToNextRepaymentDay()) { + newRepaymentDate = getNextRepaymentMeetingDate(recurringRule, seedDate, newRepaymentDate.plusDays(1), + loanRepaymentInterval, frequency, workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays, isCalledFirstTime, + applyWorkingDays); + } else { + newRepaymentDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(newRepaymentDate, nextRepaymentDate, workingDays); + } + } + + if(isCalledFirstTime && newRepaymentDate.equals(repaymentDate)){ + isCalledFirstTime = false; + newRepaymentDate = getNextRepaymentMeetingDate(recurringRule, seedDate, repaymentDate.plusDays(1), loanRepaymentInterval, + frequency, workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays, isCalledFirstTime, applyWorkingDays); + } + + if (isSkipRepaymentOnFirstDayOfMonth) { + final LocalDate newRepaymentDateTemp = adjustRecurringDate(newRepaymentDate, numberOfDays); + if (applyWorkingDays) { + if (WorkingDaysUtil.isNonWorkingDay(workingDays, newRepaymentDateTemp) + && WorkingDaysUtil.getRepaymentRescheduleType(workingDays, newRepaymentDateTemp).isMoveToNextRepaymentDay()) { + newRepaymentDate = getNextRepaymentMeetingDate(recurringRule, seedDate, newRepaymentDate.plusDays(1), + loanRepaymentInterval, frequency, workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays, + isCalledFirstTime, applyWorkingDays); + } else { + newRepaymentDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(newRepaymentDateTemp, nextRepaymentDate, workingDays); + } + } + } + return newRepaymentDate; + } + + public static Integer getMeetingIntervalFromFrequency(final Integer loanRepaymentInterval, final String frequency, final Recur recur) { + final Integer interval = 4; + Integer repaymentInterval = loanRepaymentInterval; + /* + * check loanRepaymentInterval equal to 1, if repayments frequency is + * monthly and meeting frequency is weekly, then generate repayments + * schedule as every 4 weeks + */ + if (frequency.equals(Recur.MONTHLY) && recur.getFrequency().equals(Recur.WEEKLY)) { + repaymentInterval = loanRepaymentInterval*interval; + } + return repaymentInterval; + } } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/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 cb42bf5..d8baaf3 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 @@ -34,6 +34,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; +import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO; import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType; import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; import org.apache.fineract.portfolio.calendar.service.CalendarUtils; @@ -121,7 +122,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener boolean isFirstRepayment = true; LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate( - loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO); + loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment); final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate( loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate, loanApplicationTerms.getLoanCalendar(), loanApplicationTerms.getHolidayDetailDTO(), loanApplicationTerms); @@ -179,10 +180,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener while (!scheduleParams.getOutstandingBalance().isZero() || !scheduleParams.getDisburseDetailMap().isEmpty()) { LocalDate previousRepaymentDate = scheduleParams.getActualRepaymentDate(); scheduleParams.setActualRepaymentDate(this.scheduledDateGenerator.generateNextRepaymentDate( - scheduleParams.getActualRepaymentDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO)); + scheduleParams.getActualRepaymentDate(), loanApplicationTerms, isFirstRepayment)); + AdjustedDateDetailsDTO adjustedDateDetailsDTO = this.scheduledDateGenerator.adjustRepaymentDate( + scheduleParams.getActualRepaymentDate(), loanApplicationTerms, holidayDetailDTO); + scheduleParams.setActualRepaymentDate(adjustedDateDetailsDTO.getChangedActualRepaymentDate()); isFirstRepayment = false; - LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(scheduleParams.getActualRepaymentDate(), - loanApplicationTerms, holidayDetailDTO); + LocalDate scheduledDueDate = adjustedDateDetailsDTO.getChangedScheduleDate(); // calculated interest start date for the period LocalDate periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms, @@ -1320,7 +1323,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener do { params.setActualRepaymentDate(this.scheduledDateGenerator.generateNextRepaymentDate(params.getActualRepaymentDate(), - loanApplicationTerms, isFirstRepayment, holidayDetailDTO)); + loanApplicationTerms, isFirstRepayment)); if (params.getActualRepaymentDate().isAfter(currentDate)) { params.setActualRepaymentDate(currentDate); } @@ -2172,41 +2175,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener ArrayList<LoanTermVariationsData> dueDateVariationsDataList = new ArrayList<>(); - // check for date changes + // check for date changes - do { - actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, - loanApplicationTerms, isFirstRepayment, holidayDetailDTO); - isFirstRepayment = false; - lastInstallmentDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms, - holidayDetailDTO); - while (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(lastInstallmentDate)) { - LoanTermVariationsData variation = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation(); - if (!variation.isSpecificToInstallment()) { - actualRepaymentDate = variation.getDateValue(); - /*if (!isDueDateChangeApplied) { - previousRepaymentDate = actualRepaymentDate; - isDueDateChangeApplied = true; - }*/ - lastInstallmentDate = actualRepaymentDate; - } - dueDateVariationsDataList.add(variation); + while (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(lastInstallmentDate)) { + LoanTermVariationsData variation = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation(); + if (!variation.isSpecificToInstallment()) { + actualRepaymentDate = variation.getDateValue(); + loanApplicationTerms.setSeedDate(actualRepaymentDate); } - loanTermVariationParams = applyExceptionLoanTermVariations(loanApplicationTerms, lastInstallmentDate, - exceptionDataListIterator, instalmentNumber, totalCumulativePrincipal, totalCumulativeInterest, mc); - } while (loanTermVariationParams != null && loanTermVariationParams.isSkipPeriod()); - - /*if (!lastInstallmentDate.isBefore(rescheduleFrom)) { - actualRepaymentDate = previousRepaymentDate; - if(isDueDateChangeApplied){ - int numberOfDateChangesApplied = dueDateVariationsDataList.size(); - while(numberOfDateChangesApplied >0 ){ - loanApplicationTerms.getLoanTermVariations().previousDueDateVariation(); - numberOfDateChangesApplied--; - } - } - break; - }*/ + lastInstallmentDate = variation.getDateValue(); + dueDateVariationsDataList.add(variation); + } periodNumber++; for (LoanTermVariationsData dueDateVariation : dueDateVariationsDataList) { http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java index 93a58ce..5974d3f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java @@ -20,6 +20,7 @@ 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.workingdays.data.AdjustedDateDetailsDTO; import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType; import org.apache.fineract.organisation.workingdays.domain.WorkingDays; import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil; @@ -45,25 +46,26 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator { LocalDate lastRepaymentDate = loanApplicationTerms.getExpectedDisbursementDate(); boolean isFirstRepayment = true; for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments; repaymentPeriod++) { - lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment, holidayDetailDTO); + lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment); isFirstRepayment = false; } - lastRepaymentDate = adjustRepaymentDate(lastRepaymentDate, loanApplicationTerms, holidayDetailDTO); + lastRepaymentDate = adjustRepaymentDate(lastRepaymentDate, loanApplicationTerms, holidayDetailDTO).getChangedScheduleDate(); return lastRepaymentDate; } @Override public LocalDate generateNextRepaymentDate(final LocalDate lastRepaymentDate, final LoanApplicationTerms loanApplicationTerms, - boolean isFirstRepayment, final HolidayDetailDTO holidayDetailDTO) { + boolean isFirstRepayment) { final LocalDate firstRepaymentPeriodDate = loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate(); LocalDate dueRepaymentPeriodDate = null; - Calendar currentCalendar = loanApplicationTerms.getLoanCalendar(); if (isFirstRepayment && firstRepaymentPeriodDate != null) { dueRepaymentPeriodDate = firstRepaymentPeriodDate; } else { + LocalDate seedDate = null; + String reccuringString = null; + Calendar currentCalendar = loanApplicationTerms.getLoanCalendar(); dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(), - loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, null, - null); + loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate); dueRepaymentPeriodDate = CalendarUtils.adjustDate(dueRepaymentPeriodDate, loanApplicationTerms.getSeedDate(), loanApplicationTerms.getRepaymentPeriodFrequencyType()); if (currentCalendar != null) { @@ -79,8 +81,6 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator { } // get the start date from the calendar history - LocalDate seedDate = null; - String reccuringString = null; if (calendarHistory == null) { seedDate = currentCalendar.getStartDateLocalDate(); reccuringString = currentCalendar.getRecurrence(); @@ -89,80 +89,130 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator { reccuringString = calendarHistory.getRecurrence(); } - dueRepaymentPeriodDate = CalendarUtils.getNewRepaymentMeetingDate(reccuringString, seedDate, lastRepaymentDate.plusDays(1), + dueRepaymentPeriodDate = CalendarUtils.getNextRepaymentMeetingDate(reccuringString, seedDate, lastRepaymentDate, loanApplicationTerms.getRepaymentEvery(), CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(loanApplicationTerms.getLoanTermPeriodFrequencyType()), - holidayDetailDTO.getWorkingDays(), loanApplicationTerms.isSkipRepaymentOnFirstDayofMonth(), + loanApplicationTerms.isSkipRepaymentOnFirstDayofMonth(), 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; } - 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 - public LocalDate adjustRepaymentDate(final LocalDate dueRepaymentPeriodDate, final LoanApplicationTerms loanApplicationTerms, - final HolidayDetailDTO holidayDetailDTO) { - LocalDate adjustedDate = dueRepaymentPeriodDate; + @Override + public AdjustedDateDetailsDTO adjustRepaymentDate(final LocalDate dueRepaymentPeriodDate, + final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO) { + final LocalDate adjustedDate = dueRepaymentPeriodDate; + return getAdjustedDateDetailsDTO(dueRepaymentPeriodDate, loanApplicationTerms, holidayDetailDTO, adjustedDate); + } - LocalDate nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(), - loanApplicationTerms.getRepaymentEvery(), adjustedDate, loanApplicationTerms.getNthDay(), - loanApplicationTerms.getWeekDayType()); + private AdjustedDateDetailsDTO getAdjustedDateDetailsDTO(final LocalDate dueRepaymentPeriodDate, + final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO, final LocalDate adjustedDate) { + final boolean isFirstRepayment = false; + final LocalDate nextRepaymentPeriodDueDate = generateNextRepaymentDate(adjustedDate, loanApplicationTerms, isFirstRepayment); + final AdjustedDateDetailsDTO newAdjustedDateDetailsDTO = new AdjustedDateDetailsDTO(adjustedDate, dueRepaymentPeriodDate, + nextRepaymentPeriodDueDate); + return recursivelyCheckNonWorkingDaysAndHolidaysAndWorkingDaysExemptionToGenerateNextRepaymentPeriodDate(newAdjustedDateDetailsDTO, + loanApplicationTerms, holidayDetailDTO, isFirstRepayment); + } - final RepaymentRescheduleType rescheduleType = RepaymentRescheduleType.fromInt(holidayDetailDTO.getWorkingDays() - .getRepaymentReschedulingType()); + /** + * Recursively checking non working days and holidays and working days + * exemption to generate next repayment period date Base on the + * configuration + * + * @param adjustedDateDetailsDTO + * @param loanApplicationTerms + * @param holidayDetailDTO + * @param nextRepaymentPeriodDueDate + * @param rescheduleType + * @param isFirstRepayment + * @return + */ + private AdjustedDateDetailsDTO recursivelyCheckNonWorkingDaysAndHolidaysAndWorkingDaysExemptionToGenerateNextRepaymentPeriodDate( + final AdjustedDateDetailsDTO adjustedDateDetailsDTO, final LoanApplicationTerms loanApplicationTerms, + final HolidayDetailDTO holidayDetailDTO, final boolean isFirstRepayment) { + + checkAndUpdateWorkingDayIfRepaymentDateIsNonWorkingDay(adjustedDateDetailsDTO, holidayDetailDTO, loanApplicationTerms, + isFirstRepayment); + + checkAndUpdateWorkingDayIfRepaymentDateIsHolidayDay(adjustedDateDetailsDTO, holidayDetailDTO, loanApplicationTerms, + isFirstRepayment); /** - * Fix for https://mifosforge.jira.com/browse/MIFOSX-1357 + * Check Changed Schedule Date is holiday or is not a working day Then + * re-call this method to get the non holiday and working day */ - // recursively check for the next working meeting day. - while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), nextDueRepaymentPeriodDate) - && rescheduleType == RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY) { - - nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(), - loanApplicationTerms.getRepaymentEvery(), nextDueRepaymentPeriodDate, loanApplicationTerms.getNthDay(), - loanApplicationTerms.getWeekDayType()); - nextDueRepaymentPeriodDate = CalendarUtils.adjustDate(nextDueRepaymentPeriodDate, loanApplicationTerms.getSeedDate(), - loanApplicationTerms.getRepaymentPeriodFrequencyType()); - + if ((holidayDetailDTO.isHolidayEnabled() && HolidayUtil.getApplicableHoliday(adjustedDateDetailsDTO.getChangedScheduleDate(), + holidayDetailDTO.getHolidays()) != null) + || WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), adjustedDateDetailsDTO.getChangedScheduleDate())) { + recursivelyCheckNonWorkingDaysAndHolidaysAndWorkingDaysExemptionToGenerateNextRepaymentPeriodDate(adjustedDateDetailsDTO, + loanApplicationTerms, holidayDetailDTO, isFirstRepayment); } - adjustedDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(adjustedDate, nextDueRepaymentPeriodDate, - holidayDetailDTO.getWorkingDays()); + return adjustedDateDetailsDTO; + } + /** + * This method to check and update the working day if repayment date is + * holiday + * + * @param adjustedDateDetailsDTO + * @param holidayDetailDTO + * @param loanApplicationTerms + * @param isFirstRepayment + */ + private void checkAndUpdateWorkingDayIfRepaymentDateIsHolidayDay(final AdjustedDateDetailsDTO adjustedDateDetailsDTO, + final HolidayDetailDTO holidayDetailDTO, final LoanApplicationTerms loanApplicationTerms, final boolean isFirstRepayment) { if (holidayDetailDTO.isHolidayEnabled()) { - adjustedDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(adjustedDate, holidayDetailDTO.getHolidays()); + Holiday applicableHolidayForNewAdjustedDate = null; + while ((applicableHolidayForNewAdjustedDate = HolidayUtil.getApplicableHoliday(adjustedDateDetailsDTO.getChangedScheduleDate(), + holidayDetailDTO.getHolidays())) != null) { + if (applicableHolidayForNewAdjustedDate.getReScheduleType().isResheduleToNextRepaymentDate()) { + LocalDate nextRepaymentPeriodDueDate = adjustedDateDetailsDTO.getChangedActualRepaymentDate(); + while (!nextRepaymentPeriodDueDate.isAfter(adjustedDateDetailsDTO.getChangedScheduleDate())) { + nextRepaymentPeriodDueDate = generateNextRepaymentDate(nextRepaymentPeriodDueDate, loanApplicationTerms, + isFirstRepayment); + } + adjustedDateDetailsDTO.setChangedScheduleDate(nextRepaymentPeriodDueDate); + adjustedDateDetailsDTO.setNextRepaymentPeriodDueDate(nextRepaymentPeriodDueDate); + adjustedDateDetailsDTO.setChangedActualRepaymentDate(adjustedDateDetailsDTO.getChangedScheduleDate()); + } else { + HolidayUtil.updateRepaymentRescheduleDateToWorkingDayIfItIsHoliday(adjustedDateDetailsDTO, + applicableHolidayForNewAdjustedDate); + } + } } + } - return adjustedDate; + /** + * This method to check and update the working day if repayment date is non + * working day + * + * @param adjustedDateDetailsDTO + * @param holidayDetailDTO + * @param isFirstRepayment + * @param loanApplicationTerms + */ + private void checkAndUpdateWorkingDayIfRepaymentDateIsNonWorkingDay(final AdjustedDateDetailsDTO adjustedDateDetailsDTO, + final HolidayDetailDTO holidayDetailDTO, final LoanApplicationTerms loanApplicationTerms, final boolean isFirstRepayment) { + while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), adjustedDateDetailsDTO.getChangedScheduleDate())) { + if (WorkingDaysUtil.getRepaymentRescheduleType(holidayDetailDTO.getWorkingDays(), + adjustedDateDetailsDTO.getChangedScheduleDate()).isMoveToNextRepaymentDay()) { + while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), + adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate()) + || adjustedDateDetailsDTO.getChangedScheduleDate().isAfter(adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate())) { + final LocalDate nextRepaymentPeriodDueDate = generateNextRepaymentDate( + adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate(), loanApplicationTerms, isFirstRepayment); + adjustedDateDetailsDTO.setNextRepaymentPeriodDueDate(nextRepaymentPeriodDueDate); + } + } + WorkingDaysUtil.updateWorkingDayIfRepaymentDateIsNonWorkingDay(adjustedDateDetailsDTO, holidayDetailDTO.getWorkingDays()); + } } @Override - public LocalDate getRepaymentPeriodDate(final PeriodFrequencyType frequency, final int repaidEvery, final LocalDate startDate, - Integer nthDay, DayOfWeekType dayOfWeek) { + public LocalDate getRepaymentPeriodDate(final PeriodFrequencyType frequency, final int repaidEvery, final LocalDate startDate) { LocalDate dueRepaymentPeriodDate = startDate; switch (frequency) { case DAYS: @@ -173,9 +223,6 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator { break; case MONTHS: dueRepaymentPeriodDate = startDate.plusMonths(repaidEvery); - if (!(nthDay == null || dayOfWeek == null || dayOfWeek == DayOfWeekType.INVALID)) { - dueRepaymentPeriodDate = adjustToNthWeekDay(dueRepaymentPeriodDate, nthDay, dayOfWeek.getValue()); - } break; case YEARS: dueRepaymentPeriodDate = startDate.plusYears(repaidEvery); @@ -282,10 +329,10 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator { LocalDate generatedDate = loanApplicationTerms.getExpectedDisbursementDate(); boolean isFirstRepayment = true; while (!generatedDate.isAfter(lastRepaymentDate)) { - generatedDate = generateNextRepaymentDate(generatedDate, loanApplicationTerms, isFirstRepayment, holidayDetailDTO); + generatedDate = generateNextRepaymentDate(generatedDate, loanApplicationTerms, isFirstRepayment); isFirstRepayment = false; } - generatedDate = adjustRepaymentDate(generatedDate, loanApplicationTerms, holidayDetailDTO); + generatedDate = adjustRepaymentDate(generatedDate, loanApplicationTerms, holidayDetailDTO).getChangedScheduleDate(); return generatedDate; } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java index 8db5aff..d5f08cb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java @@ -183,7 +183,7 @@ public final class LoanApplicationTerms { private Money adjustPrincipalForFlatLoans; - private final LocalDate seedDate; + private LocalDate seedDate; private final CalendarHistoryDataWrapper calendarHistoryDataWrapper; @@ -1742,5 +1742,9 @@ public final class LoanApplicationTerms { public void updateTotalInterestAccounted(Money totalInterestAccounted){ this.totalInterestAccounted = totalInterestAccounted; } + + public void setSeedDate(LocalDate seedDate) { + this.seedDate = seedDate; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java index c82301d..2119472 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain; +import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO; import org.apache.fineract.portfolio.calendar.domain.Calendar; import org.apache.fineract.portfolio.common.domain.DayOfWeekType; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; @@ -32,14 +33,12 @@ public interface ScheduledDateGenerator { final LocalDate firstRepaymentDate, final Calendar loanCalendar, final HolidayDetailDTO holidayDetailDTO, final LoanApplicationTerms loanApplicationTerms); - LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment, - final HolidayDetailDTO holidayDetailDTO); + LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment); - LocalDate adjustRepaymentDate(LocalDate dueRepaymentPeriodDate, LoanApplicationTerms loanApplicationTerms, + AdjustedDateDetailsDTO adjustRepaymentDate(LocalDate dueRepaymentPeriodDate, LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO); - LocalDate getRepaymentPeriodDate(PeriodFrequencyType frequency, int repaidEvery, LocalDate startDate, Integer nthDay, - DayOfWeekType dayOfWeek); + LocalDate getRepaymentPeriodDate(PeriodFrequencyType frequency, int repaidEvery, LocalDate startDate); Boolean isDateFallsInSchedule(PeriodFrequencyType frequency, int repaidEvery, LocalDate startDate, LocalDate date); http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java index e5ab38d..ef64ec3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java @@ -114,10 +114,10 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) { if (rescheduleFromDate.isBefore(loanTermVariation.getTermApplicableFrom())) { LocalDate applicableDate = this.scheduledDateGenerator.generateNextRepaymentDate(rescheduleFromDate, loanApplicationTerms, - false, loanApplicationTerms.getHolidayDetailDTO()); + false); if (loanTermVariation.getTermApplicableFrom().equals(applicableDate)) { LocalDate adjustedDate = this.scheduledDateGenerator.generateNextRepaymentDate(adjustedApplicableDate, - loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO()); + loanApplicationTerms, false); loanTermVariation.setApplicableFromDate(adjustedDate); loanTermVariationsData.add(loanTermVariation); } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java index 977e7ba..ebffa27 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java @@ -410,9 +410,9 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche } else if (!activeLoanTermVariation.fetchTermApplicaDate().isBefore(fromScheduleDate)) { while (currentScheduleDate.isBefore(activeLoanTermVariation.fetchTermApplicaDate())) { currentScheduleDate = this.scheduledDateGenerator.generateNextRepaymentDate(currentScheduleDate, - loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO()); + loanApplicationTerms, false); modifiedScheduleDate = this.scheduledDateGenerator.generateNextRepaymentDate(modifiedScheduleDate, - loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO()); + loanApplicationTerms, false); changeMap.put(currentScheduleDate, modifiedScheduleDate); } if (changeMap.containsKey(activeLoanTermVariation.fetchTermApplicaDate())) { http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 98f86fc..5744b67 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -2421,7 +2421,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf while (!startDate.isAfter(DateUtils.getLocalDateOfTenant())) { scheduleDates.put(frequencyNunber++, startDate.minusDays(diff.intValue())); LocalDate scheduleDate = scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency), - chargeDefinition.feeInterval(), startDate, null, null); + chargeDefinition.feeInterval(), startDate); startDate = scheduleDate; } http://git-wip-us.apache.org/repos/asf/fineract/blob/b9017e2b/fineract-provider/src/main/resources/sql/migrations/core_db/V331__holiday_schema_changes.sql ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V331__holiday_schema_changes.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V331__holiday_schema_changes.sql new file mode 100644 index 0000000..94ae19a --- /dev/null +++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V331__holiday_schema_changes.sql @@ -0,0 +1,23 @@ +-- +-- 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_holiday +MODIFY COLUMN repayments_rescheduled_to DATETIME NULL DEFAULT NULL, +ADD COLUMN `rescheduling_type` INT(5) NOT NULL DEFAULT '2'; \ No newline at end of file