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 <[email protected]>
Authored: Wed Mar 23 14:50:47 2016 +0530
Committer: jinjurajan <[email protected]>
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);
 }


Reply via email to