You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ra...@apache.org on 2016/03/28 11:35:46 UTC
[1/2] incubator-fineract git commit: Skip Repayment Date Falling On
First Day of Month
Repository: incubator-fineract
Updated Branches:
refs/heads/develop 9c38078de -> bba8ca47b
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/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 e3d6e4e..64040af 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
@@ -50,6 +50,7 @@ import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanResch
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
+import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
import org.springframework.beans.factory.annotation.Autowired;
@@ -66,6 +67,7 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
private final CalendarInstanceRepository calendarInstanceRepository;
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
+ private final LoanUtilService loanUtilService;
@Autowired
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
@@ -74,7 +76,7 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
final WorkingDaysRepositoryWrapper workingDaysRepository,
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
final CalendarInstanceRepository calendarInstanceRepository,
- final FloatingRatesReadPlatformService floatingRatesReadPlatformService) {
+ final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService) {
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
this.applicationCurrencyRepository = applicationCurrencyRepository;
this.configurationDomainService = configurationDomainService;
@@ -83,6 +85,7 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
this.calendarInstanceRepository = calendarInstanceRepository;
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
+ this.loanUtilService = loanUtilService;
}
@Override
@@ -122,9 +125,17 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
loanCalendar = loanCalendarInstance.getCalendar();
}
final FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar);
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+
+ }
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
- loanCalendar, floatingRateDTO);
+ loanCalendar, floatingRateDTO, isSkipRepaymentOnFirstMonth, numberOfDays);
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
oldPeriods);
return loanRescheduleModelWithOldPeriods;
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/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 b1de9a9..9ab13ee 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
@@ -355,9 +355,17 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
loanCalendar = loanCalendarInstance.getCalendar();
}
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar);
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+
+ }
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
- loanCalendar, floatingRateDTO);
+ loanCalendar, floatingRateDTO, isSkipRepaymentOnFirstMonth, numberOfDays);
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java
index fdda0de..3109a56 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java
@@ -109,10 +109,11 @@ public final class LoanEventApiJsonValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
- public void validateDisbursementDateWithMeetingDate(final LocalDate actualDisbursementDate, final CalendarInstance calendarInstance) {
+ public void validateDisbursementDateWithMeetingDate(final LocalDate actualDisbursementDate, final CalendarInstance calendarInstance,
+ Boolean isSkipRepaymentOnFirstMonth, Integer numberOfDays) {
if (null != calendarInstance) {
final Calendar calendar = calendarInstance.getCalendar();
- if (!calendar.isValidRecurringDate(actualDisbursementDate)) {
+ if (!calendar.isValidRecurringDate(actualDisbursementDate, isSkipRepaymentOnFirstMonth, numberOfDays)) {
// Disbursement date should fall on a meeting date
final String errorMessage = "Expected disbursement date '" + actualDisbursementDate.toString()
+ "' does not fall on a meeting date.";
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
index e27edf6..572b559 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
@@ -889,13 +889,21 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
checkClientOrGroupActive(loan);
-
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
// validate expected disbursement date against meeting date
if (loan.isSyncDisbursementWithMeeting() && (loan.isGroupLoan() || loan.isJLGLoan())) {
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
final Calendar calendar = calendarInstance.getCalendar();
- this.loanScheduleAssembler.validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar);
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if (isSkipRepaymentOnFirstMonthEnabled) {
+ isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+ }
+ this.loanScheduleAssembler.validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar,
+ isSkipRepaymentOnFirstMonth, numberOfDays);
+
}
final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray,
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
index 9689baf..ce06ca4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
@@ -42,11 +42,13 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
+import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
import org.apache.fineract.portfolio.floatingrates.exception.FloatingRateNotFoundException;
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
+import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
@@ -72,13 +74,14 @@ public class LoanUtilService {
private final LoanScheduleGeneratorFactory loanScheduleFactory;
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
private final FromJsonHelper fromApiJsonHelper;
+ private final CalendarReadPlatformService calendarReadPlatformService;
@Autowired
public LoanUtilService(final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService,
final HolidayRepository holidayRepository, final WorkingDaysRepositoryWrapper workingDaysRepository,
final LoanScheduleGeneratorFactory loanScheduleFactory, final FloatingRatesReadPlatformService floatingRatesReadPlatformService,
- final FromJsonHelper fromApiJsonHelper) {
+ final FromJsonHelper fromApiJsonHelper, final CalendarReadPlatformService calendarReadPlatformService) {
this.applicationCurrencyRepository = applicationCurrencyRepository;
this.calendarInstanceRepository = calendarInstanceRepository;
this.configurationDomainService = configurationDomainService;
@@ -87,6 +90,7 @@ public class LoanUtilService {
this.loanScheduleFactory = loanScheduleFactory;
this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
this.fromApiJsonHelper = fromApiJsonHelper;
+ this.calendarReadPlatformService = calendarReadPlatformService;
}
public ScheduleGeneratorDTO buildScheduleGeneratorDTO(final Loan loan, final LocalDate recalculateFrom) {
@@ -125,13 +129,46 @@ public class LoanUtilService {
}
final Boolean isInterestChargedFromDateAsDisbursementDateEnabled = this.configurationDomainService.isInterestChargedFromDateSameAsDisbursementDate();
FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+ }
+
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
calculatedRepaymentsStartingFromDate, holidayDetails, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
- overdurPenaltyWaitPeriod, floatingRateDTO, calendar, calendarHistoryDataWrapper, isInterestChargedFromDateAsDisbursementDateEnabled);
+ overdurPenaltyWaitPeriod, floatingRateDTO, calendar, calendarHistoryDataWrapper, isInterestChargedFromDateAsDisbursementDateEnabled,
+ numberOfDays, isSkipRepaymentOnFirstMonth);
- return scheduleGeneratorDTO;
+ return scheduleGeneratorDTO;
}
+ public Boolean isLoanRepaymentsSyncWithMeeting(final Group group, final Calendar calendar) {
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Long entityId = null;
+ Long entityTypeId = null;
+
+ if (group != null) {
+ if (group.getParent() != null) {
+ entityId = group.getParent().getId();
+ entityTypeId = CalendarEntityType.CENTERS.getValue().longValue();
+ } else {
+ entityId = group.getId();
+ entityTypeId = CalendarEntityType.GROUPS.getValue().longValue();
+ }
+ }
+
+ if (entityId == null || calendar == null) {
+ return isSkipRepaymentOnFirstMonth;
+ }
+ isSkipRepaymentOnFirstMonth = this.calendarReadPlatformService
+ .isCalendarAssociatedWithEntity(entityId, calendar.getId(), entityTypeId);
+ return isSkipRepaymentOnFirstMonth;
+ }
+
+
public LocalDate getCalculatedRepaymentsStartingFromDate(final Loan loan) {
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
@@ -209,8 +246,15 @@ public class LoanUtilService {
final Integer repayEvery = repaymentScheduleDetails.getRepayEvery();
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentScheduleDetails
.getRepaymentPeriodFrequencyType());
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
+ }
calculatedRepaymentsStartingFromDate = CalendarUtils.getFirstRepaymentMeetingDate(calendar, actualDisbursementDate,
- repayEvery, frequency);
+ repayEvery, frequency, isSkipRepaymentOnFirstMonth, numberOfDays);
}
}
}
@@ -230,8 +274,15 @@ public class LoanUtilService {
final Integer repayEvery = repaymentScheduleDetails.getRepayEvery();
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentScheduleDetails
.getRepaymentPeriodFrequencyType());
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), historyList.get(0).getCalendar());
+ }
calculatedRepaymentsStartingFromDate = CalendarUtils.getNextRepaymentMeetingDate(historyList.get(0).getRecurrence(), historyList.get(0).getStartDateLocalDate(),
- actualDisbursementDate, repayEvery, frequency, workingDays);
+ actualDisbursementDate, repayEvery, frequency, workingDays, isSkipRepaymentOnFirstMonth, numberOfDays);
}
}
return calculatedRepaymentsStartingFromDate;
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/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 ba1e9e6..639836a 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
@@ -310,14 +310,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
// check for product mix validations
checkForProductMixRestrictions(loan);
+
+ LocalDate recalculateFrom = null;
+ ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
// validate actual disbursement date against meeting date
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
if (loan.isSyncDisbursementWithMeeting()) {
-
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
- this.loanEventApiJsonValidator.validateDisbursementDateWithMeetingDate(actualDisbursementDate, calendarInstance);
+ this.loanEventApiJsonValidator.validateDisbursementDateWithMeetingDate(actualDisbursementDate, calendarInstance,
+ scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), scheduleGeneratorDTO.getNumberOfdays());
}
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_DISBURSAL,
@@ -356,9 +359,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.getLoanTransactions().add(disbursementTransaction);
}
- LocalDate recalculateFrom = null;
- ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
-
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, rescheduledRepaymentDate);
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
@@ -1988,11 +1988,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
// loop through each loan to reschedule the repayment dates
for (final Loan loan : loans) {
if (loan != null) {
+
if(loan.getExpectedFirstRepaymentOnDate() != null && loan.getExpectedFirstRepaymentOnDate().equals(presentMeetingDate)){
final String defaultUserMessage = "Meeting calendar date update is not supported since its a first repayment date";
throw new CalendarParameterUpdateNotSupportedException("meeting.for.first.repayment.date", defaultUserMessage,
loan.getExpectedFirstRepaymentOnDate(), presentMeetingDate);
}
+
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+ }
+
+
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
@@ -2003,10 +2014,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.fetchRepaymentScheduleInstallments(), loan, null);
} else if (reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates) {
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
- holidays, workingDays, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate);
+ holidays, workingDays, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate,
+ isSkipRepaymentOnFirstMonth, numberOfDays);
} else {
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
- holidays, workingDays);
+ holidays, workingDays, isSkipRepaymentOnFirstMonth, numberOfDays);
}
saveLoanWithDataIntegrityViolationChecks(loan);
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/domain/Meeting.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/domain/Meeting.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/domain/Meeting.java
index be914ed..e33459e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/domain/Meeting.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/domain/Meeting.java
@@ -77,9 +77,11 @@ public class Meeting extends AbstractPersistable<Long> {
this.meetingDate = meetingDate;
}
- public static Meeting createNew(final CalendarInstance calendarInstance, final Date meetingDate, Boolean isTransactionDateOnNonMeetingDate) {
+ public static Meeting createNew(final CalendarInstance calendarInstance, final Date meetingDate, Boolean isTransactionDateOnNonMeetingDate,
+ final boolean isSkipRepaymentOnFirstMonth, final int numberOfDays) {
- if (!isTransactionDateOnNonMeetingDate && !isValidMeetingDate(calendarInstance, meetingDate)) { throw new NotValidRecurringDateException("meeting", "The date '"
+ if (!isTransactionDateOnNonMeetingDate && !isValidMeetingDate(calendarInstance, meetingDate,isSkipRepaymentOnFirstMonth, numberOfDays))
+ { throw new NotValidRecurringDateException("meeting", "The date '"
+ meetingDate + "' is not a valid meeting date.", meetingDate); }
return new Meeting(calendarInstance, meetingDate);
}
@@ -93,7 +95,7 @@ public class Meeting extends AbstractPersistable<Long> {
this.clientsAttendance = new HashSet<>(clientsAttendance);
}
- public Map<String, Object> update(final JsonCommand command) {
+ public Map<String, Object> update(final JsonCommand command, final boolean isSkipRepaymentOnFirstMonth, final int numberOfDays) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
@@ -106,7 +108,7 @@ public class Meeting extends AbstractPersistable<Long> {
actualChanges.put("locale", localeAsInput);
this.meetingDate = newValue.toDate();
- if (!isValidMeetingDate(this.calendarInstance, this.meetingDate)) { throw new NotValidRecurringDateException("meeting",
+ if (!isValidMeetingDate(this.calendarInstance, this.meetingDate, isSkipRepaymentOnFirstMonth, numberOfDays)) { throw new NotValidRecurringDateException("meeting",
"Not a valid meeting date", this.meetingDate); }
}
@@ -177,14 +179,15 @@ public class Meeting extends AbstractPersistable<Long> {
return this.meetingDate != null && newStartDate != null && getMeetingDateLocalDate().isBefore(newStartDate) ? true : false;
}
- private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final Date meetingDate) {
+ private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final Date meetingDate,
+ final boolean isSkipRepaymentOnFirstMonth, final int numberOfDays) {
final Calendar calendar = calendarInstance.getCalendar();
LocalDate meetingDateLocalDate = null;
if (meetingDate != null) {
meetingDateLocalDate = LocalDate.fromDateFields(meetingDate);
}
- if (meetingDateLocalDate == null || !calendar.isValidRecurringDate(meetingDateLocalDate)) { return false; }
+ if (meetingDateLocalDate == null || !calendar.isValidRecurringDate(meetingDateLocalDate, isSkipRepaymentOnFirstMonth, numberOfDays)) { return false; }
return true;
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
index a781129..5ed8e10 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java
@@ -31,11 +31,13 @@ import java.util.Collection;
import java.util.Date;
import java.util.Map;
+import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.calendar.data.CalendarData;
import org.apache.fineract.portfolio.calendar.domain.Calendar;
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
@@ -43,6 +45,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
import org.apache.fineract.portfolio.calendar.exception.CalendarInstanceNotFoundException;
import org.apache.fineract.portfolio.calendar.exception.CalendarNotFoundException;
+import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepository;
import org.apache.fineract.portfolio.group.domain.Group;
@@ -73,12 +76,15 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
private final ClientRepository clientRepository;
private final GroupRepository groupRepository;
private final FromJsonHelper fromApiJsonHelper;
+ private final ConfigurationDomainService configurationDomainService;
+ private final CalendarReadPlatformService calendarReadPlatformService;
@Autowired
public MeetingWritePlatformServiceJpaRepositoryImpl(final MeetingRepositoryWrapper meetingRepositoryWrapper,
final MeetingRepository meetingRepository, final MeetingDataValidator meetingDataValidator,
final CalendarInstanceRepository calendarInstanceRepository, final CalendarRepository calendarRepository,
- final ClientRepository clientRepository, final GroupRepository groupRepository, final FromJsonHelper fromApiJsonHelper) {
+ final ClientRepository clientRepository, final GroupRepository groupRepository, final FromJsonHelper fromApiJsonHelper,
+ final ConfigurationDomainService configurationDomainService, final CalendarReadPlatformService calendarReadPlatformService) {
this.meetingRepositoryWrapper = meetingRepositoryWrapper;
this.meetingRepository = meetingRepository;
this.meetingDataValidator = meetingDataValidator;
@@ -87,6 +93,8 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
this.clientRepository = clientRepository;
this.groupRepository = groupRepository;
this.fromApiJsonHelper = fromApiJsonHelper;
+ this.configurationDomainService = configurationDomainService;
+ this.calendarReadPlatformService = calendarReadPlatformService;
}
@Override
@@ -96,11 +104,25 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
final Date meetingDate = command.DateValueOfParameterNamed(meetingDateParamName);
final Boolean isTransactionDateOnNonMeetingDate = false;
+ /*Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+ }*/
try {
final CalendarInstance calendarInstance = getCalendarInstance(command);
// create new meeting
- final Meeting newMeeting = Meeting.createNew(calendarInstance, meetingDate, isTransactionDateOnNonMeetingDate);
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ if(calendarInstance != null){isSkipRepaymentOnFirstMonth = true;}
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+ }
+ final Meeting newMeeting = Meeting.createNew(calendarInstance, meetingDate, isTransactionDateOnNonMeetingDate, isSkipRepaymentOnFirstMonth, numberOfDays);
final Collection<ClientAttendance> clientsAttendance = getClientsAttendance(newMeeting, command);
if (clientsAttendance != null && !clientsAttendance.isEmpty()) {
@@ -214,9 +236,23 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
@Override
public CommandProcessingResult updateMeeting(final JsonCommand command) {
this.meetingDataValidator.validateForUpdate(command);
-
+
+ final CalendarInstance calendarInstance = getCalendarInstance(command);
+
+ // create new meeting
+ Boolean isSkipRepaymentOnFirstMonth = false;
+
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService
+ .isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if (isSkipRepaymentOnFirstMonthEnabled) {
+ if (calendarInstance != null) {
+ isSkipRepaymentOnFirstMonth = true;
+ numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ }
+ }
final Meeting meetingForUpdate = this.meetingRepositoryWrapper.findOneWithNotFoundDetection(command.entityId());
- final Map<String, Object> changes = meetingForUpdate.update(command);
+ final Map<String, Object> changes = meetingForUpdate.update(command, isSkipRepaymentOnFirstMonth, numberOfDays);
try {
if (!changes.isEmpty()) {
@@ -280,10 +316,23 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit
try {
final CalendarInstance calendarInstance = getCalendarInstance(command);
- final Meeting meeting = this.meetingRepository.findByCalendarInstanceIdAndMeetingDate(calendarInstance.getId(), meetingDate);
-
+
+ final Meeting meeting = this.meetingRepository
+ .findByCalendarInstanceIdAndMeetingDate(calendarInstance.getId(), meetingDate);
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService
+ .isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if (isSkipRepaymentOnFirstMonthEnabled) {
+ isSkipRepaymentOnFirstMonth = true;
+ if (isSkipRepaymentOnFirstMonth) {
+ numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate()
+ .intValue();
+ }
+ }
// create new meeting
- final Meeting newMeeting = (meeting != null) ? meeting : Meeting.createNew(calendarInstance, meetingDate, isTransactionDateOnNonMeetingDate);
+ final Meeting newMeeting = (meeting != null) ? meeting : Meeting.createNew(calendarInstance, meetingDate, isTransactionDateOnNonMeetingDate,
+ isSkipRepaymentOnFirstMonth, numberOfDays);
final Collection<ClientAttendance> clientsAttendance = getClientsAttendance(newMeeting, command);
if (clientsAttendance != null && !clientsAttendance.isEmpty()) {
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/resources/sql/migrations/core_db/V296__skip_repayment_on first-day_of_month.sql
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V296__skip_repayment_on first-day_of_month.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V296__skip_repayment_on first-day_of_month.sql
new file mode 100644
index 0000000..be3d7a2
--- /dev/null
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V296__skip_repayment_on first-day_of_month.sql
@@ -0,0 +1 @@
+insert into c_configuration(name,value,description) values("skip-repayment-on-first-day-of-month",14,"skipping repayment on first day of month");
\ No newline at end of file
[2/2] incubator-fineract git commit: Skip Repayment Date Falling On
First Day of Month
Posted by ra...@apache.org.
Skip Repayment Date Falling On First Day of Month
Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/bba8ca47
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/bba8ca47
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/bba8ca47
Branch: refs/heads/develop
Commit: bba8ca47be73d7663f8675a1fb061c434ef96797
Parents: 9c38078
Author: jinjurajan <ji...@confluxtechnologies.com>
Authored: Wed Mar 23 14:50:47 2016 +0530
Committer: jinjurajan <ji...@confluxtechnologies.com>
Committed: Wed Mar 23 14:50:47 2016 +0530
----------------------------------------------------------------------
.../SkipRepaymentOnMonthFirstTest.java | 151 +++++++++++++++++++
.../domain/ConfigurationDomainService.java | 7 +-
.../domain/ConfigurationDomainServiceJpa.java | 13 ++
.../portfolio/calendar/data/CalendarData.java | 4 +-
.../portfolio/calendar/domain/Calendar.java | 6 +-
.../calendar/domain/CalendarHistory.java | 5 +
.../service/CalendarReadPlatformService.java | 2 +
.../CalendarReadPlatformServiceImpl.java | 91 +++++++----
.../calendar/service/CalendarUtils.java | 93 +++++++++---
.../CollectionSheetReadPlatformServiceImpl.java | 40 ++++-
.../service/CenterReadPlatformServiceImpl.java | 16 +-
.../loanaccount/data/ScheduleGeneratorDTO.java | 18 ++-
.../portfolio/loanaccount/domain/Loan.java | 23 +--
.../domain/AbstractLoanScheduleGenerator.java | 5 +-
.../domain/DefaultScheduledDateGenerator.java | 4 +-
.../domain/LoanApplicationTerms.java | 47 ++++--
.../domain/LoanScheduleGenerator.java | 3 +-
.../service/LoanScheduleAssembler.java | 47 ++++--
.../domain/DefaultLoanReschedulerFactory.java | 7 +-
.../domain/LoanReschedulerFactory.java | 3 +-
...oanReschedulePreviewPlatformServiceImpl.java | 15 +-
...scheduleRequestWritePlatformServiceImpl.java | 10 +-
.../LoanEventApiJsonValidator.java | 5 +-
...onWritePlatformServiceJpaRepositoryImpl.java | 12 +-
.../loanaccount/service/LoanUtilService.java | 61 +++++++-
...anWritePlatformServiceJpaRepositoryImpl.java | 26 +++-
.../portfolio/meeting/domain/Meeting.java | 15 +-
...ngWritePlatformServiceJpaRepositoryImpl.java | 63 +++++++-
...96__skip_repayment_on first-day_of_month.sql | 1 +
29 files changed, 660 insertions(+), 133 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/SkipRepaymentOnMonthFirstTest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/SkipRepaymentOnMonthFirstTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/SkipRepaymentOnMonthFirstTest.java
new file mode 100644
index 0000000..b863b03
--- /dev/null
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/SkipRepaymentOnMonthFirstTest.java
@@ -0,0 +1,151 @@
+package org.apache.fineract.integrationtests;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import org.apache.fineract.integrationtests.common.CalendarHelper;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.GroupHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.builder.ResponseSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.specification.RequestSpecification;
+import com.jayway.restassured.specification.ResponseSpecification;
+
+import junit.framework.Assert;
+
+@SuppressWarnings({ "static-access", "rawtypes", "unchecked", "deprecation" })
+public class SkipRepaymentOnMonthFirstTest {
+
+ private ResponseSpecification responseSpec;
+ private RequestSpecification requestSpec;
+ private GlobalConfigurationHelper globalConfigurationHelper;
+ private LoanTransactionHelper loanTransactionHelper;
+ private CalendarHelper calendarHelper;
+
+ @Before
+ public void setup() {
+ Utils.initializeRESTAssured();
+ this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
+ this.requestSpec.header("Authorization",
+ "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+ this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+ }
+
+ @Test
+ public void testSkippingRepaymentOnFirstDayOfMonth() {
+ this.globalConfigurationHelper = new GlobalConfigurationHelper(this.requestSpec, this.responseSpec);
+
+ // Retrieving All Global Configuration details
+ final ArrayList<HashMap> globalConfig = this.globalConfigurationHelper
+ .getAllGlobalConfigurations(this.requestSpec, this.responseSpec);
+ Assert.assertNotNull(globalConfig);
+
+ String configName = "skip-repayment-on-first-day-of-month";
+ boolean newBooleanValue = true;
+
+ for (Integer configIndex = 0; configIndex < (globalConfig.size()); configIndex++) {
+ if (globalConfig.get(configIndex).get("name").equals(configName)) {
+ String configId = (globalConfig.get(configIndex).get("id")).toString();
+ Integer updateConfigId = this.globalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(
+ this.requestSpec, this.responseSpec, configId.toString(), newBooleanValue);
+ Assert.assertNotNull(updateConfigId);
+ break;
+ }
+ }
+
+ }
+
+ @Test
+ public void checkRepaymentSkipOnFirstDayOfMonth() {
+ this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
+
+ final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
+ Integer groupID = GroupHelper.createGroup(this.requestSpec, this.responseSpec, true);
+ groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(),
+ clientID.toString());
+ final String startDate = "15 September 2011";
+ final String frequency = "3"; // Monthly
+ final String interval = "1"; //Every One Moth
+ Integer calendarID = calendarHelper.createMeetingForGroup(requestSpec, responseSpec, groupID, startDate, frequency,
+ interval, null);
+ System.out.println("caladerId --------------------" + calendarID);
+ final Integer loanProductID = createLoanProduct();
+ final Integer loanID = applyForLoanApplication(groupID, loanProductID, calendarID, clientID);
+ System.out.println("loanID----" + loanID);
+ final ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec,
+ this.responseSpec, loanID);
+ verifyLoanRepaymentSchedule(loanSchedule);
+
+ }
+
+ private Integer createLoanProduct() {
+ System.out.println(
+ "------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
+ final String loanProductJSON = new LoanProductTestBuilder() //
+ .withPrincipal("12,000.00") //
+ .withNumberOfRepayments("4") //
+ .withRepaymentAfterEvery("1") //
+ .withRepaymentTypeAsMonth() //
+ .withinterestRatePerPeriod("1") //
+ .withInterestRateFrequencyTypeAsMonths() //
+ .withAmortizationTypeAsEqualInstallments() //
+ .withInterestTypeAsDecliningBalance() //
+ .build(null);
+ return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
+ }
+
+ private Integer applyForLoanApplication(final Integer groupID, final Integer loanProductID, Integer calendarID,
+ Integer clientID) {
+ System.out.println(
+ "--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
+ final String loanApplicationJSON = new LoanApplicationTestBuilder() //
+ .withPrincipal("12,000.00") //
+ .withLoanTermFrequency("4") //
+ .withLoanTermFrequencyAsMonths() //
+ .withNumberOfRepayments("4") //
+ .withRepaymentEveryAfter("1") //
+ .withRepaymentFrequencyTypeAsMonths() //
+ .withInterestRatePerPeriod("2") //
+ .withAmortizationTypeAsEqualInstallments() //
+ .withInterestTypeAsDecliningBalance() //
+ .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
+ .withExpectedDisbursementDate("01 October 2011") //
+ .withCalendarID(calendarID.toString()) //
+ .withSubmittedOnDate("01 October 2011") //
+ .withLoanType("jlg").build(clientID.toString(), groupID.toString(), loanProductID.toString(), null);
+ System.out.println(loanApplicationJSON);
+ return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
+ }
+
+ private void verifyLoanRepaymentSchedule(final ArrayList<HashMap> loanSchedule) {
+ System.out.println("--------------------VERIFYING THE REPAYMENT DATE--------------------------");
+ assertEquals("Checking for Repayment Date for 1st Month", new ArrayList<>(Arrays.asList(2011, 10, 15)),
+ loanSchedule.get(1).get("dueDate"));
+ System.out.println("Repayment Date for 1st Month--" + loanSchedule.get(1).get("dueDate"));
+
+ assertEquals("Checking for Repayment Date for 2nd Month", new ArrayList<>(Arrays.asList(2011, 11, 15)),
+ loanSchedule.get(2).get("dueDate"));
+ System.out.println("Repayment Date for 2nd Month--" + loanSchedule.get(2).get("dueDate"));
+
+ assertEquals("Checking for Repayment Date for 3rd Month", new ArrayList<>(Arrays.asList(2011, 12, 15)),
+ loanSchedule.get(3).get("dueDate"));
+ System.out.println("Repayment Date for 3rd Month--" + loanSchedule.get(3).get("dueDate"));
+
+ assertEquals("Checking for Repayment Date for 4th Month", new ArrayList<>(Arrays.asList(2012, 1, 15)),
+ loanSchedule.get(4).get("dueDate"));
+ System.out.println("Repayment Date for 4th Month--" + loanSchedule.get(4).get("dueDate"));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
index a466a95..b62aaf4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -70,6 +70,11 @@ public interface ConfigurationDomainService {
Date retrieveOrganisationStartDate();
boolean isPaymnetypeApplicableforDisbursementCharge();
-
+
boolean isInterestChargedFromDateSameAsDisbursementDate();
+
+ boolean isSkippingMeetingOnFirstDayOfMonthEnabled();
+
+ Long retreivePeroidInNumberOfDaysForSkipMeetingDate();
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index c957f94..db853d4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -235,6 +235,19 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
return property.isEnabled();
}
+
+ @Override
+ public boolean isSkippingMeetingOnFirstDayOfMonthEnabled() {
+ return this.globalConfigurationRepository.findOneByNameWithNotFoundDetection("skip-repayment-on-first-day-of-month").isEnabled();
+ }
+
+ @Override
+ public Long retreivePeroidInNumberOfDaysForSkipMeetingDate() {
+ final String propertyName = "skip-repayment-on-first-day-of-month";
+ final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
+ return property.getValue();
+
+ }
@Override
public boolean isInterestChargedFromDateSameAsDisbursementDate() {
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java
index 9368462..6151743 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarData.java
@@ -334,9 +334,9 @@ public class CalendarData {
return false;
}
- public boolean isValidRecurringDate(final LocalDate compareDate) {
+ public boolean isValidRecurringDate(final LocalDate compareDate, final Boolean isSkipMeetingOnFirstDay, final Integer numberOfDays) {
if (isBetweenStartAndEndDate(compareDate)) { return CalendarUtils.isValidRedurringDate(this.getRecurrence(), this.getStartDate(),
- compareDate); }
+ compareDate, isSkipMeetingOnFirstDay, numberOfDays); }
return false;
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
index 52d072d..8be58ec 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
@@ -560,15 +560,15 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
return recurrenceBuilder.toString();
}
- public boolean isValidRecurringDate(final LocalDate compareDate) {
+ public boolean isValidRecurringDate(final LocalDate compareDate, Boolean isSkipRepaymentOnFirstMonth, Integer numberOfDays) {
if (isBetweenStartAndEndDate(compareDate)) { return CalendarUtils.isValidRedurringDate(getRecurrence(), getStartDateLocalDate(),
- compareDate); }
+ compareDate, isSkipRepaymentOnFirstMonth, numberOfDays); }
// validate with history details.
for (CalendarHistory history : history()) {
if (history.isBetweenStartAndEndDate(compareDate)) { return CalendarUtils.isValidRedurringDate(history.getRecurrence(),
- history.getStartDateLocalDate(), compareDate); }
+ history.getStartDateLocalDate(), compareDate, isSkipRepaymentOnFirstMonth, numberOfDays); }
}
return false;
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarHistory.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarHistory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarHistory.java
index 4b193ab..93dc0bf 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarHistory.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarHistory.java
@@ -142,4 +142,9 @@ public class CalendarHistory extends AbstractPersistable<Long> {
public void updateEndDate(Date historyCalEndDate) {
this.endDate = historyCalEndDate;
}
+
+ public Calendar getCalendar() {
+ return this.calendar;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformService.java
index 4584cc4..5b7b28f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformService.java
@@ -50,4 +50,6 @@ public interface CalendarReadPlatformService {
LocalDate generateNextEligibleMeetingDateForCollection(CalendarData calendarData, MeetingData lastMeetingData);
+ Boolean isCalendarAssociatedWithEntity(final Long entityId, final Long calendarId, Long entityTypeId);
+
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
index 9c867c1..d86b7eb 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@@ -45,10 +46,12 @@ import org.springframework.util.CollectionUtils;
public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformService {
private final JdbcTemplate jdbcTemplate;
+ private final ConfigurationDomainService configurationDomainService;
@Autowired
- public CalendarReadPlatformServiceImpl(final RoutingDataSource dataSource) {
+ public CalendarReadPlatformServiceImpl(final RoutingDataSource dataSource, final ConfigurationDomainService configurationDomainService) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
+ this.configurationDomainService = configurationDomainService;
}
private static final class CalendarDataMapper implements RowMapper<CalendarData> {
@@ -237,11 +240,34 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
* till periodEndDate recurring dates will be generated.
*/
final LocalDate periodEndDate = this.getPeriodEndDate(calendarData.getEndDate(), tillDate);
-
- final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, periodStartDate, periodEndDate,
- maxCount);
- return recurringDates;
- }
+
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService
+ .isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if (isSkipRepaymentOnFirstMonthEnabled) {
+ numberOfDays = this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ }
+
+ final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, periodStartDate,
+ periodEndDate, maxCount, isSkipRepaymentOnFirstMonthEnabled, numberOfDays);
+ return recurringDates;
+ }
+
+ @Override
+ public Boolean isCalendarAssociatedWithEntity(final Long entityId, final Long calendarId, final Long entityTypeId) {
+ String query = "Select COUNT(*) from m_calendar_instance ci where ci.entity_id = ? and ci.calendar_id = ? and "
+ + " ci.entity_type_enum = ?";
+ try {
+ int calendarInstaneId = this.jdbcTemplate.queryForObject(query,
+ new Object[] { entityId, calendarId, entityTypeId }, Integer.class);
+ if (calendarInstaneId > 0) {
+ return true;
+ }
+ return false;
+ } catch (final EmptyResultDataAccessException e) {
+ return false;
+ }
+ }
private LocalDate getSeedDate(LocalDate date) {
return date;
@@ -301,26 +327,37 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
* which is still on Tuesday and next collection sheet date should be on
* 18th of Oct as per current calendar
*/
- if (lastMeetingDate != null && !calendarData.isBetweenStartAndEndDate(lastMeetingDate)
- && !calendarData.isBetweenStartAndEndDate(DateUtils.getLocalDateOfTenant())) {
- applicableCalendarData = this.retrieveApplicableCalendarFromHistory(calendarData.getId(), lastMeetingDate);
- nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(), lastMeetingDate);
- }
-
- /**
- * If nextEligibleMeetingDate is on or after current calendar startdate
- * then regenerate the nextEligible meeting date based on
- */
- if (nextEligibleMeetingDate == null) {
- final LocalDate seedDate = (lastMeetingDate != null) ? lastMeetingDate : calendarData.getStartDate();
- nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(), seedDate);
- } else if (calendarData.isBetweenStartAndEndDate(nextEligibleMeetingDate)) {
- nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(),
- calendarData.getStartDate());
- }
-
- return nextEligibleMeetingDate;
- }
+
+
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService
+ .isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if (isSkipRepaymentOnFirstMonthEnabled) {
+ numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ }
+
+ if (lastMeetingDate != null && !calendarData.isBetweenStartAndEndDate(lastMeetingDate)
+ && !calendarData.isBetweenStartAndEndDate(DateUtils.getLocalDateOfTenant())) {
+ applicableCalendarData = this.retrieveApplicableCalendarFromHistory(calendarData.getId(), lastMeetingDate);
+ nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(),
+ lastMeetingDate, isSkipRepaymentOnFirstMonthEnabled, numberOfDays);
+ }
+
+ /**
+ * If nextEligibleMeetingDate is on or after current calendar startdate
+ * then regenerate the nextEligible meeting date based on
+ */
+ if (nextEligibleMeetingDate == null) {
+ final LocalDate seedDate = (lastMeetingDate != null) ? lastMeetingDate : calendarData.getStartDate();
+ nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(),
+ seedDate, isSkipRepaymentOnFirstMonthEnabled, numberOfDays);
+ } else if (calendarData.isBetweenStartAndEndDate(nextEligibleMeetingDate)) {
+ nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(),
+ calendarData.getStartDate(), isSkipRepaymentOnFirstMonthEnabled, numberOfDays);
+ }
+
+ return nextEligibleMeetingDate;
+ }
@Override
public Collection<CalendarData> updateWithRecurringDates(final Collection<CalendarData> calendarsData) {
@@ -465,4 +502,6 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
lastUpdatedByUserName);
}
}
+
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/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 ce42c0a..a525606 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
@@ -133,19 +133,23 @@ public class CalendarUtils {
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate,
final LocalDate periodStartDate, final LocalDate periodEndDate) {
final int maxCount = 10;// Default number of recurring dates
- return getRecurringDates(recurringRule, seedDate, periodStartDate, periodEndDate, maxCount);
+ boolean isSkipRepaymentOnFirstdayofMonth = false;
+ final Integer numberofDays = 0;
+ return getRecurringDates(recurringRule, seedDate, periodStartDate, periodEndDate, maxCount, isSkipRepaymentOnFirstdayofMonth,
+ numberofDays);
}
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate,
- final LocalDate periodStartDate, final LocalDate periodEndDate, final int maxCount) {
+ final LocalDate periodStartDate, final LocalDate periodEndDate, final int maxCount, boolean isSkippMeetingOnFirstDay,
+ final Integer numberOfDays) {
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
- return getRecurringDates(recur, seedDate, periodStartDate, periodEndDate, maxCount);
+ return getRecurringDates(recur, seedDate, periodStartDate, periodEndDate, maxCount, isSkippMeetingOnFirstDay, numberOfDays);
}
private static Collection<LocalDate> getRecurringDates(final Recur recur, final LocalDate seedDate, final LocalDate periodStartDate,
- final LocalDate periodEndDate, final int maxCount) {
+ final LocalDate periodEndDate, final int maxCount, boolean isSkippMeetingOnFirstDay, final Integer numberOfDays) {
if (recur == null) { return null; }
final Date seed = convertToiCal4JCompatibleDate(seedDate);
final DateTime periodStart = new DateTime(periodStartDate.toDate());
@@ -153,11 +157,12 @@ public class CalendarUtils {
final Value value = new Value(Value.DATE.getValue());
final DateList recurringDates = recur.getDates(seed, periodStart, periodEnd, value, maxCount);
- return convertToLocalDateList(recurringDates, seedDate, getMeetingPeriodFrequencyType(recur));
+ return convertToLocalDateList(recurringDates, seedDate, getMeetingPeriodFrequencyType(recur), isSkippMeetingOnFirstDay,
+ numberOfDays);
}
private static Collection<LocalDate> convertToLocalDateList(final DateList dates, final LocalDate seedDate,
- final PeriodFrequencyType frequencyType) {
+ final PeriodFrequencyType frequencyType, boolean isSkippMeetingOnFirstDay, final Integer numberOfDays) {
final Collection<LocalDate> recurringDates = new ArrayList<>();
@@ -167,9 +172,30 @@ public class CalendarUtils {
recurringDates.add(adjustDate(new LocalDate(date), seedDate, frequencyType));
}
+ if (isSkippMeetingOnFirstDay) { return skipMeetingOnFirstdayOfMonth(recurringDates, numberOfDays); }
+
return recurringDates;
}
+ private static Collection<LocalDate> skipMeetingOnFirstdayOfMonth(final Collection<LocalDate> recurringDates, final Integer numberOfDays) {
+ final Collection<LocalDate> adjustedRecurringDates = new ArrayList<>();
+
+ for (@SuppressWarnings("rawtypes")
+ final Iterator iterator = recurringDates.iterator(); iterator.hasNext();) {
+ LocalDate recuringDate = (LocalDate) iterator.next();
+ adjustedRecurringDates.add(adjustRecurringDate(recuringDate, numberOfDays));
+ }
+ return adjustedRecurringDates;
+ }
+
+ public static LocalDate adjustRecurringDate(final LocalDate recuringDate, final Integer numberOfDays) {
+ if (recuringDate.getDayOfMonth() == 1) {
+ LocalDate adjustedRecurringDate = recuringDate.plusDays(numberOfDays);
+ return adjustedRecurringDate;
+ }
+ return recuringDate;
+ }
+
public static Recur getICalRecur(final String recurringRule) {
// Construct RRule
@@ -269,14 +295,30 @@ public class CalendarUtils {
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
if (recur == null) { return false; }
+ final boolean isSkipRepaymentonFirstDayOfMonth = false;
+ final int numberOfDays = 0;
+ return isValidRecurringDate(recur, seedDate, date, isSkipRepaymentonFirstDayOfMonth, numberOfDays);
+ }
+
+ public static boolean isValidRedurringDate(final String recurringRule, final LocalDate seedDate, final LocalDate date,
+ boolean isSkipRepaymentonFirstDayOfMonth, final Integer numberOfDays) {
+
+ final Recur recur = CalendarUtils.getICalRecur(recurringRule);
+ if (recur == null) { return false; }
- return isValidRecurringDate(recur, seedDate, date);
+ return isValidRecurringDate(recur, seedDate, date, isSkipRepaymentonFirstDayOfMonth, numberOfDays);
}
- public static boolean isValidRecurringDate(final Recur recur, final LocalDate seedDate, final LocalDate date) {
+ public static boolean isValidRecurringDate(final Recur recur, final LocalDate seedDate, final LocalDate date,
+ boolean isSkipRepaymentonFirstDayOfMonth, final int numberOfDays) {
+ LocalDate startDate = date;
+ if (isSkipRepaymentonFirstDayOfMonth && date.getDayOfMonth() == (numberOfDays + 1)) {
+ startDate = startDate.minusDays(numberOfDays);
+ }
+ final Collection<LocalDate> recurDate = getRecurringDates(recur, seedDate, startDate, date.plusDays(1), 1,
+ isSkipRepaymentonFirstDayOfMonth, numberOfDays);
- final Collection<LocalDate> recurDate = getRecurringDates(recur, seedDate, date, date.plusDays(1), 1);
- return (recurDate == null || recurDate.isEmpty()) ? false : true;
+ return (recurDate == null || recurDate.isEmpty()) ? false : recurDate.contains(date);
}
public static enum DayNameEnum {
@@ -359,12 +401,13 @@ public class CalendarUtils {
}
public static LocalDate getFirstRepaymentMeetingDate(final Calendar calendar, final LocalDate disbursementDate,
- final Integer loanRepaymentInterval, final String frequency) {
+ final Integer loanRepaymentInterval, final String frequency, boolean isSkipRepaymentOnFirstDayOfMonth,
+ final Integer numberOfDays) {
final Recur recur = CalendarUtils.getICalRecur(calendar.getRecurrence());
if (recur == null) { return null; }
LocalDate startDate = disbursementDate;
final LocalDate seedDate = calendar.getStartDateLocalDate();
- if (isValidRedurringDate(calendar.getRecurrence(), seedDate, startDate)) {
+ if (isValidRedurringDate(calendar.getRecurrence(), seedDate, startDate, isSkipRepaymentOnFirstDayOfMonth, numberOfDays)) {
startDate = startDate.plusDays(1);
}
// Recurring dates should follow loanRepaymentInterval.
@@ -386,25 +429,32 @@ public class CalendarUtils {
}
final LocalDate firstRepaymentDate = getNextRecurringDate(recur, seedDate, startDate);
+ if (isSkipRepaymentOnFirstDayOfMonth && firstRepaymentDate.getDayOfMonth() == 1) { return adjustRecurringDate(firstRepaymentDate,
+ numberOfDays); }
return firstRepaymentDate;
}
public static LocalDate getNewRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate,
- final LocalDate oldRepaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays) {
+ final LocalDate oldRepaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays,
+ final boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays) {
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
if (recur == null) { return null; }
- if (isValidRecurringDate(recur, seedDate, oldRepaymentDate)) { return oldRepaymentDate; }
- return getNextRepaymentMeetingDate(recurringRule, seedDate, oldRepaymentDate, loanRepaymentInterval, frequency, workingDays);
+ if (isValidRecurringDate(recur, seedDate, oldRepaymentDate, isSkipRepaymentOnFirstDayOfMonth, numberOfDays)) { return oldRepaymentDate; }
+ LocalDate nextRapaymentDate = getNextRepaymentMeetingDate(recurringRule, seedDate, oldRepaymentDate, loanRepaymentInterval,
+ frequency, workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays);
+
+ return nextRapaymentDate;
}
public static LocalDate getNextRepaymentMeetingDate(final String recurringRule, final LocalDate seedDate,
- final LocalDate repaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays) {
+ final LocalDate repaymentDate, final Integer loanRepaymentInterval, final String frequency, final WorkingDays workingDays,
+ boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays) {
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
if (recur == null) { return null; }
LocalDate tmpDate = repaymentDate;
- if (isValidRecurringDate(recur, seedDate, repaymentDate)) {
+ if (isValidRecurringDate(recur, seedDate, repaymentDate, isSkipRepaymentOnFirstDayOfMonth, numberOfDays)) {
tmpDate = repaymentDate.plusDays(1);
}
/*
@@ -430,6 +480,10 @@ public class CalendarUtils {
final LocalDate nextRepaymentDate = getNextRecurringDate(recur, seedDate, newRepaymentDate);
newRepaymentDate = WorkingDaysUtil.getOffSetDateIfNonWorkingDay(newRepaymentDate, nextRepaymentDate, workingDays);
+ if (isSkipRepaymentOnFirstDayOfMonth) {
+ LocalDate newRepaymentDateTemp = adjustRecurringDate(newRepaymentDate, numberOfDays);
+ return WorkingDaysUtil.getOffSetDateIfNonWorkingDay(newRepaymentDateTemp, nextRepaymentDate, workingDays);
+ }
return newRepaymentDate;
}
@@ -500,12 +554,13 @@ public class CalendarUtils {
return sqlCalendarTypeOptions;
}
- public static LocalDate getRecentEligibleMeetingDate(final String recurringRule, final LocalDate seedDate) {
+ public static LocalDate getRecentEligibleMeetingDate(final String recurringRule, final LocalDate seedDate,
+ final boolean isSkipMeetingOnFirstDay, final Integer numberOfDays) {
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
if (recur == null) { return null; }
- if (isValidRecurringDate(recur, seedDate, currentDate)) { return currentDate; }
+ if (isValidRecurringDate(recur, seedDate, currentDate, isSkipMeetingOnFirstDay, numberOfDays)) { return currentDate; }
if (recur.getFrequency().equals(Recur.DAILY)) {
currentDate = currentDate.plusDays(recur.getInterval());
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
index 76d0c09..247d426 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java
@@ -36,6 +36,7 @@ import java.util.Set;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
+import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
@@ -44,8 +45,10 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.calendar.domain.Calendar;
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
+import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
import org.apache.fineract.portfolio.calendar.domain.CalendarRepositoryWrapper;
import org.apache.fineract.portfolio.calendar.exception.NotValidRecurringDateException;
+import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
import org.apache.fineract.portfolio.collectionsheet.data.IndividualClientData;
import org.apache.fineract.portfolio.collectionsheet.data.IndividualCollectionSheetData;
import org.apache.fineract.portfolio.collectionsheet.data.IndividualCollectionSheetLoanFlatData;
@@ -91,6 +94,9 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
private final MandatorySavingsCollectionsheetExtractor mandatorySavingsExtractor = new MandatorySavingsCollectionsheetExtractor();
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
+ private final CalendarReadPlatformService calendarReadPlatformService;
+ private final ConfigurationDomainService configurationDomainService;
+ private final CalendarInstanceRepository calendarInstanceRepository;
@Autowired
public CollectionSheetReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
@@ -98,7 +104,9 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final CollectionSheetGenerateCommandFromApiJsonDeserializer collectionSheetGenerateCommandFromApiJsonDeserializer,
final CalendarRepositoryWrapper calendarRepositoryWrapper,
final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService,
- final CodeValueReadPlatformService codeValueReadPlatformService, final PaymentTypeReadPlatformService paymentTypeReadPlatformService) {
+ final CodeValueReadPlatformService codeValueReadPlatformService, final PaymentTypeReadPlatformService paymentTypeReadPlatformService,
+ final CalendarReadPlatformService calendarReadPlatformService, final ConfigurationDomainService configurationDomainService,
+ final CalendarInstanceRepository calendarInstanceRepository) {
this.context = context;
this.centerReadPlatformService = centerReadPlatformService;
this.namedParameterjdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
@@ -108,6 +116,9 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
this.attendanceDropdownReadPlatformService = attendanceDropdownReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
+ this.calendarReadPlatformService = calendarReadPlatformService;
+ this.configurationDomainService = configurationDomainService;
+ this.calendarInstanceRepository = calendarInstanceRepository;
}
/*
@@ -320,20 +331,39 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final Calendar calendar = this.calendarRepositoryWrapper.findOneWithNotFoundDetection(calendarId);
// check if transaction against calendar effective from date
+
+ final GroupGeneralData group = this.groupReadPlatformService.retrieveOne(groupId);
+
+ // entityType should be center if it's within a center
+ final CalendarEntityType entityType = (group.isChildGroup()) ? CalendarEntityType.CENTERS : CalendarEntityType.GROUPS;
+
+ Long entityId = null;
+ if(group.isChildGroup()){
+ entityId = group.getParentId();
+ }else{
+ entityId = group.getId();
+ }
- if (!calendar.isValidRecurringDate(transactionDate)) { throw new NotValidRecurringDateException("collectionsheet", "The date '"
+ Boolean isSkipMeetingOnFirstDay = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ numberOfDays = this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ isSkipMeetingOnFirstDay = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(entityId, calendar.getId(),
+ entityType.getValue().longValue());
+ }
+
+ if (!calendar.isValidRecurringDate(transactionDate, isSkipMeetingOnFirstDay, numberOfDays)) { throw new NotValidRecurringDateException("collectionsheet", "The date '"
+ transactionDate + "' is not a valid meeting date.", transactionDate); }
final AppUser currentUser = this.context.authenticatedUser();
final String hierarchy = currentUser.getOffice().getHierarchy();
final String officeHierarchy = hierarchy + "%";
- final GroupGeneralData group = this.groupReadPlatformService.retrieveOne(groupId);
+
final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper();
- // entityType should be center if it's within a center
- final CalendarEntityType entityType = (group.isChildGroup()) ? CalendarEntityType.CENTERS : CalendarEntityType.GROUPS;
final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("dueDate", transactionDateStr)
.addValue("groupId", group.getId()).addValue("officeHierarchy", officeHierarchy)
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
index 716d5ec..f19148f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
@@ -31,6 +31,7 @@ import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
+import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.ApiParameterHelper;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
@@ -50,6 +51,7 @@ import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
import org.apache.fineract.portfolio.calendar.data.CalendarData;
import org.apache.fineract.portfolio.calendar.service.CalendarEnumerations;
+import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
import org.apache.fineract.portfolio.client.data.ClientData;
import org.apache.fineract.portfolio.client.domain.ClientEnumerations;
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
@@ -79,6 +81,8 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
private final OfficeReadPlatformService officeReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
+ private final ConfigurationDomainService configurationDomainService;
+ private final CalendarReadPlatformService calendarReadPlatformService;
// data mappers
private final CenterDataMapper centerMapper = new CenterDataMapper();
@@ -92,7 +96,8 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
public CenterReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService,
final StaffReadPlatformService staffReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService,
- final PaginationParametersDataValidator paginationParametersDataValidator) {
+ final PaginationParametersDataValidator paginationParametersDataValidator, final ConfigurationDomainService configurationDomainService,
+ final CalendarReadPlatformService calendarReadPlatformService) {
this.context = context;
this.clientReadPlatformService = clientReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
@@ -100,6 +105,8 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
this.staffReadPlatformService = staffReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.paginationParametersDataValidator = paginationParametersDataValidator;
+ this.configurationDomainService = configurationDomainService;
+ this.calendarReadPlatformService = calendarReadPlatformService;
}
// 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where
@@ -521,8 +528,13 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
Collection<StaffCenterData> staffCenterDataArray = new ArrayList<>();
Boolean flag = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if (isSkipRepaymentOnFirstMonthEnabled) {
+ numberOfDays = this.configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
+ }
for (CenterData centerData : centerDataArray) {
- if (centerData.getCollectionMeetingCalendar().isValidRecurringDate(new LocalDate(meetingDate))) {
+ if (centerData.getCollectionMeetingCalendar().isValidRecurringDate(new LocalDate(meetingDate), isSkipRepaymentOnFirstMonthEnabled, numberOfDays)) {
if (staffCenterDataArray.size() <= 0) {
Collection<CenterData> meetingFallCenter = new ArrayList<>();
meetingFallCenter.add(centerData);
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
index 7ffe6bd..ee6461a 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
@@ -40,14 +40,18 @@ public class ScheduleGeneratorDTO {
final Calendar calendar;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper;
final Boolean isInterestChargedFromDateAsDisbursementDateEnabled;
+ final Integer numberOfdays;
+ final boolean isSkipRepaymentOnFirstDayofMonth;
+
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO,
- final Calendar calendar, final CalendarHistoryDataWrapper calendarHistoryDataWrapper,
- final Boolean isInterestChargedFromDateAsDisbursementDateEnabled) {
+ final Calendar calendar, final CalendarHistoryDataWrapper calendarHistoryDataWrapper,
+ final Boolean isInterestChargedFromDateAsDisbursementDateEnabled, final Integer numberOfdays, final boolean isSkipRepaymentOnFirstDayofMonth) {
+
this.loanScheduleFactory = loanScheduleFactory;
this.applicationCurrency = applicationCurrency;
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
@@ -61,6 +65,8 @@ public class ScheduleGeneratorDTO {
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
this.isInterestChargedFromDateAsDisbursementDateEnabled = isInterestChargedFromDateAsDisbursementDateEnabled;
+ this.numberOfdays = numberOfdays;
+ this.isSkipRepaymentOnFirstDayofMonth = isSkipRepaymentOnFirstDayofMonth;
}
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
@@ -123,4 +129,12 @@ public class ScheduleGeneratorDTO {
return this.isInterestChargedFromDateAsDisbursementDateEnabled;
}
+ public Integer getNumberOfdays() {
+ return numberOfdays;
+ }
+
+ public boolean isSkipRepaymentOnFirstDayofMonth() {
+ return isSkipRepaymentOnFirstDayofMonth;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index ebc2b6c..9f235ba 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -4170,7 +4170,8 @@ public class Loan extends AbstractPersistable<Long> {
public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule,
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
- final Boolean reschedulebasedOnMeetingDates, final LocalDate presentMeetingDate, final LocalDate newMeetingDate) {
+ final Boolean reschedulebasedOnMeetingDates, final LocalDate presentMeetingDate, final LocalDate newMeetingDate,
+ final boolean isSkipRepaymentonfirstdayofmonth, final Integer numberofDays) {
// first repayment's from date is same as disbursement date.
/*
@@ -4202,7 +4203,7 @@ public class Loan extends AbstractPersistable<Long> {
// getNewRepaymentMeetingDate method returns next meeting
// date and not the same as tmpFromDate
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, tmpFromDate, tmpFromDate.plusDays(1),
- loanRepaymentInterval, frequency, workingDays);
+ loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
}
if (isHolidayEnabled) {
@@ -4230,7 +4231,8 @@ public class Loan extends AbstractPersistable<Long> {
}
public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule,
- final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
+ final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
+ final boolean isSkipRepaymentonfirstdayofmonth, final Integer numberofDays) {
// first repayment's from date is same as disbursement date.
LocalDate tmpFromDate = getDisbursementDate();
@@ -4250,14 +4252,14 @@ public class Loan extends AbstractPersistable<Long> {
if (oldDueDate.isAfter(seedDate) && oldDueDate.isAfter(DateUtils.getLocalDateOfTenant())) {
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, seedDate, oldDueDate, loanRepaymentInterval,
- frequency, workingDays);
+ frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType,
loanRepaymentInterval, tmpFromDate);
if (newRepaymentDate.isAfter(maxDateLimitForNewRepayment)) {
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, seedDate, tmpFromDate,
- loanRepaymentInterval, frequency, workingDays);
+ loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
}
if (isHolidayEnabled) {
@@ -5046,9 +5048,9 @@ public class Loan extends AbstractPersistable<Long> {
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
- calendar = scheduleGeneratorDTO.getCalendar();
- calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
}
+ calendar = scheduleGeneratorDTO.getCalendar();
+ calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
BigDecimal annualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
FloatingRateDTO floatingRateDTO = scheduleGeneratorDTO.getFloatingRateDTO();
@@ -5066,7 +5068,8 @@ public class Loan extends AbstractPersistable<Long> {
this.maxOutstandingLoanBalance, interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
- rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper);
+ rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper,
+ scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth());
return loanApplicationTerms;
}
@@ -5230,7 +5233,7 @@ public class Loan extends AbstractPersistable<Long> {
@SuppressWarnings({ "unused" })
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar,
- final FloatingRateDTO floatingRateDTO) {
+ final FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) {
LoanProduct loanProduct = loanProduct();
// LoanProductRelatedDetail loanProductRelatedDetail =
// getLoanRepaymentScheduleDetail();
@@ -5310,7 +5313,7 @@ public class Loan extends AbstractPersistable<Long> {
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
- calendarHistoryDataWrapper);
+ calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst);
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/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 e60a749..8024652 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
@@ -57,6 +57,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.Schedule
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
+import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
import org.joda.time.Days;
import org.joda.time.LocalDate;
@@ -1581,7 +1582,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO,
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar,
- final FloatingRateDTO floatingRateDTO) {
+ final FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) {
final Loan loan = loanRescheduleRequest.getLoan();
final LoanSummary loanSummary = loan.getSummary();
@@ -1723,7 +1724,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// get the loan application terms from the Loan object
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency, restCalendarInstance,
- compoundingCalendarInstance, loanCalendar, floatingRateDTO);
+ compoundingCalendarInstance, loanCalendar, floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays);
// for applying variations
Collection<LoanTermVariationsData> loanTermVariations = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/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 a23f1e4..7afc002 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
@@ -92,9 +92,11 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
dueRepaymentPeriodDate = CalendarUtils.getNewRepaymentMeetingDate(reccuringString, seedDate, lastRepaymentDate.plusDays(1),
loanApplicationTerms.getRepaymentEvery(),
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(loanApplicationTerms.getLoanTermPeriodFrequencyType()),
- holidayDetailDTO.getWorkingDays());
+ holidayDetailDTO.getWorkingDays(), loanApplicationTerms.isSkipRepaymentOnFirstDayofMonth(),
+ loanApplicationTerms.getNumberOfdays());
}
}
+
return dueRepaymentPeriodDate;
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/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 e4f1555..d2341ba 100755
--- 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,6 +183,10 @@ public final class LoanApplicationTerms {
private final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled;
+ private final Integer numberOfDays;
+
+ private final boolean isSkipRepaymentOnFirstDayOfMonth;
+
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
@@ -199,9 +203,11 @@ public final class LoanApplicationTerms {
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
- BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations, Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled) {
+ BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations, Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled,
+ final Integer numberOfdays,boolean isSkipRepaymentOnFirstDayofMonth) {
- final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
+
+ final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
@@ -214,7 +220,8 @@ public final class LoanApplicationTerms {
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
- isInterestChargedFromDateSameAsDisbursalDateEnabled);
+ isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfdays, isSkipRepaymentOnFirstDayofMonth);
+
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -229,7 +236,7 @@ public final class LoanApplicationTerms {
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount, BigDecimal annualNominalInterestRate,
- List<LoanTermVariationsData> loanTermVariations) {
+ List<LoanTermVariationsData> loanTermVariations, final Integer numberOfdays, final boolean isSkipRepaymentOnFirstDayofMonth) {
final Calendar loanCalendar = null;
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -239,7 +246,7 @@ public final class LoanApplicationTerms {
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType, restCalendarInstance,
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations,
- calendarHistoryDataWrapper);
+ calendarHistoryDataWrapper, numberOfdays, isSkipRepaymentOnFirstDayofMonth);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -255,7 +262,8 @@ public final class LoanApplicationTerms {
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount,
BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
- final CalendarHistoryDataWrapper calendarHistoryDataWrapper) {
+ final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final Integer numberOfdays,
+ final boolean isSkipRepaymentOnFirstDayofMonth) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -289,7 +297,7 @@ public final class LoanApplicationTerms {
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
- isInterestChargedFromDateSameAsDisbursalDateEnabled);
+ isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfdays, isSkipRepaymentOnFirstDayofMonth);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -302,7 +310,8 @@ public final class LoanApplicationTerms {
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy, final Calendar loanCalendar,
- BigDecimal approvedAmount, final BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations) {
+ BigDecimal approvedAmount, final BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
+ Integer numberOfdays, boolean isSkipRepaymentOnFirstDayofMonth) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -344,7 +353,8 @@ public final class LoanApplicationTerms {
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
- isInterestChargedFromDateSameAsDisbursalDateEnabled);
+ isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfdays, isSkipRepaymentOnFirstDayofMonth);
+
}
public static LoanApplicationTerms assembleFrom(final LoanApplicationTerms applicationTerms,
@@ -367,8 +377,9 @@ public final class LoanApplicationTerms {
applicationTerms.principalThresholdForLastInstalment, applicationTerms.installmentAmountInMultiplesOf,
applicationTerms.preClosureInterestCalculationStrategy, applicationTerms.loanCalendar,
applicationTerms.approvedPrincipal.getAmount(), loanTermVariations, applicationTerms.calendarHistoryDataWrapper,
- applicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled);
- }
+ applicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled, applicationTerms.numberOfDays,
+ applicationTerms.isSkipRepaymentOnFirstDayOfMonth);
+ }
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
@@ -389,7 +400,9 @@ public final class LoanApplicationTerms {
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar,
BigDecimal approvedAmount, List<LoanTermVariationsData> loanTermVariations,
- final CalendarHistoryDataWrapper calendarHistoryDataWrapper, Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled) {
+ final CalendarHistoryDataWrapper calendarHistoryDataWrapper, Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled,
+ final Integer numberOfdays, final boolean isSkipRepaymentOnFirstDayofMonth) {
+
this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
@@ -436,6 +449,8 @@ public final class LoanApplicationTerms {
this.principalThresholdForLastInstalment = principalThresholdForLastInstalment;
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
this.preClosureInterestCalculationStrategy = preClosureInterestCalculationStrategy;
+ this.isSkipRepaymentOnFirstDayOfMonth = isSkipRepaymentOnFirstDayofMonth;
+ this.numberOfDays = numberOfdays;
this.loanCalendar = loanCalendar;
this.approvedPrincipal = Money.of(principal.getCurrency(), approvedAmount);
@@ -1454,4 +1469,12 @@ public final class LoanApplicationTerms {
return this.isInterestChargedFromDateSameAsDisbursalDateEnabled;
}
+ public Integer getNumberOfdays() {
+ return numberOfDays;
+ }
+
+ public boolean isSkipRepaymentOnFirstDayofMonth() {
+ return isSkipRepaymentOnFirstDayOfMonth;
+ }
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
index 822632d..ae67451 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
@@ -54,5 +54,6 @@ public interface LoanScheduleGenerator {
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance,
- CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, FloatingRateDTO floatingRateDTO);
+ CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, FloatingRateDTO floatingRateDTO,
+ final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays);
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index b5486f7..fa29f9e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -270,14 +270,29 @@ public class LoanScheduleAssembler {
* If it is JLG loan/Group Loan synched with a meeting, then make sure
* first repayment falls on meeting date
*/
+ final Long groupId = this.fromApiJsonHelper.extractLongNamed("groupId", element);
+ Group group = null;
+ if(groupId != null){
+ group = this.groupRepository.findOneWithNotFoundDetection(groupId);
+ }
+
+ Boolean isSkipMeetingOnFirstDay = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ isSkipMeetingOnFirstDay = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(group, calendar);
+ if(isSkipMeetingOnFirstDay) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+ }
if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendar != null) {
- validateRepaymentsStartDateWithMeetingDates(calculatedRepaymentsStartingFromDate, calendar);
+ validateRepaymentsStartDateWithMeetingDates(calculatedRepaymentsStartingFromDate, calendar, isSkipMeetingOnFirstDay,
+ numberOfDays);
+
/*
* If disbursement is synced on meeting, make sure disbursement date
* is on a meeting date
*/
if (synchDisbursement != null && synchDisbursement.booleanValue()) {
- validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar);
+ validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar, isSkipMeetingOnFirstDay, numberOfDays);
}
}
@@ -397,8 +412,8 @@ public class LoanScheduleAssembler {
maxOutstandingBalance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
recalculationFrequencyType, restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType,
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(),
- calendar, BigDecimal.ZERO, loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled);
- }
+ calendar, BigDecimal.ZERO, loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled,numberOfDays, isSkipMeetingOnFirstDay);
+}
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
final PeriodFrequencyType repaymentPeriodFrequencyType, final LocalDate expectedDisbursementDate) {
@@ -468,19 +483,20 @@ public class LoanScheduleAssembler {
return disbursementDatas;
}
- private void validateRepaymentsStartDateWithMeetingDates(final LocalDate repaymentsStartingFromDate, final Calendar calendar) {
+ private void validateRepaymentsStartDateWithMeetingDates(final LocalDate repaymentsStartingFromDate, final Calendar calendar,
+ boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays) {
if (repaymentsStartingFromDate != null
&& !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(),
- repaymentsStartingFromDate)) {
+ repaymentsStartingFromDate, isSkipRepaymentOnFirstDayOfMonth, numberOfDays)) {
final String errorMessage = "First repayment date '" + repaymentsStartingFromDate + "' do not fall on a meeting date";
throw new LoanApplicationDateException("first.repayment.date.do.not.match.meeting.date", errorMessage,
repaymentsStartingFromDate);
}
}
- public void validateDisbursementDateWithMeetingDates(final LocalDate expectedDisbursementDate, final Calendar calendar) {
+ public void validateDisbursementDateWithMeetingDates(final LocalDate expectedDisbursementDate, final Calendar calendar, Boolean isSkipRepaymentOnFirstMonth, Integer numberOfDays) {
// disbursement date should fall on a meeting date
- if (!calendar.isValidRecurringDate(expectedDisbursementDate)) {
+ if (!calendar.isValidRecurringDate(expectedDisbursementDate, isSkipRepaymentOnFirstMonth, numberOfDays)) {
final String errorMessage = "Expected disbursement date '" + expectedDisbursementDate + "' do not fall on a meeting date";
throw new LoanApplicationDateException("disbursement.date.do.not.match.meeting.date", errorMessage, expectedDisbursementDate);
}
@@ -747,6 +763,13 @@ public class LoanScheduleAssembler {
if (loanCalendarInstance != null) {
loanCalendar = loanCalendarInstance.getCalendar();
}
+ Boolean isSkipRepaymentOnFirstMonth = false;
+ Integer numberOfDays = 0;
+ boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ if(isSkipRepaymentOnFirstMonthEnabled){
+ isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar);
+ if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
+ }
final Integer minGap = installmentConfig.getMinimumGap();
final Integer maxGap = installmentConfig.getMaximumGap();
@@ -760,7 +783,8 @@ public class LoanScheduleAssembler {
.value(duedate)
.failWithCodeNoParameterAddedToErrorCode("variable.schedule.date.must.be.in.min.max.range",
"Loan schedule date invalid");
- } else if (loanCalendar != null && !actualDueDates.contains(duedate) && !loanCalendar.isValidRecurringDate(duedate)) {
+ } else if (loanCalendar != null && !actualDueDates.contains(duedate) && !loanCalendar.isValidRecurringDate(duedate,
+ isSkipRepaymentOnFirstMonth, numberOfDays)) {
baseDataValidator
.reset()
.value(duedate)
@@ -1004,10 +1028,11 @@ public class LoanScheduleAssembler {
private LocalDate deriveFirstRepaymentDateForJLGLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar) {
-
+ boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
+ int numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
- refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency);
+ refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment : deriveFirstRepaymentDateForJLGLoans(
repaymentEvery, expectedDisbursementDate, derivedFirstRepayment, repaymentPeriodFrequencyType,
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
index d04a8a1..bcb7bc4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
@@ -35,7 +35,8 @@ public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
final HolidayDetailDTO holidayDetailDTO, final CalendarInstance restCalendarInstance,
- final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, final FloatingRateDTO floatingRateDTO) {
+ final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, final FloatingRateDTO floatingRateDTO,
+ final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) {
LoanRescheduleModel loanRescheduleModel = null;
@@ -43,13 +44,13 @@ public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
case DECLINING_BALANCE:
loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
- floatingRateDTO);
+ floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays);
break;
case FLAT:
loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
- floatingRateDTO);
+ floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays);
break;
case INVALID:
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/bba8ca47/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
index 8356e1b..f2e8bc7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
@@ -32,5 +32,6 @@ public interface LoanReschedulerFactory {
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance,
- final Calendar loanCalendar, FloatingRateDTO floatingRateDTO);
+ final Calendar loanCalendar, FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst,
+ final Integer numberofdays);
}