AL-2-reschedule-loan-first-pay-day-holiday-fix
This commit is contained in:
+2
@@ -94,4 +94,6 @@ public interface ConfigurationDomainService {
|
||||
Integer retrieveOTPLiveTime();
|
||||
|
||||
boolean isSubRatesEnabled();
|
||||
|
||||
boolean isFirstRepaymentDateAfterRescheduleAllowedOnHoliday();
|
||||
}
|
||||
|
||||
+5
@@ -252,6 +252,11 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
|
||||
return getGlobalConfigurationPropertyData("skip-repayment-on-first-day-of-month").isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFirstRepaymentDateAfterRescheduleAllowedOnHoliday() {
|
||||
return getGlobalConfigurationPropertyData("loan-reschedule-is-first-payday-allowed-on-holiday").isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long retreivePeroidInNumberOfDaysForSkipMeetingDate() {
|
||||
final String propertyName = "skip-repayment-on-first-day-of-month";
|
||||
|
||||
+8
-1
@@ -43,6 +43,7 @@ public class ScheduleGeneratorDTO {
|
||||
final Integer numberOfdays;
|
||||
final boolean isSkipRepaymentOnFirstDayofMonth;
|
||||
final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
|
||||
final boolean isFirstRepaymentDateAllowedOnHoliday;
|
||||
|
||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||
@@ -50,7 +51,8 @@ public class ScheduleGeneratorDTO {
|
||||
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO,
|
||||
final Calendar calendar, final CalendarHistoryDataWrapper calendarHistoryDataWrapper,
|
||||
final Boolean isInterestChargedFromDateAsDisbursementDateEnabled, final Integer numberOfdays,
|
||||
final boolean isSkipRepaymentOnFirstDayofMonth, final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled) {
|
||||
final boolean isSkipRepaymentOnFirstDayofMonth, final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled,
|
||||
final boolean isFirstRepaymentDateAllowedOnHoliday) {
|
||||
|
||||
this.loanScheduleFactory = loanScheduleFactory;
|
||||
this.applicationCurrency = applicationCurrency;
|
||||
@@ -67,6 +69,7 @@ public class ScheduleGeneratorDTO {
|
||||
this.numberOfdays = numberOfdays;
|
||||
this.isSkipRepaymentOnFirstDayofMonth = isSkipRepaymentOnFirstDayofMonth;
|
||||
this.isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
|
||||
this.isFirstRepaymentDateAllowedOnHoliday = isFirstRepaymentDateAllowedOnHoliday;
|
||||
}
|
||||
|
||||
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
|
||||
@@ -141,4 +144,8 @@ public class ScheduleGeneratorDTO {
|
||||
return this.isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
|
||||
}
|
||||
|
||||
public boolean isFirstRepaymentDateAllowedOnHoliday() {
|
||||
return isFirstRepaymentDateAllowedOnHoliday;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -5486,7 +5486,7 @@ public class Loan extends AbstractPersistableCustom {
|
||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||
rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
||||
calendarHistoryDataWrapper, scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
|
||||
holidayDetailDTO, allowCompoundingOnEod);
|
||||
holidayDetailDTO, allowCompoundingOnEod, scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday());
|
||||
return loanApplicationTerms;
|
||||
}
|
||||
|
||||
@@ -5764,7 +5764,7 @@ public class Loan extends AbstractPersistableCustom {
|
||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
||||
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod);
|
||||
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
@@ -29,12 +29,15 @@ import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
|
||||
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.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
@@ -2341,6 +2344,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
periods.clear();
|
||||
}
|
||||
LoanScheduleModel loanScheduleModel = generate(mc, loanApplicationTerms, loan.charges(), holidayDetailDTO, loanScheduleParams);
|
||||
// check if first installment after reschedule is a holiday
|
||||
if (!loanApplicationTerms.isFirstRepaymentDateAllowedOnHoliday()) {
|
||||
checkIfFirstRepaymentDateisOnHolidayOrNonWorkingDay(holidayDetailDTO, loanScheduleModel);
|
||||
}
|
||||
|
||||
for (LoanScheduleModelPeriod loanScheduleModelPeriod : loanScheduleModel.getPeriods()) {
|
||||
if (loanScheduleModelPeriod.isRepaymentPeriod()) {
|
||||
// adding newly created repayment periods to installments
|
||||
@@ -2352,6 +2360,24 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
return LoanScheduleDTO.from(retainedInstallments, loanScheduleModelwithPeriodChanges);
|
||||
}
|
||||
|
||||
private void checkIfFirstRepaymentDateisOnHolidayOrNonWorkingDay(HolidayDetailDTO holidayDetailDTO,
|
||||
LoanScheduleModel loanScheduleModel) {
|
||||
|
||||
if (loanScheduleModel != null && loanScheduleModel.getPeriods() != null && loanScheduleModel.getPeriods().iterator() != null
|
||||
&& loanScheduleModel.getPeriods().iterator().next() != null
|
||||
&& loanScheduleModel.getPeriods().iterator().next().periodDueDate() != null) {
|
||||
|
||||
if (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(),
|
||||
loanScheduleModel.getPeriods().iterator().next().periodDueDate())
|
||||
|| HolidayUtil.getApplicableHoliday(loanScheduleModel.getPeriods().iterator().next().periodDueDate(),
|
||||
holidayDetailDTO.getHolidays()) != null) {
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.first.installment.date.after.reschedule.should.be.a.working.day",
|
||||
"As per configiration, the first repayment date after reschedule should be a working day");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<LoanRepaymentScheduleInstallment> fetchRetainedInstallments(
|
||||
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LocalDate rescheduleFrom,
|
||||
MonetaryCurrency currency) {
|
||||
|
||||
+1
@@ -62,6 +62,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
||||
LocalDate dueRepaymentPeriodDate = null;
|
||||
if (isFirstRepayment && firstRepaymentPeriodDate != null) {
|
||||
dueRepaymentPeriodDate = firstRepaymentPeriodDate;
|
||||
|
||||
} else {
|
||||
LocalDate seedDate = null;
|
||||
String reccuringString = null;
|
||||
|
||||
+16
-7
@@ -190,6 +190,8 @@ public final class LoanApplicationTerms {
|
||||
|
||||
private final boolean isSkipRepaymentOnFirstDayOfMonth;
|
||||
|
||||
private final boolean isFirstRepaymentDateAllowedOnHoliday;
|
||||
|
||||
private final HolidayDetailDTO holidayDetailDTO;
|
||||
|
||||
private final Set<Integer> periodNumbersApplicableForPrincipalGrace = new HashSet<>();
|
||||
@@ -243,7 +245,7 @@ public final class LoanApplicationTerms {
|
||||
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations,
|
||||
calendarHistoryDataWrapper, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
|
||||
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization);
|
||||
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false);
|
||||
|
||||
}
|
||||
|
||||
@@ -269,7 +271,7 @@ public final class LoanApplicationTerms {
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType, restCalendarInstance,
|
||||
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
|
||||
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations,
|
||||
calendarHistoryDataWrapper, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod);
|
||||
calendarHistoryDataWrapper, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, false);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -286,7 +288,8 @@ public final class LoanApplicationTerms {
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount,
|
||||
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
|
||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final Integer numberOfDays,
|
||||
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod) {
|
||||
final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
|
||||
final boolean isFirstRepaymentDateAllowedOnHoliday) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -324,7 +327,7 @@ public final class LoanApplicationTerms {
|
||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
|
||||
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO,
|
||||
allowCompoundingOnEod, isEqualAmortization);
|
||||
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -383,7 +386,7 @@ public final class LoanApplicationTerms {
|
||||
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||
installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations,
|
||||
calendarHistoryDataWrapper, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
|
||||
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization);
|
||||
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization, false);
|
||||
|
||||
}
|
||||
|
||||
@@ -409,7 +412,8 @@ public final class LoanApplicationTerms {
|
||||
applicationTerms.loanCalendar, applicationTerms.approvedPrincipal.getAmount(), loanTermVariations,
|
||||
applicationTerms.calendarHistoryDataWrapper, applicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled,
|
||||
applicationTerms.numberOfDays, applicationTerms.isSkipRepaymentOnFirstDayOfMonth, applicationTerms.holidayDetailDTO,
|
||||
applicationTerms.allowCompoundingOnEod, applicationTerms.isEqualAmortization);
|
||||
applicationTerms.allowCompoundingOnEod, applicationTerms.isEqualAmortization,
|
||||
applicationTerms.isFirstRepaymentDateAllowedOnHoliday);
|
||||
}
|
||||
|
||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||
@@ -433,7 +437,7 @@ public final class LoanApplicationTerms {
|
||||
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations,
|
||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper, Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled,
|
||||
final Integer numberOfDays, final boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO,
|
||||
final boolean allowCompoundingOnEod, final boolean isEqualAmortization) {
|
||||
final boolean allowCompoundingOnEod, final boolean isEqualAmortization, final boolean isFirstRepaymentDateAllowedOnHoliday) {
|
||||
|
||||
this.currency = currency;
|
||||
this.loanTermFrequency = loanTermFrequency;
|
||||
@@ -506,6 +510,7 @@ public final class LoanApplicationTerms {
|
||||
this.totalInterestAccounted = principal.zero();
|
||||
this.totalPrincipalAccounted = principal.zero();
|
||||
this.isEqualAmortization = isEqualAmortization;
|
||||
this.isFirstRepaymentDateAllowedOnHoliday = isFirstRepaymentDateAllowedOnHoliday;
|
||||
}
|
||||
|
||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||
@@ -1769,4 +1774,8 @@ public final class LoanApplicationTerms {
|
||||
this.isEqualAmortization = isEqualAmortization;
|
||||
}
|
||||
|
||||
public boolean isFirstRepaymentDateAllowedOnHoliday() {
|
||||
return isFirstRepaymentDateAllowedOnHoliday;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-1
@@ -140,11 +140,14 @@ public class LoanUtilService {
|
||||
final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = this.configurationDomainService
|
||||
.isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled();
|
||||
|
||||
boolean isFirstRepaymentDateAllowedOnHoliday = this.configurationDomainService
|
||||
.isFirstRepaymentDateAfterRescheduleAllowedOnHoliday();
|
||||
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetails, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod, floatingRateDTO, calendar, calendarHistoryDataWrapper,
|
||||
isInterestChargedFromDateAsDisbursementDateEnabled, numberOfDays, isSkipRepaymentOnFirstMonth,
|
||||
isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled);
|
||||
isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled, isFirstRepaymentDateAllowedOnHoliday);
|
||||
|
||||
return scheduleGeneratorDTO;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user