MIFOSX-1891 Improvements to extend term for loans following daily repayment schedule.
This commit is contained in:
+10
-2
@@ -13971,6 +13971,12 @@ Request Body:
|
||||
<td class=fielddesc>repayment reschedule type .Options listed on the schedule for repayments on non-working days
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>extendTermForDailyRepayments</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Extend the term for loans following a daily repayment schedule.Expects boolean value true/false</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>locale</td>
|
||||
</tr>
|
||||
@@ -14080,6 +14086,7 @@ GET https://DomainName/api/v1/workingdays
|
||||
"code": "RepaymentRescheduleType.move.to.next.working.day",
|
||||
"value": "move to next working day"
|
||||
}
|
||||
"extendTermForDailyRepayments" : true
|
||||
}
|
||||
]
|
||||
</code>
|
||||
@@ -14094,7 +14101,7 @@ GET https://DomainName/api/v1/workingdays
|
||||
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recurrence,repaymentRescheduleType,locale</td>
|
||||
<td>recurrence,repaymentRescheduleType,extendTermForDailyRepayments,locale</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -14109,7 +14116,8 @@ Request Body:
|
||||
{
|
||||
"recurrence": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,SU",
|
||||
"locale": "en",
|
||||
"repaymentsRescheduledType": 4
|
||||
"repaymentsRescheduledType": 4,
|
||||
"extendTermForDailyRepayments": false
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
|
||||
+2
@@ -36,6 +36,7 @@ public class WorkingDaysHelper {
|
||||
map.put("recurrence", "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR,SA,SU");
|
||||
map.put("locale", "en");
|
||||
map.put("repaymentRescheduleType", randomInt(1, 4));
|
||||
map.put("extendTermForDailyRepayments", false);
|
||||
System.out.println("map : " + map);
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
@@ -45,6 +46,7 @@ public class WorkingDaysHelper {
|
||||
map.put("recurrence", "FREQ=WEEKLY;INTERVAL=1;BYDAY=MP,TI,TE,TH");
|
||||
map.put("locale", "en");
|
||||
map.put("repaymentRescheduleType", randomInt(1, 4));
|
||||
map.put("extendTermForDailyRepayments", false);
|
||||
System.out.println("map : " + map);
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
|
||||
+3
-2
@@ -22,14 +22,15 @@ public class WorkingDaysApiConstants {
|
||||
|
||||
public static final String rescheduleRepaymentTemplate = "rescheduleRepaymentTemplate";
|
||||
public static final String localeParamName = "locale";
|
||||
public static final String extendTermForDailyRepayments = "extendTermForDailyRepayments";
|
||||
|
||||
|
||||
|
||||
public static final Set<String> WORKING_DAYS_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS =new HashSet<>(Arrays.asList(
|
||||
recurrence,repayment_rescheduling_enum,localeParamName
|
||||
recurrence,repayment_rescheduling_enum,localeParamName,extendTermForDailyRepayments
|
||||
));
|
||||
public static final Set<String> WORKING_DAYS_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
|
||||
recurrence,repayment_rescheduling_enum
|
||||
recurrence,repayment_rescheduling_enum,extendTermForDailyRepayments
|
||||
));
|
||||
|
||||
public static final Set<String> WORKING_DAYS_TEMPLATE_PARAMETERS = new HashSet<>(Arrays.asList(rescheduleRepaymentTemplate));
|
||||
|
||||
+3
@@ -52,6 +52,9 @@ public class WorkingDayValidator {
|
||||
final Integer repaymentRescheduleType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("repaymentRescheduleType", element);
|
||||
baseDataValidator.reset().parameter("repaymentRescheduleType").value(repaymentRescheduleType).ignoreIfNull().inMinMaxRange(1, 4);
|
||||
|
||||
final Boolean extendTermForDailyRepayments = this.fromApiJsonHelper.extractBooleanNamed("extendTermForDailyRepayments", element);
|
||||
baseDataValidator.reset().parameter(WorkingDaysApiConstants.extendTermForDailyRepayments).value(extendTermForDailyRepayments).ignoreIfNull().validateForBooleanValue();
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
}
|
||||
|
||||
+7
-2
@@ -18,23 +18,28 @@ public class WorkingDaysData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData repaymentRescheduleType;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Boolean extendTermForDailyRepayments;
|
||||
|
||||
// template date
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> repaymentRescheduleOptions;
|
||||
|
||||
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType) {
|
||||
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType, Boolean extendTermForDailyRepayments) {
|
||||
this.id = id;
|
||||
this.recurrence = recurrence;
|
||||
this.repaymentRescheduleType = repaymentRescheduleType;
|
||||
this.repaymentRescheduleOptions = null;
|
||||
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
||||
}
|
||||
|
||||
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType,
|
||||
Collection<EnumOptionData> repaymentRescheduleOptions) {
|
||||
Collection<EnumOptionData> repaymentRescheduleOptions, Boolean extendTermForDailyRepayments) {
|
||||
this.id = id;
|
||||
this.recurrence = recurrence;
|
||||
this.repaymentRescheduleType = repaymentRescheduleType;
|
||||
this.repaymentRescheduleOptions = repaymentRescheduleOptions;
|
||||
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -7,11 +7,13 @@
|
||||
package org.mifosplatform.organisation.workingdays.domain;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.organisation.workingdays.api.WorkingDaysApiConstants;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -25,13 +27,17 @@ public class WorkingDays extends AbstractPersistable<Long> {
|
||||
@Column(name = "repayment_rescheduling_enum", nullable = false)
|
||||
private Integer repaymentReschedulingType;
|
||||
|
||||
@Column(name = "extend_term_daily_repayments", nullable = false)
|
||||
private Boolean extendTermForDailyRepayments;
|
||||
|
||||
protected WorkingDays() {
|
||||
|
||||
}
|
||||
|
||||
protected WorkingDays(final String recurrence, final Integer repaymentReschedulingType) {
|
||||
protected WorkingDays(final String recurrence, final Integer repaymentReschedulingType, final Boolean extendTermForDailyRepayments ) {
|
||||
this.recurrence = recurrence;
|
||||
this.repaymentReschedulingType = repaymentReschedulingType;
|
||||
this.extendTermForDailyRepayments = extendTermForDailyRepayments;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,6 +54,13 @@ public class WorkingDays extends AbstractPersistable<Long> {
|
||||
return this.repaymentReschedulingType;
|
||||
}
|
||||
|
||||
public void setRepaymentReschedulingType(Integer repaymentReschedulingType) {
|
||||
this.repaymentReschedulingType = repaymentReschedulingType;
|
||||
}
|
||||
|
||||
public Boolean getExtendTermForDailyRepayments(){
|
||||
return this.extendTermForDailyRepayments;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
|
||||
@@ -65,6 +78,12 @@ public class WorkingDays extends AbstractPersistable<Long> {
|
||||
actualChanges.put(repaymentRescheduleTypeParamName, WorkingDaysEnumerations.workingDaysStatusType(newValue));
|
||||
this.repaymentReschedulingType = RepaymentRescheduleType.fromInt(newValue).getValue();
|
||||
}
|
||||
|
||||
if(command.isChangeInBooleanParameterNamed(WorkingDaysApiConstants.extendTermForDailyRepayments, this.extendTermForDailyRepayments)){
|
||||
final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed(WorkingDaysApiConstants.extendTermForDailyRepayments);
|
||||
actualChanges.put(WorkingDaysApiConstants.extendTermForDailyRepayments, newValue);
|
||||
this.extendTermForDailyRepayments = newValue;
|
||||
}
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -39,7 +39,8 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
|
||||
|
||||
public WorkingDaysMapper() {
|
||||
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("from m_working_days w");
|
||||
|
||||
this.schema = sqlBuilder.toString();
|
||||
@@ -55,8 +56,9 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
|
||||
final String recurrence = rs.getString("recurrence");
|
||||
final Integer statusEnum = JdbcSupport.getInteger(rs, "status_enum");
|
||||
final EnumOptionData status = WorkingDaysEnumerations.workingDaysStatusType(statusEnum);
|
||||
final Boolean extendTermForDailyRepayments = rs.getBoolean("extendTermForDailyRepayments");
|
||||
|
||||
return new WorkingDaysData(id, recurrence, status);
|
||||
return new WorkingDaysData(id, recurrence, status,extendTermForDailyRepayments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +80,6 @@ public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatfo
|
||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY),
|
||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY),
|
||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY));
|
||||
return new WorkingDaysData(null, null, null, repaymentRescheduleOptions);
|
||||
return new WorkingDaysData(null, null, null, repaymentRescheduleOptions, null);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -23,8 +23,10 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.organisation.workingdays.domain.RepaymentRescheduleType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
@@ -145,14 +147,25 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
Boolean extendTermForDailyRepayments = false;
|
||||
if(holidayDetailDTO.getWorkingDays().getExtendTermForDailyRepayments() == true &&
|
||||
loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.DAYS &&
|
||||
loanApplicationTerms.getRepaymentEvery() == 1){
|
||||
holidayDetailDTO.getWorkingDays().setRepaymentReschedulingType(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY.getValue());
|
||||
extendTermForDailyRepayments = true;
|
||||
}
|
||||
while (!outstandingBalance.isZero() || !disburseDetailMap.isEmpty()) {
|
||||
|
||||
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||
isFirstRepayment);
|
||||
isFirstRepayment = false;
|
||||
isFirstRepayment = false;
|
||||
LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
|
||||
if(extendTermForDailyRepayments){
|
||||
actualRepaymentDate = scheduledDueDate;
|
||||
}
|
||||
|
||||
// calculated interest start date for the period
|
||||
periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms, periodStartDate,
|
||||
idealDisbursementDate, periodStartDateApplicableForInterest);
|
||||
|
||||
+17
-6
@@ -11,6 +11,7 @@ import org.joda.time.Months;
|
||||
import org.joda.time.Weeks;
|
||||
import org.joda.time.Years;
|
||||
import org.mifosplatform.organisation.holiday.service.HolidayUtil;
|
||||
import org.mifosplatform.organisation.workingdays.domain.RepaymentRescheduleType;
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.mifosplatform.portfolio.common.domain.DayOfWeekType;
|
||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||
@@ -53,22 +54,32 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
||||
final HolidayDetailDTO holidayDetailDTO) {
|
||||
|
||||
LocalDate adjustedDate = dueRepaymentPeriodDate;
|
||||
|
||||
LocalDate nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
||||
loanApplicationTerms.getRepaymentEvery(), adjustedDate, loanApplicationTerms.getNthDay(),
|
||||
loanApplicationTerms.getWeekDayType());
|
||||
|
||||
final RepaymentRescheduleType rescheduleType = RepaymentRescheduleType.fromInt(holidayDetailDTO.getWorkingDays().getRepaymentReschedulingType());
|
||||
|
||||
/**
|
||||
* Fix for https://mifosforge.jira.com/browse/MIFOSX-1357
|
||||
*/
|
||||
// recursively check for the next working day.
|
||||
while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), adjustedDate)) {
|
||||
// recursively check for the next working meeting day.
|
||||
while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), nextDueRepaymentPeriodDate) &&
|
||||
rescheduleType == RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY) {
|
||||
|
||||
final LocalDate nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
||||
loanApplicationTerms.getRepaymentEvery(), adjustedDate, loanApplicationTerms.getNthDay(),
|
||||
nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
||||
loanApplicationTerms.getRepaymentEvery(), nextDueRepaymentPeriodDate, loanApplicationTerms.getNthDay(),
|
||||
loanApplicationTerms.getWeekDayType());
|
||||
adjustedDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(adjustedDate, nextDueRepaymentPeriodDate,
|
||||
holidayDetailDTO.getWorkingDays());
|
||||
|
||||
}
|
||||
adjustedDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(adjustedDate, nextDueRepaymentPeriodDate,
|
||||
holidayDetailDTO.getWorkingDays());
|
||||
|
||||
if (holidayDetailDTO.isHolidayEnabled()) {
|
||||
adjustedDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(adjustedDate, holidayDetailDTO.getHolidays());
|
||||
}
|
||||
|
||||
return adjustedDate;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
ALTER TABLE `m_working_days` ADD extend_term_daily_repayments TINYINT(1) NULL DEFAULT '0';
|
||||
Reference in New Issue
Block a user