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


Reply via email to