You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ra...@apache.org on 2016/05/04 14:26:13 UTC

[01/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Repository: incubator-fineract
Updated Branches:
  refs/heads/develop 92286b391 -> ffe6a139f


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
index 3437b94..3529323 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
@@ -30,13 +30,14 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.commons.lang.StringUtils;
-import org.apache.fineract.accounting.common.AccountingRuleType;
 import org.apache.fineract.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
+import org.apache.fineract.accounting.common.AccountingRuleType;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
 import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
@@ -47,7 +48,6 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType;
 import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
-import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -90,10 +90,8 @@ public final class LoanProductDataValidator {
             LoanProductConstants.daysInYearTypeParameterName, LoanProductConstants.daysInMonthTypeParameterName,
             LoanProductConstants.rescheduleStrategyMethodParameterName,
             LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
-            LoanProductConstants.recalculationRestFrequencyDateParamName,
             LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
             LoanProductConstants.recalculationRestFrequencyTypeParameterName,
-            LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
             LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
             LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName,
             LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
@@ -104,7 +102,12 @@ public final class LoanProductDataValidator {
             LoanProductConstants.installmentAmountInMultiplesOfParamName,
             LoanProductConstants.preClosureInterestCalculationStrategyParamName, LoanProductConstants.allowAttributeOverridesParamName,
             LoanProductConstants.allowVariableInstallmentsParamName, LoanProductConstants.minimumGapBetweenInstallments,
-            LoanProductConstants.maximumGapBetweenInstallments));
+            LoanProductConstants.maximumGapBetweenInstallments, LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
+            LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
+            LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
+            LoanProductConstants.recalculationRestFrequencyWeekdayParamName,
+            LoanProductConstants.recalculationRestFrequencyNthDayParamName, LoanProductConstants.recalculationRestFrequencyOnDayParamName,
+            LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, LoanProductConstants.allowCompoundingOnEodParamName));
 
     private final FromJsonHelper fromApiJsonHelper;
 
@@ -787,13 +790,6 @@ public final class LoanProductDataValidator {
 
         if (!frequencyType.isSameAsRepayment()) {
             if (loanProduct == null
-                    || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyDateParamName, element)) {
-                final LocalDate recurrenceOnLocalDate = this.fromApiJsonHelper.extractLocalDateNamed(
-                        LoanProductConstants.recalculationRestFrequencyDateParamName, element);
-                baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyDateParamName)
-                        .value(recurrenceOnLocalDate).notNull();
-            }
-            if (loanProduct == null
                     || this.fromApiJsonHelper
                             .parameterExists(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, element)) {
                 final Integer recurrenceInterval = this.fromApiJsonHelper.extractIntegerNamed(
@@ -801,6 +797,20 @@ public final class LoanProductDataValidator {
                 baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyIntervalParameterName)
                         .value(recurrenceInterval).notNull();
             }
+            if (loanProduct == null
+                    || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyNthDayParamName, element)
+                    || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyWeekdayParamName, element)) {
+                CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
+                        LoanProductConstants.recalculationRestFrequencyNthDayParamName,
+                        LoanProductConstants.recalculationRestFrequencyWeekdayParamName, element, this.fromApiJsonHelper);
+            }
+            if (loanProduct == null
+                    || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyOnDayParamName, element)) {
+                final Integer recalculationRestFrequencyOnDay = this.fromApiJsonHelper.extractIntegerNamed(
+                        LoanProductConstants.recalculationRestFrequencyOnDayParamName, element, Locale.getDefault());
+                baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyOnDayParamName)
+                        .value(recalculationRestFrequencyOnDay).ignoreIfNull().inMinMaxRange(1, 28);
+            }
         }
 
         if (compoundingMethod.isCompoundingEnabled()) {
@@ -817,11 +827,11 @@ public final class LoanProductDataValidator {
                     compoundingfrequencyType = RecalculationFrequencyType.fromInt(recalculationCompoundingFrequencyType);
                     if (!compoundingfrequencyType.isSameAsRepayment()) {
                         PeriodFrequencyType repaymentFrequencyType = null;
-                        if (loanProduct == null) {
+                        if (this.fromApiJsonHelper.parameterExists("repaymentFrequencyType", element)) {
                             Integer repaymentFrequencyTypeVal = this.fromApiJsonHelper.extractIntegerNamed("repaymentFrequencyType",
                                     element, Locale.getDefault());
                             repaymentFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyTypeVal);
-                        } else {
+                        } else if (loanProduct != null) {
                             repaymentFrequencyType = loanProduct.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType();
                         }
                         if (!compoundingfrequencyType.isSameFrequency(repaymentFrequencyType)) {
@@ -842,14 +852,6 @@ public final class LoanProductDataValidator {
 
             if (!compoundingfrequencyType.isSameAsRepayment()) {
                 if (loanProduct == null
-                        || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
-                                element)) {
-                    final LocalDate recurrenceOnLocalDate = this.fromApiJsonHelper.extractLocalDateNamed(
-                            LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
-                    baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyDateParamName)
-                            .value(recurrenceOnLocalDate).notNull();
-                }
-                if (loanProduct == null
                         || this.fromApiJsonHelper.parameterExists(
                                 LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName, element)) {
                     final Integer recurrenceInterval = this.fromApiJsonHelper.extractIntegerNamed(
@@ -864,6 +866,23 @@ public final class LoanProductDataValidator {
                     baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName)
                             .value(recurrenceInterval).notNull().integerInMultiplesOfNumber(repaymentEvery);
                 }
+                if (loanProduct == null
+                        || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
+                                element)
+                        || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
+                                element)) {
+                    CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
+                            LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
+                            LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName, element, this.fromApiJsonHelper);
+                }
+                if (loanProduct == null
+                        || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
+                                element)) {
+                    final Integer recalculationRestFrequencyOnDay = this.fromApiJsonHelper.extractIntegerNamed(
+                            LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName, element, Locale.getDefault());
+                    baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName)
+                            .value(recalculationRestFrequencyOnDay).ignoreIfNull().inMinMaxRange(1, 28);
+                }
             }
         }
 
@@ -873,6 +892,12 @@ public final class LoanProductDataValidator {
             baseDataValidator.reset().parameter(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName)
                     .value(isArrearsBasedOnOriginalSchedule).notNull().isOneOfTheseValues(true, false);
         }
+        if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, element)) {
+            final Boolean isCompoundingToBePostedAsTransactions = this.fromApiJsonHelper.extractBooleanNamed(
+                    LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, element);
+            baseDataValidator.reset().parameter(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName)
+                    .value(isCompoundingToBePostedAsTransactions).notNull().isOneOfTheseValues(true, false);
+        }
 
         final Integer preCloseInterestCalculationStrategy = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
                 LoanProductConstants.preClosureInterestCalculationStrategyParamName, element);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java
index 376e092..b0761d7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java
@@ -47,6 +47,8 @@ public interface LoanDropdownReadPlatformService {
     List<EnumOptionData> retrieveLoanCycleValueConditionTypeOptions();
 
     List<EnumOptionData> retrieveInterestRecalculationCompoundingTypeOptions();
+    List<EnumOptionData> retrieveInterestRecalculationNthDayTypeOptions();
+    List<EnumOptionData> retrieveInterestRecalculationDayOfWeekTypeOptions();
 
     List<EnumOptionData> retrieveRescheduleStrategyTypeOptions();
     

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java
index e2d8ed5..b82763f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java
@@ -31,6 +31,8 @@ import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations
 import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyNthDayType;
 import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType;
 import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType;
+import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestRecalculationCompoundingNthDayType;
+import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestRecalculationCompoundingDayOfWeekType;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -112,7 +114,7 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
     public List<EnumOptionData> retrieveRepaymentFrequencyOptionsForNthDayOfMonth() {
         final List<EnumOptionData> repaymentFrequencyOptions = Arrays.asList(repaymentFrequencyNthDayType(NthDayType.ONE),
                 repaymentFrequencyNthDayType(NthDayType.TWO), repaymentFrequencyNthDayType(NthDayType.THREE),
-                repaymentFrequencyNthDayType(NthDayType.FOUR));
+                repaymentFrequencyNthDayType(NthDayType.FOUR), repaymentFrequencyNthDayType(NthDayType.LAST));
         return repaymentFrequencyOptions;
     }
 
@@ -138,7 +140,7 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
     public Collection<TransactionProcessingStrategyData> retreiveTransactionProcessingStrategies() {
 
         final Collection<TransactionProcessingStrategyData> strategyOptions = new ArrayList<>();
-        Sort sort = new Sort("sortOrder") ;
+        Sort sort = new Sort("sortOrder");
         final List<LoanTransactionProcessingStrategy> strategies = this.loanTransactionProcessingStrategyRepository.findAll(sort);
         for (final LoanTransactionProcessingStrategy strategy : strategies) {
             strategyOptions.add(strategy.toData());
@@ -168,6 +170,28 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
     }
 
     @Override
+    public List<EnumOptionData> retrieveInterestRecalculationNthDayTypeOptions() {
+        final List<EnumOptionData> interestRecalculationCompoundingNthDayTypeOptions = Arrays.asList(
+                interestRecalculationCompoundingNthDayType(NthDayType.ONE), interestRecalculationCompoundingNthDayType(NthDayType.TWO),
+                interestRecalculationCompoundingNthDayType(NthDayType.THREE), interestRecalculationCompoundingNthDayType(NthDayType.FOUR),
+                interestRecalculationCompoundingNthDayType(NthDayType.LAST));
+        return interestRecalculationCompoundingNthDayTypeOptions;
+    }
+
+    @Override
+    public List<EnumOptionData> retrieveInterestRecalculationDayOfWeekTypeOptions() {
+        final List<EnumOptionData> interestRecalculationCompoundingNthDayTypeOptions = Arrays.asList(
+                interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.SUNDAY),
+                interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.MONDAY),
+                interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.TUESDAY),
+                interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.WEDNESDAY),
+                interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.THURSDAY),
+                interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.FRIDAY),
+                interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.SATURDAY));
+        return interestRecalculationCompoundingNthDayTypeOptions;
+    }
+
+    @Override
     public List<EnumOptionData> retrieveRescheduleStrategyTypeOptions() {
 
         final List<EnumOptionData> rescheduleStrategyTypeOptions = Arrays.asList(

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
index c5466e6..dffd39c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
@@ -172,6 +172,9 @@ public class LoanEnumerations {
             case FIVE:
                 optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "fifth");
             break;
+            case LAST:
+                optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "last");
+            break;
             default:
                 optionData = new EnumOptionData(new Integer(0).longValue(), codePrefix + type.getCode(), "invalid");
             break;
@@ -390,6 +393,10 @@ public class LoanEnumerations {
                 optionData = new LoanTransactionEnumData(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN.getValue().longValue(),
                         LoanTransactionType.REFUND_FOR_ACTIVE_LOAN.getCode(), "Refund");
             break;
+            case INCOME_POSTING:
+                optionData = new LoanTransactionEnumData(LoanTransactionType.INCOME_POSTING.getValue().longValue(),
+                        LoanTransactionType.INCOME_POSTING.getCode(), "Income Posting");
+            break;
             default:
             break;
         }
@@ -578,6 +585,48 @@ public class LoanEnumerations {
         }
         return optionData;
     }
+    public static EnumOptionData interestRecalculationCompoundingNthDayType(final Integer id) {
+        if (id == null) { return null; }
+        return interestRecalculationCompoundingNthDayType(NthDayType.fromInt(id));
+    }
+    public static EnumOptionData interestRecalculationCompoundingNthDayType(final NthDayType type) {
+    	final String codePrefix = "interestRecalculationCompounding.";
+        long nthDayValue = type.getValue().longValue();
+        EnumOptionData optionData = null;
+        switch (type) {
+            case ONE:
+                optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "first");
+            break;
+            case TWO:
+                optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "second");
+            break;
+            case THREE:
+                optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "third");
+            break;
+            case FOUR:
+                optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "fourth");
+            break;
+            case FIVE:
+                optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "fifth");
+            break;
+            case LAST:
+                optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "last");
+            break;
+            default:
+                optionData = new EnumOptionData(new Integer(0).longValue(), codePrefix + type.getCode(), "invalid");
+            break;
+        }
+        return optionData;
+    }
+    public static EnumOptionData interestRecalculationCompoundingDayOfWeekType(final Integer id) {
+        if (id == null) { return null; }
+        return interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.fromInt(id));
+    }
+    public static EnumOptionData interestRecalculationCompoundingDayOfWeekType(final DayOfWeekType type) {
+        final String codePrefix = "interestRecalculationCompounding.";
+        EnumOptionData optionData = new EnumOptionData(type.getValue().longValue(), codePrefix + type.getCode(), type.toString());
+        return optionData;
+    }
 
     public static EnumOptionData rescheduleStrategyType(final int id) {
         return rescheduleStrategyType(LoanRescheduleStrategyMethod.fromInt(id));

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
index 47f5493..31c7903 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
@@ -194,9 +194,16 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
                     + "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
                     + "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
                     + "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
-                    + "lpr.rest_freqency_date as restFrequencyDate, lpr.arrears_based_on_original_schedule as isArrearsBasedOnOriginalSchedule, "
+                    + "lpr.rest_frequency_nth_day_enum as restFrequencyNthDayEnum, "
+                    + "lpr.rest_frequency_weekday_enum as restFrequencyWeekDayEnum, "
+                    + "lpr.rest_frequency_on_day as restFrequencyOnDay, "
+                    + "lpr.arrears_based_on_original_schedule as isArrearsBasedOnOriginalSchedule, "
                     + "lpr.compounding_frequency_type_enum as compoundingFrequencyTypeEnum, lpr.compounding_frequency_interval as compoundingInterval, "
-                    + "lpr.compounding_freqency_date as compoundingFrequencyDate,  "
+                    + "lpr.compounding_frequency_nth_day_enum as compoundingFrequencyNthDayEnum, "
+                    + "lpr.compounding_frequency_weekday_enum as compoundingFrequencyWeekDayEnum, "
+                    + "lpr.compounding_frequency_on_day as compoundingFrequencyOnDay, "
+                    + "lpr.is_compounding_to_be_posted_as_transaction as isCompoundingToBePostedAsTransaction, "
+                    + "lpr.allow_compounding_on_eod as allowCompoundingOnEod, "
                     + "lp.hold_guarantee_funds as holdGuaranteeFunds, "
                     + "lp.principal_threshold_for_last_installment as principalThresholdForLastInstallment, "
                     + "lpg.id as lpgId, lpg.mandatory_guarantee as mandatoryGuarantee, "
@@ -361,23 +368,50 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
                 final int restFrequencyEnumValue = JdbcSupport.getInteger(rs, "restFrequencyEnum");
                 final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue);
                 final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval");
-                final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate");
+                final Integer restFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyNthDayEnum");
+                EnumOptionData restFrequencyNthDayEnum = null;
+                if (restFrequencyNthDayEnumValue != null) {
+                    restFrequencyNthDayEnum = LoanEnumerations.interestRecalculationCompoundingNthDayType(restFrequencyNthDayEnumValue);
+                }
+                final Integer restFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyWeekDayEnum");
+                EnumOptionData restFrequencyWeekDayEnum = null;
+                if (restFrequencyWeekDayEnumValue != null) {
+                    restFrequencyWeekDayEnum = LoanEnumerations
+                            .interestRecalculationCompoundingDayOfWeekType(restFrequencyWeekDayEnumValue);
+                }
+                final Integer restFrequencyOnDay = JdbcSupport.getInteger(rs, "restFrequencyOnDay");
                 final Integer compoundingFrequencyEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyTypeEnum");
                 EnumOptionData compoundingFrequencyType = null;
                 if (compoundingFrequencyEnumValue != null) {
                     compoundingFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(compoundingFrequencyEnumValue);
                 }
                 final Integer compoundingInterval = JdbcSupport.getInteger(rs, "compoundingInterval");
-                final LocalDate compoundingFrequencyDate = JdbcSupport.getLocalDate(rs, "compoundingFrequencyDate");
+                final Integer compoundingFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyNthDayEnum");
+                EnumOptionData compoundingFrequencyNthDayEnum = null;
+                if (compoundingFrequencyNthDayEnumValue != null) {
+                    compoundingFrequencyNthDayEnum = LoanEnumerations
+                            .interestRecalculationCompoundingNthDayType(compoundingFrequencyNthDayEnumValue);
+                }
+                final Integer compoundingFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyWeekDayEnum");
+                EnumOptionData compoundingFrequencyWeekDayEnum = null;
+                if (compoundingFrequencyWeekDayEnumValue != null) {
+                    compoundingFrequencyWeekDayEnum = LoanEnumerations
+                            .interestRecalculationCompoundingDayOfWeekType(compoundingFrequencyWeekDayEnumValue);
+                }
+                final Integer compoundingFrequencyOnDay = JdbcSupport.getInteger(rs, "compoundingFrequencyOnDay");
                 final boolean isArrearsBasedOnOriginalSchedule = rs.getBoolean("isArrearsBasedOnOriginalSchedule");
+                final boolean isCompoundingToBePostedAsTransaction = rs.getBoolean("isCompoundingToBePostedAsTransaction");
                 final int preCloseInterestCalculationStrategyEnumValue = JdbcSupport.getInteger(rs, "preCloseInterestCalculationStrategy");
                 final EnumOptionData preCloseInterestCalculationStrategy = LoanEnumerations
                         .preCloseInterestCalculationStrategy(preCloseInterestCalculationStrategyEnumValue);
+                final boolean allowCompoundingOnEod = rs.getBoolean("allowCompoundingOnEod");
 
                 interestRecalculationData = new LoanProductInterestRecalculationData(lprId, productId,
                         interestRecalculationCompoundingType, rescheduleStrategyType, restFrequencyType, restFrequencyInterval,
-                        restFrequencyDate, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate,
-                        isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
+                        restFrequencyNthDayEnum, restFrequencyWeekDayEnum, restFrequencyOnDay, compoundingFrequencyType,
+                        compoundingInterval, compoundingFrequencyNthDayEnum, compoundingFrequencyWeekDayEnum, compoundingFrequencyOnDay,
+                        isArrearsBasedOnOriginalSchedule, isCompoundingToBePostedAsTransaction, preCloseInterestCalculationStrategy, 
+                        allowCompoundingOnEod);
             }
 
             final boolean amortization = rs.getBoolean("amortizationBoolean");

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
index 2c105f4..9dac460 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
@@ -342,7 +342,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
             final String title = "recurring_savings_" + account.getId();
             
             final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
-                    CalendarFrequencyType.from(periodFrequencyType), frequency, repeatsOnDay);
+                    CalendarFrequencyType.from(periodFrequencyType), frequency, repeatsOnDay, null);
             calendarInstance = CalendarInstance.from(calendar, account.getId(), CalendarEntityType.SAVINGS.getValue());
         }
         if (calendarInstance == null) {
@@ -488,7 +488,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
                         accountId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
                 Calendar calendar = calendarInstance.getCalendar();
                 calendar.updateRepeatingCalendar(calendarStartDate, CalendarFrequencyType.from(periodFrequencyType), frequency,
-                        repeatsOnDay);
+                        repeatsOnDay, null);
                 this.calendarInstanceRepository.save(calendarInstance);
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/resources/sql/migrations/core_db/V305__compounding_and_rest_frequency_nth_day_freq_and_insertion_script_for_accrual_job.sql
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V305__compounding_and_rest_frequency_nth_day_freq_and_insertion_script_for_accrual_job.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V305__compounding_and_rest_frequency_nth_day_freq_and_insertion_script_for_accrual_job.sql
new file mode 100644
index 0000000..fba505b
--- /dev/null
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V305__compounding_and_rest_frequency_nth_day_freq_and_insertion_script_for_accrual_job.sql
@@ -0,0 +1,60 @@
+CREATE TABLE `m_loan_interest_recalculation_additional_details` (
+	`id` BIGINT NOT NULL AUTO_INCREMENT,
+	`loan_repayment_schedule_id` BIGINT NOT NULL,
+	`effective_date` DATE NOT NULL,
+	`amount` DECIMAL(19,6) NOT NULL,
+	PRIMARY KEY (`id`),
+	CONSTRAINT `FK_additional_details_repayment_schedule_id` FOREIGN KEY (`loan_repayment_schedule_id`) REFERENCES `m_loan_repayment_schedule` (`id`)
+);
+
+
+ALTER TABLE `m_loan` DROP `repayment_frequency_nth_day_enum`, DROP `repayment_frequency_day_of_week_enum`;
+
+
+ALTER TABLE `m_product_loan_recalculation_details` ADD `rest_frequency_nth_day_enum` INT(5), ADD `rest_frequency_on_day` INT(5), ADD `rest_frequency_weekday_enum` INT(5),
+ADD `compounding_frequency_nth_day_enum` INT(5), ADD `compounding_frequency_on_day` INT(5), ADD `compounding_frequency_weekday_enum` INT(5), ADD `is_compounding_to_be_posted_as_transaction` TINYINT(1) NOT NULL DEFAULT '0', ADD `allow_compounding_on_eod` TINYINT(1) NOT NULL DEFAULT '0';
+
+
+ALTER TABLE `m_loan_recalculation_details` ADD `rest_frequency_nth_day_enum` INT(5), ADD `rest_frequency_on_day` INT(5), ADD `rest_frequency_weekday_enum` INT(5),
+ADD `compounding_frequency_nth_day_enum` INT(5), ADD `compounding_frequency_on_day` INT(5), 
+ADD `is_compounding_to_be_posted_as_transaction` TINYINT(1) NOT NULL DEFAULT '0',
+ADD `compounding_frequency_weekday_enum` INT(5), ADD `allow_compounding_on_eod` TINYINT(1) NOT NULL DEFAULT '0';
+
+
+UPDATE m_product_loan_recalculation_details plr SET plr.compounding_frequency_weekday_enum = (WEEKDAY(plr.compounding_freqency_date) + 1) WHERE plr.compounding_frequency_type_enum = 3 AND plr.compounding_freqency_date IS NOT NULL;
+
+
+UPDATE m_product_loan_recalculation_details plr SET plr.compounding_frequency_on_day = DAYOFMONTH(plr.compounding_freqency_date) WHERE plr.compounding_frequency_type_enum = 4 AND plr.compounding_freqency_date IS NOT NULL;
+
+
+UPDATE m_loan_recalculation_details lrd SET lrd.compounding_frequency_weekday_enum = (WEEKDAY(lrd.compounding_freqency_date) + 1) WHERE lrd.compounding_frequency_type_enum = 3 AND lrd.compounding_freqency_date IS NOT NULL;
+
+
+UPDATE m_loan_recalculation_details lrd SET lrd.compounding_frequency_on_day = DAYOFMONTH(lrd.compounding_freqency_date) WHERE lrd.compounding_frequency_type_enum = 4 AND lrd.compounding_freqency_date IS NOT NULL;
+
+
+UPDATE m_product_loan_recalculation_details plr SET plr.rest_frequency_weekday_enum = (WEEKDAY(plr.rest_freqency_date) + 1) WHERE plr.rest_frequency_type_enum = 3 AND plr.rest_freqency_date IS NOT NULL;
+
+
+UPDATE m_product_loan_recalculation_details plr SET plr.rest_frequency_on_day = DAYOFMONTH(plr.rest_freqency_date) WHERE plr.rest_frequency_type_enum = 4 AND plr.rest_freqency_date IS NOT NULL;
+
+
+UPDATE m_loan_recalculation_details lrd SET lrd.rest_frequency_weekday_enum = (WEEKDAY(lrd.rest_freqency_date) + 1) WHERE lrd.rest_frequency_type_enum = 3 AND lrd.rest_freqency_date IS NOT NULL;
+
+
+UPDATE m_loan_recalculation_details lrd SET lrd.rest_frequency_on_day = DAYOFMONTH(lrd.rest_freqency_date) WHERE lrd.rest_frequency_type_enum = 4 AND lrd.rest_freqency_date IS NOT NULL;
+
+
+ALTER TABLE `m_product_loan_recalculation_details` DROP `rest_freqency_date`, DROP `compounding_freqency_date`;
+
+
+ALTER TABLE `m_loan_recalculation_details` DROP `rest_freqency_date`, DROP `compounding_freqency_date`;
+
+
+ALTER TABLE `job`
+	CHANGE COLUMN `name` `name` VARCHAR(100) NOT NULL AFTER `id`,
+	CHANGE COLUMN `display_name` `display_name` VARCHAR(100) NOT NULL AFTER `name`;
+
+INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES ('Add Accrual Transactions For Loans With Income Posted As Transactions', 'Add Accrual Transactions For Loans With Income Posted As Transactions', '0 1 0 1/1 * ? *', now(), 5, NULL, NULL, NULL, NULL, NULL, 1, 0, 1, 3, 0);
+
+UPDATE `job` SET `task_priority`=6 WHERE  `name`='Update Non Performing Assets';
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/LoanRepaymentScheduleInstallmentBuilder.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/LoanRepaymentScheduleInstallmentBuilder.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/LoanRepaymentScheduleInstallmentBuilder.java
index c8a1bba..5e6ee29 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/LoanRepaymentScheduleInstallmentBuilder.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/LoanRepaymentScheduleInstallmentBuilder.java
@@ -18,9 +18,12 @@
  */
 package org.apache.fineract.portfolio.loanaccount;
 
+import java.util.List;
+
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import org.joda.time.LocalDate;
 
@@ -46,9 +49,10 @@ public class LoanRepaymentScheduleInstallmentBuilder {
     }
 
     public LoanRepaymentScheduleInstallment build() {
+        final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
         final LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(this.loan, this.installmentNumber,
                 this.fromDate, this.dueDate, this.principal.getAmount(), this.interest.getAmount(), this.feeCharges.getAmount(),
-                this.penaltyCharges.getAmount(), this.recalculatedInterestComponent);
+                this.penaltyCharges.getAmount(), this.recalculatedInterestComponent, compoundingDetails);
         if (this.completed) {
             installment.payPrincipalComponent(this.latestTransactionDate, this.principal);
             installment.payInterestComponent(this.latestTransactionDate, this.interest);



[06/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java
index fe071f5..a56c004 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java
@@ -18,23 +18,16 @@
  */
 package org.apache.fineract.portfolio.loanaccount.domain;
 
-import java.util.Date;
-import java.util.Map;
-
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.JoinColumn;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
 
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
 import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
 import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
-import org.joda.time.LocalDate;
 import org.springframework.data.jpa.domain.AbstractPersistable;
 
 /**
@@ -70,9 +63,14 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
     @Column(name = "rest_frequency_interval", nullable = false)
     private Integer restInterval;
 
-    @Temporal(TemporalType.DATE)
-    @Column(name = "rest_freqency_date")
-    private Date restFrequencyDate;
+    @Column(name = "rest_frequency_nth_day_enum", nullable = true)
+    private Integer restFrequencyNthDay;
+
+    @Column(name = "rest_frequency_weekday_enum", nullable = true)
+    private Integer restFrequencyWeekday;
+
+    @Column(name = "rest_frequency_on_day", nullable = true)
+    private Integer restFrequencyOnDay;
 
     @Column(name = "compounding_frequency_type_enum", nullable = true)
     private Integer compoundingFrequencyType;
@@ -80,78 +78,63 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
     @Column(name = "compounding_frequency_interval", nullable = true)
     private Integer compoundingInterval;
 
-    @Temporal(TemporalType.DATE)
-    @Column(name = "compounding_freqency_date")
-    private Date compoundingFrequencyDate;
+    @Column(name = "compounding_frequency_nth_day_enum", nullable = true)
+    private Integer compoundingFrequencyNthDay;
+    @Column(name = "compounding_frequency_weekday_enum", nullable = true)
+    private Integer compoundingFrequencyWeekday;
+    @Column(name = "compounding_frequency_on_day", nullable = true)
+    private Integer compoundingFrequencyOnDay;
+
+    @Column(name = "is_compounding_to_be_posted_as_transaction")
+    private Boolean isCompoundingToBePostedAsTransaction;
+    @Column(name = "allow_compounding_on_eod")
+    private Boolean allowCompoundingOnEod;
 
     protected LoanInterestRecalculationDetails() {
         // Default constructor for jpa repository
     }
 
     private LoanInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod, final Integer rescheduleStrategyMethod,
-            final Integer restFrequencyType, final Integer restInterval, final Date restFrequencyDate, Integer compoundingFrequencyType,
-            Integer compoundingInterval, Date compoundingFrequencyDate) {
+            final Integer restFrequencyType, final Integer restInterval, final Integer restFrequencyNthDay, Integer restFrequencyWeekday,
+            Integer restFrequencyOnDay, Integer compoundingFrequencyType, Integer compoundingInterval, Integer compoundingFrequencyNthDay,
+            Integer compoundingFrequencyWeekday, Integer compoundingFrequencyOnDay, final boolean isCompoundingToBePostedAsTransaction,
+            final boolean allowCompoundingOnEod) {
         this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
         this.rescheduleStrategyMethod = rescheduleStrategyMethod;
-        this.restFrequencyDate = restFrequencyDate;
+        this.restFrequencyNthDay = restFrequencyNthDay;
+        this.restFrequencyWeekday = restFrequencyWeekday;
+        this.restFrequencyOnDay = restFrequencyOnDay;
         this.restFrequencyType = restFrequencyType;
         this.restInterval = restInterval;
-        this.compoundingFrequencyDate = compoundingFrequencyDate;
+        this.compoundingFrequencyNthDay = compoundingFrequencyNthDay;
+        this.compoundingFrequencyWeekday = compoundingFrequencyWeekday;
+        this.compoundingFrequencyOnDay = compoundingFrequencyOnDay;
         this.compoundingFrequencyType = compoundingFrequencyType;
         this.compoundingInterval = compoundingInterval;
+        this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
+        this.allowCompoundingOnEod = allowCompoundingOnEod;
     }
 
-    public static LoanInterestRecalculationDetails createFrom(final Integer interestRecalculationCompoundingMethod,
-            final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
-            final Date restFrequencyDate, final Integer compoundingFrequencyType, final Integer compoundingInterval,
-            final Date compoundingFrequencyDate) {
-        return new LoanInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod, restFrequencyType,
-                restInterval, restFrequencyDate, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate);
+    public static LoanInterestRecalculationDetails createFrom(
+            final LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails) {
+        return new LoanInterestRecalculationDetails(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod(),
+                loanProductInterestRecalculationDetails.getRescheduleStrategyMethod(), loanProductInterestRecalculationDetails
+                        .getRestFrequencyType().getValue(), loanProductInterestRecalculationDetails.getRestInterval(),
+                loanProductInterestRecalculationDetails.getRestFrequencyNthDay(),
+                loanProductInterestRecalculationDetails.getRestFrequencyWeekday(),
+                loanProductInterestRecalculationDetails.getRestFrequencyOnDay(), loanProductInterestRecalculationDetails
+                        .getCompoundingFrequencyType().getValue(), loanProductInterestRecalculationDetails.getCompoundingInterval(),
+                loanProductInterestRecalculationDetails.getCompoundingFrequencyNthDay(),
+                loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday(),
+                loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay(),
+                loanProductInterestRecalculationDetails.getIsCompoundingToBePostedAsTransaction(),
+                loanProductInterestRecalculationDetails.allowCompoundingOnEod());
     }
 
     public void updateLoan(final Loan loan) {
         this.loan = loan;
     }
 
-    public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
-        if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName,
-                getRestFrequencyLocalDate())) {
-            final String dateFormatAsInput = command.dateFormat();
-            final String localeAsInput = command.locale();
-            final String valueAsInput = command.stringValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
-            actualChanges.put(LoanProductConstants.recalculationRestFrequencyDateParamName, valueAsInput);
-            actualChanges.put("dateFormat", dateFormatAsInput);
-            actualChanges.put("locale", localeAsInput);
-
-            final LocalDate newValue = command.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
-            if (newValue == null || getRestFrequencyType().isSameAsRepayment()) {
-                this.restFrequencyDate = null;
-            } else {
-                this.restFrequencyDate = newValue.toDate();
-            }
-        }
-
-        if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
-                getCompoundingFrequencyLocalDate())) {
-            final String dateFormatAsInput = command.dateFormat();
-            final String localeAsInput = command.locale();
-            final String valueAsInput = command
-                    .stringValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
-            actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyDateParamName, valueAsInput);
-            actualChanges.put("dateFormat", dateFormatAsInput);
-            actualChanges.put("locale", localeAsInput);
-
-            final LocalDate newValue = command
-                    .localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
-            if (newValue == null || !getInterestRecalculationCompoundingMethod().isCompoundingEnabled()
-                    || getCompoundingFrequencyType().isSameAsRepayment()) {
-                this.compoundingFrequencyDate = null;
-            } else {
-                this.compoundingFrequencyDate = newValue.toDate();
-            }
-        }
-    }
-
     public InterestRecalculationCompoundingMethod getInterestRecalculationCompoundingMethod() {
         return InterestRecalculationCompoundingMethod.fromInt(this.interestRecalculationCompoundingMethod);
     }
@@ -160,14 +143,6 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
         return LoanRescheduleStrategyMethod.fromInt(this.rescheduleStrategyMethod);
     }
 
-    public LocalDate getRestFrequencyLocalDate() {
-        LocalDate recurrenceOnLocalDate = null;
-        if (this.restFrequencyDate != null) {
-            recurrenceOnLocalDate = new LocalDate(this.restFrequencyDate);
-        }
-        return recurrenceOnLocalDate;
-    }
-
     public RecalculationFrequencyType getRestFrequencyType() {
         return RecalculationFrequencyType.fromInt(this.restFrequencyType);
     }
@@ -176,14 +151,6 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
         return this.restInterval;
     }
 
-    public LocalDate getCompoundingFrequencyLocalDate() {
-        LocalDate recurrenceOnLocalDate = null;
-        if (this.compoundingFrequencyDate != null) {
-            recurrenceOnLocalDate = new LocalDate(this.compoundingFrequencyDate);
-        }
-        return recurrenceOnLocalDate;
-    }
-
     public RecalculationFrequencyType getCompoundingFrequencyType() {
         return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
     }
@@ -191,4 +158,36 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
     public Integer getCompoundingInterval() {
         return this.compoundingInterval;
     }
+
+    public Integer getRestFrequencyNthDay() {
+        return this.restFrequencyNthDay;
+    }
+
+    public Integer getRestFrequencyWeekday() {
+        return this.restFrequencyWeekday;
+    }
+
+    public Integer getRestFrequencyOnDay() {
+        return this.restFrequencyOnDay;
+    }
+
+    public Integer getCompoundingFrequencyNthDay() {
+        return this.compoundingFrequencyNthDay;
+    }
+
+    public Integer getCompoundingFrequencyWeekday() {
+        return this.compoundingFrequencyWeekday;
+    }
+
+    public Integer getCompoundingFrequencyOnDay() {
+        return this.compoundingFrequencyOnDay;
+    }
+
+    public boolean isCompoundingToBePostedAsTransaction() {
+        return null == this.isCompoundingToBePostedAsTransaction ? false : this.isCompoundingToBePostedAsTransaction;
+    }
+
+    public boolean allowCompoundingOnEod() {
+        return this.allowCompoundingOnEod;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
index 73aedb6..711a313 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
@@ -19,13 +19,17 @@
 package org.apache.fineract.portfolio.loanaccount.domain;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Date;
+import java.util.List;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
@@ -34,6 +38,8 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.useradministration.domain.AppUser;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
 import org.joda.time.LocalDate;
 
 @Entity
@@ -125,6 +131,10 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
     @Column(name = "recalculated_interest_component", nullable = false)
     private boolean recalculatedInterestComponent;
 
+    @LazyCollection(LazyCollectionOption.FALSE)
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
+    @JoinColumn(name = "loan_repayment_schedule_id", referencedColumnName = "id", nullable = false)
+    private List<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new ArrayList<>();
     protected LoanRepaymentScheduleInstallment() {
         this.installmentNumber = null;
         this.fromDate = null;
@@ -134,7 +144,8 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
 
     public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate,
             final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
-            final BigDecimal penaltyCharges, boolean recalculatedInterestComponent) {
+            final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent,
+            final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails) {
         this.loan = loan;
         this.installmentNumber = installmentNumber;
         this.fromDate = fromDate.toDateTimeAtStartOfDay().toDate();
@@ -145,6 +156,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
         this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
         this.obligationsMet = false;
         this.recalculatedInterestComponent = recalculatedInterestComponent;
+        this.loanCompoundingDetails = compoundingDetails;
     }
 
     public LoanRepaymentScheduleInstallment(final Loan loan) {
@@ -770,4 +782,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
     public Money getDue(MonetaryCurrency currency) {
         return getPrincipal(currency).plus(getInterestCharged(currency)).plus(getFeeChargesCharged(currency)).plus(getPenaltyChargesCharged(currency));
     }
+    public List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
+        return this.loanCompoundingDetails;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 6d4783a..8172d0b 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -146,6 +146,19 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
         this.appUser = null;
     }
 
+    public static LoanTransaction incomePosting(final Loan loan, final Office office, final Date dateOf, 
+    		final BigDecimal amount, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, 
+    		final BigDecimal penaltyChargesPortion, final AppUser appUser){
+    	final Integer typeOf = LoanTransactionType.INCOME_POSTING.getValue();
+    	final BigDecimal principalPortion = BigDecimal.ZERO;
+    	final BigDecimal overPaymentPortion = BigDecimal.ZERO;
+    	final boolean reversed = false;
+    	final PaymentDetail paymentDetail = null;
+    	final String externalId = null;
+    	final LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
+    	return new LoanTransaction(loan, office, typeOf, dateOf, amount, principalPortion, interestPortion, feeChargesPortion,
+                penaltyChargesPortion, overPaymentPortion, reversed, paymentDetail, externalId, createdDate, appUser);
+    }
     public static LoanTransaction disbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
             final LocalDate disbursementDate, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
         return new LoanTransaction(null, office, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate,
@@ -199,6 +212,19 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
                 principalPortion, interestPortion, feesPortion, penaltiesPortion, overPaymentPortion, reversed, paymentDetail, externalId,
                 createdDate, appUser);
     }
+    public static LoanTransaction accrueTransaction(final Loan loan, final Office office, final LocalDate dateOf, final BigDecimal amount,
+            final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
+            final BigDecimal penaltyChargesPortion, final AppUser appUser) {
+        BigDecimal principalPortion = null;
+        BigDecimal overPaymentPortion = null;
+        boolean reversed = false;
+        PaymentDetail paymentDetail = null;
+        String externalId = null;
+        LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
+        return new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL.getValue(), dateOf.toDate(), amount,
+                principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overPaymentPortion, reversed, paymentDetail, externalId,
+                createdDate, appUser);
+    }
 
     public static LoanTransaction initiateTransfer(final Office office, final Loan loan, final LocalDate transferDate,
             final LocalDateTime createdDate, final AppUser appUser) {
@@ -461,6 +487,9 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
         return !isRepayment();
     }
 
+    public boolean isIncomePosting() {
+        return LoanTransactionType.INCOME_POSTING.equals(getTypeOf()) && isNotReversed();
+    }
     public boolean isDisbursement() {
         return LoanTransactionType.DISBURSEMENT.equals(getTypeOf()) && isNotReversed();
     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
index 2e1ae0d..d898561 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
@@ -51,7 +51,8 @@ public enum LoanTransactionType {
     REJECT_TRANSFER(15, "loanTransactionType.rejectTransfer"), //
     REFUND(16, "loanTransactionType.refund"), //
     CHARGE_PAYMENT(17, "loanTransactionType.chargePayment"),  //
-    REFUND_FOR_ACTIVE_LOAN(18, "loanTransactionType.refund");
+    REFUND_FOR_ACTIVE_LOAN(18, "loanTransactionType.refund"), //
+    INCOME_POSTING(19,"loanTransactionType.incomePosting");
 
     private final Integer value;
     private final String code;
@@ -126,6 +127,9 @@ public enum LoanTransactionType {
             case 18:
                 loanTransactionType = LoanTransactionType.REFUND_FOR_ACTIVE_LOAN;
             break;
+            case 19:
+            	loanTransactionType = LoanTransactionType.INCOME_POSTING;
+            	break;
             default:
                 loanTransactionType = LoanTransactionType.INVALID;
             break;
@@ -172,4 +176,7 @@ public enum LoanTransactionType {
     public boolean isRefundForActiveLoan() {
         return this.value.equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN.getValue());
     }
+    public boolean isIncomePosting() {
+        return this.value.equals(LoanTransactionType.INCOME_POSTING.getValue());
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
index 679964a..446c64e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
@@ -69,8 +69,19 @@ public class LoanScheduleParams {
     // date(after applying compounding frequency)
     // from when these amounts will effect the outstanding balance for
     // interest calculation
-    private final TreeMap<LocalDate, Money> compoundingMap;
-    private final Map<LocalDate, TreeMap<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
+    private final Map<LocalDate, Money> compoundingMap;
+    private final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
+    private Money unCompoundedAmount;
+    private Money compoundedInLastInstallment;
+
+    
+    public Money getCompoundedInLastInstallment() {
+        return this.compoundedInLastInstallment;
+    }
+
+    public void setCompoundedInLastInstallment(Money compoundedInLastInstallment) {
+        this.compoundedInLastInstallment = compoundedInLastInstallment;
+    }
 
     // disbursement map for tranche details(will added to outstanding
     // balance as per the start date)
@@ -94,7 +105,7 @@ public class LoanScheduleParams {
             final LocalDate actualRepaymentDate, final Money totalCumulativePrincipal, final Money totalCumulativeInterest,
             final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged, final Money totalRepaymentExpected,
             Money totalOutstandingInterestPaymentDueToGrace, final Money reducePrincipal, final Map<LocalDate, Money> principalPortionMap,
-            final Map<LocalDate, Money> latePaymentMap, final TreeMap<LocalDate, Money> compoundingMap,
+            final Map<LocalDate, Money> latePaymentMap, final Map<LocalDate, Money> compoundingMap, final Money unCompoundedAmount,
             final Map<LocalDate, Money> disburseDetailMap, Money principalToBeScheduled, final Money outstandingBalance,
             final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
             final Collection<RecalculationDetail> recalculationDetails,
@@ -115,6 +126,7 @@ public class LoanScheduleParams {
         this.principalPortionMap = principalPortionMap;
         this.latePaymentMap = latePaymentMap;
         this.compoundingMap = compoundingMap;
+        this.unCompoundedAmount = unCompoundedAmount;
         this.disburseDetailMap = disburseDetailMap;
         this.principalToBeScheduled = principalToBeScheduled;
         this.outstandingBalance = outstandingBalance;
@@ -126,6 +138,9 @@ public class LoanScheduleParams {
         this.partialUpdate = partialUpdate;
         this.currency = currency;
         this.applyInterestRecalculation = applyInterestRecalculation;
+        if (this.currency != null) {
+            this.compoundedInLastInstallment = Money.zero(this.currency);
+        }
     }
 
     public static LoanScheduleParams createLoanScheduleParamsForPartialUpdate(final int periodNumber, final int instalmentNumber,
@@ -133,8 +148,8 @@ public class LoanScheduleParams {
             final Money totalCumulativeInterest, final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged,
             final Money totalRepaymentExpected, Money totalOutstandingInterestPaymentDueToGrace, final Money reducePrincipal,
             final Map<LocalDate, Money> principalPortionMap, final Map<LocalDate, Money> latePaymentMap,
-            final TreeMap<LocalDate, Money> compoundingMap, final Map<LocalDate, Money> disburseDetailMap, Money principalToBeScheduled,
-            final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
+            final Map<LocalDate, Money> compoundingMap, Money unCompoundedAmount, final Map<LocalDate, Money> disburseDetailMap,
+            final Money principalToBeScheduled, final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
             final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
             final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
             final MonetaryCurrency currency, final boolean applyInterestRecalculation) {
@@ -142,9 +157,9 @@ public class LoanScheduleParams {
         return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
                 totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
                 totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
-                compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
-                recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
-                applyInterestRecalculation);
+                compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
+                outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
+                scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
     }
 
     public static LoanScheduleParams createLoanScheduleParamsForCompleteUpdate(final Collection<RecalculationDetail> recalculationDetails,
@@ -162,7 +177,7 @@ public class LoanScheduleParams {
         final Money reducePrincipal = null;
         final Map<LocalDate, Money> principalPortionMap = null;
         final Map<LocalDate, Money> latePaymentMap = null;
-        final TreeMap<LocalDate, Money> compoundingMap = null;
+        final Map<LocalDate, Money> compoundingMap = null;
         final Map<LocalDate, Money> disburseDetailMap = null;
         final Money principalToBeScheduled = null;
         final Money outstandingBalance = null;
@@ -172,12 +187,13 @@ public class LoanScheduleParams {
         final int loanTermInDays = 0;
         final Money totalOutstandingInterestPaymentDueToGrace = null;
         final MonetaryCurrency currency = null;
+        final Money unCompoundedAmount = null;
         return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
                 totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
                 totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
-                compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
-                recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
-                applyInterestRecalculation);
+                compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
+                outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
+                scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
     }
 
     public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
@@ -195,7 +211,7 @@ public class LoanScheduleParams {
         final Money reducePrincipal = Money.zero(currency);
         final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
         final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
-        final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
+        final Map<LocalDate, Money> compoundingMap = new TreeMap<>();
         final Map<LocalDate, Money> disburseDetailMap = new TreeMap<>();
         final Money outstandingBalance = principalToBeScheduled;
         final Money outstandingBalanceAsPerRest = principalToBeScheduled;
@@ -205,12 +221,13 @@ public class LoanScheduleParams {
         final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = null;
         final LocalDate scheduleTillDate = null;
         final boolean applyInterestRecalculation = false;
+        final Money unCompoundedAmount = Money.zero(currency);
         return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
                 totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
                 totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
-                compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
-                recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
-                applyInterestRecalculation);
+                compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
+                outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
+                scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
     }
 
     public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
@@ -228,7 +245,7 @@ public class LoanScheduleParams {
         final Money reducePrincipal = Money.zero(currency);
         final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
         final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
-        final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
+        final Map<LocalDate, Money> compoundingMap = new TreeMap<>();
         final Map<LocalDate, Money> disburseDetailMap = new TreeMap<>();
         final Money outstandingBalance = principalToBeScheduled;
         final Money outstandingBalanceAsPerRest = principalToBeScheduled;
@@ -238,12 +255,13 @@ public class LoanScheduleParams {
         final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanScheduleParams.loanRepaymentScheduleTransactionProcessor;
         final LocalDate scheduleTillDate = loanScheduleParams.scheduleTillDate;
         final boolean applyInterestRecalculation = loanScheduleParams.applyInterestRecalculation;
+        final Money unCompoundedAmount = Money.zero(currency);
         return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
                 totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
                 totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
-                compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
-                recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
-                applyInterestRecalculation);
+                compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
+                outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
+                scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
     }
 
     public int getPeriodNumber() {
@@ -310,7 +328,7 @@ public class LoanScheduleParams {
         return this.latePaymentMap;
     }
 
-    public TreeMap<LocalDate, Money> getCompoundingMap() {
+    public Map<LocalDate, Money> getCompoundingMap() {
         return this.compoundingMap;
     }
 
@@ -434,7 +452,7 @@ public class LoanScheduleParams {
         this.totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace;
     }
 
-    public Map<LocalDate, TreeMap<LocalDate, Money>> getCompoundingDateVariations() {
+    public Map<LocalDate, Map<LocalDate, Money>> getCompoundingDateVariations() {
         return this.compoundingDateVariations;
     }
 
@@ -446,4 +464,18 @@ public class LoanScheduleParams {
         return this.applyInterestRecalculation;
     }
 
+    public Money getUnCompoundedAmount() {
+        return this.unCompoundedAmount;
+    }
+    public void addUnCompoundedAmount(Money unCompoundedAmount) {
+        this.unCompoundedAmount = this.unCompoundedAmount.plus(unCompoundedAmount);
+    }
+
+    public void minusUnCompoundedAmount(Money unCompoundedAmount) {
+        this.unCompoundedAmount = this.unCompoundedAmount.minus(unCompoundedAmount);
+    }
+
+    public void setUnCompoundedAmount(Money unCompoundedAmount) {
+        this.unCompoundedAmount = unCompoundedAmount;
+    }
 }


[09/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes


Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/763cf18b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/763cf18b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/763cf18b

Branch: refs/heads/develop
Commit: 763cf18b90a5956356fdce270588ad923da2e8f9
Parents: a9f811c
Author: Vishwa <vi...@confluxtechnologies.com>
Authored: Wed May 4 14:44:05 2016 +0530
Committer: Vishwa <vi...@confluxtechnologies.com>
Committed: Wed May 4 17:27:00 2016 +0530

----------------------------------------------------------------------
 .../AccountingScenarioIntegrationTest.java      |   14 +-
 .../ClientLoanIntegrationTest.java              |  334 +-
 ...anRepaymentRescheduleAtDisbursementTest.java |   41 +-
 .../LoanReschedulingWithinCenterTest.java       |   26 +-
 .../loans/LoanApplicationTestBuilder.java       |   16 -
 .../common/loans/LoanProductTestBuilder.java    |   24 +-
 .../journalentry/domain/JournalEntry.java       |    3 +
 .../domain/JournalEntryRepository.java          |   12 +-
 .../service/AccountingProcessorHelper.java      |    8 +-
 .../AccrualBasedAccountingProcessorForLoan.java |  111 +-
 .../infrastructure/jobs/service/JobName.java    |    5 +-
 .../portfolio/calendar/CalendarConstants.java   |    3 +-
 .../calendar/api/CalendarsApiResource.java      |    3 +-
 .../portfolio/calendar/data/CalendarData.java   |   84 +-
 .../portfolio/calendar/domain/Calendar.java     |   77 +-
 .../calendar/domain/CalendarInstance.java       |    2 +-
 .../CalendarCommandFromApiJsonDeserializer.java |   11 +
 .../CalendarDropdownReadPlatformService.java    |    1 +
 ...CalendarDropdownReadPlatformServiceImpl.java |    4 +
 .../calendar/service/CalendarEnumerations.java  |   27 +-
 .../CalendarReadPlatformServiceImpl.java        |   16 +-
 .../calendar/service/CalendarUtils.java         |  113 +-
 ...arWritePlatformServiceJpaRepositoryImpl.java |    7 +-
 .../portfolio/common/domain/NthDayType.java     |   17 +
 .../service/CenterReadPlatformServiceImpl.java  |    5 +-
 .../loanaccount/api/LoanApiConstants.java       |   41 +-
 .../loanaccount/api/LoansApiResource.java       |   22 +-
 .../loanaccount/data/LoanAccountData.java       |   32 +
 .../data/LoanInterestRecalculationData.java     |   36 +-
 .../portfolio/loanaccount/domain/Loan.java      |  443 ++-
 .../domain/LoanInstallmentCharge.java           |    6 +
 ...nInterestRecalcualtionAdditionalDetails.java |   62 +
 .../LoanInterestRecalculationDetails.java       |  157 +-
 .../LoanRepaymentScheduleInstallment.java       |   17 +-
 .../loanaccount/domain/LoanTransaction.java     |   29 +
 .../loanaccount/domain/LoanTransactionType.java |    9 +-
 .../loanschedule/data/LoanScheduleParams.java   |   76 +-
 .../domain/AbstractLoanScheduleGenerator.java   |  502 ++-
 ...ingBalanceInterestLoanScheduleGenerator.java |   19 +-
 .../domain/DefaultScheduledDateGenerator.java   |   17 +-
 .../domain/LoanApplicationTerms.java            | 3363 ++++++++----------
 .../LoanScheduleModelDisbursementPeriod.java    |    6 +
 .../domain/LoanScheduleModelPeriod.java         |    3 +
 .../LoanScheduleModelRepaymentPeriod.java       |    8 +
 .../domain/ScheduledDateGenerator.java          |    4 +-
 .../service/LoanScheduleAssembler.java          |  103 +-
 ...scheduleRequestWritePlatformServiceImpl.java |    5 +-
 ...ulateLoanScheduleQueryFromApiJsonHelper.java |   33 +-
 ...LoanApplicationCommandFromApiJsonHelper.java |   99 +-
 .../service/LoanAccrualPlatformService.java     |    1 +
 .../service/LoanAccrualPlatformServiceImpl.java |   20 +
 .../LoanAccrualWritePlatformService.java        |    1 +
 .../LoanAccrualWritePlatformServiceImpl.java    |   41 +-
 ...onWritePlatformServiceJpaRepositoryImpl.java |  213 +-
 .../loanaccount/service/LoanAssembler.java      |    9 +-
 .../service/LoanReadPlatformService.java        |    1 +
 .../service/LoanReadPlatformServiceImpl.java    |  107 +-
 ...anWritePlatformServiceJpaRepositoryImpl.java |   54 +-
 .../loanproduct/LoanProductConstants.java       |   10 +-
 .../api/LoanProductsApiResource.java            |    7 +-
 .../loanproduct/data/LoanProductData.java       |   53 +-
 .../LoanProductInterestRecalculationData.java   |   76 +-
 ...LoanProductInterestRecalculationDetails.java |  272 +-
 .../domain/LoanProductRelatedDetail.java        |    4 +-
 .../serialization/LoanProductDataValidator.java |   69 +-
 .../LoanDropdownReadPlatformService.java        |    2 +
 .../LoanDropdownReadPlatformServiceImpl.java    |   28 +-
 .../loanproduct/service/LoanEnumerations.java   |   49 +
 .../LoanProductReadPlatformServiceImpl.java     |   46 +-
 ...ssWritePlatformServiceJpaRepositoryImpl.java |    4 +-
 ...req_and_insertion_script_for_accrual_job.sql |   60 +
 ...LoanRepaymentScheduleInstallmentBuilder.java |    6 +-
 72 files changed, 4180 insertions(+), 3009 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java
index 0e40d74..f86bc32 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java
@@ -166,8 +166,7 @@ public class AccountingScenarioIntegrationTest {
         float expected_value = this.LP_PRINCIPAL - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
         this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(1, expected_value, loanID);
         final JournalEntry[] assetAccountFirstEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[1], JournalEntry.TransactionType.DEBIT),
-                new JournalEntry(FIRST_INTEREST, JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
+                new JournalEntry(FIRST_INTEREST + FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[1], assetAccountFirstEntry);
         System.out.println("Repayment 1 Done......");
 
@@ -179,8 +178,7 @@ public class AccountingScenarioIntegrationTest {
         expected_value = expected_value - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
         this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(2, expected_value, loanID);
         final JournalEntry[] assetAccountSecondEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[2], JournalEntry.TransactionType.DEBIT),
-                new JournalEntry(SECOND_AND_THIRD_INTEREST, JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
+                new JournalEntry(SECOND_AND_THIRD_INTEREST + SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[2], assetAccountSecondEntry);
         System.out.println("Repayment 2 Done ......");
 
@@ -605,8 +603,7 @@ public class AccountingScenarioIntegrationTest {
         float expected_value = this.LP_PRINCIPAL - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
         this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(1, expected_value, loanID);
         final JournalEntry[] assetAccountFirstEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[1], JournalEntry.TransactionType.DEBIT),
-                new JournalEntry(FIRST_INTEREST, JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
+                new JournalEntry(FIRST_INTEREST + FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[1], assetAccountFirstEntry);
         System.out.println("Repayment 1 Done......");
 
@@ -622,8 +619,7 @@ public class AccountingScenarioIntegrationTest {
                 FEE_PORTION, PENALTY_PORTION, loanID);
         this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(2, expected_value, loanID);
         final JournalEntry[] assetAccountSecondEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[2], JournalEntry.TransactionType.DEBIT),
-                new JournalEntry(SECOND_AND_THIRD_INTEREST, JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
+                new JournalEntry(SECOND_AND_THIRD_INTEREST + SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[2], assetAccountSecondEntry);
         System.out.println("Repayment 2 Done ......");
 
@@ -723,7 +719,7 @@ public class AccountingScenarioIntegrationTest {
         float expected_value = this.LP_PRINCIPAL - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
         this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(1, expected_value, loanID);
         final JournalEntry[] assetAccountEntry = { new JournalEntry(15000f, JournalEntry.TransactionType.DEBIT),
-                new JournalEntry(1000f, JournalEntry.TransactionType.CREDIT), new JournalEntry(10000f, JournalEntry.TransactionType.CREDIT) };
+                new JournalEntry(11000f, JournalEntry.TransactionType.CREDIT) };
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[1], assetAccountEntry);
         this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, this.REPAYMENT_DATE[1], new JournalEntry(4000f,
                 JournalEntry.TransactionType.CREDIT));

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
index 8b52001..5696143 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
@@ -1873,9 +1873,8 @@ public class ClientLoanIntegrationTest {
         validateCharge(flatInstallmentFee, loanCharges, "50", "150.00", "50.0", "0.0");
 
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("150.00"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
+                JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
                 String.valueOf(flatSpecifiedDueDate), "29 October 2011", "100"));
@@ -1899,9 +1898,7 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 2------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.49"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
+                new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3251.49"),
                         JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
@@ -1937,17 +1934,13 @@ public class ClientLoanIntegrationTest {
 
         // checking the journal entry as applied penalty has been collected
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("150"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2811.49"),
-                        JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
+                JournalEntry.TransactionType.CREDIT));
 
         System.out.println("----------Make repayment 3 advance------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.49"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.11"),
+                new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
                         JournalEntry.TransactionType.CREDIT));
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
                 String.valueOf(flatPenaltySpecifiedDueDate), "10 January 2012", "100"));
@@ -1970,10 +1963,10 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make over payment for repayment 4 ------------");
         this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3220.60"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
-                Float.valueOf("3220.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
-        this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(80.92f,
+                Float.valueOf("3220.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3139.68"),
                 JournalEntry.TransactionType.CREDIT));
+        this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012",
+                new JournalEntry(Float.valueOf("80.92"), JournalEntry.TransactionType.CREDIT));
         loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
         LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
     }
@@ -2069,9 +2062,8 @@ public class ClientLoanIntegrationTest {
         validateCharge(percentageInstallmentFee, loanCharges, "1", "90.89", "29.11", "0.0");
 
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("149.11"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
+                JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
                 String.valueOf(percentageSpecifiedDueDateCharge), "29 October 2011", "1"));
@@ -2095,9 +2087,7 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 2------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.49"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
+                new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3271.49"),
                         JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
@@ -2133,17 +2123,13 @@ public class ClientLoanIntegrationTest {
 
         // checking the journal entry as applied penalty has been collected
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("149.11"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
-                        JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
+                JournalEntry.TransactionType.CREDIT));
 
         System.out.println("----------Make repayment 3 advance------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.78"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
+                new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.78"),
                         JournalEntry.TransactionType.CREDIT));
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
                 String.valueOf(percentagePenaltySpecifiedDueDate), "10 January 2012", "1"));
@@ -2166,10 +2152,10 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make over payment for repayment 4 ------------");
         this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3220.58"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
-                Float.valueOf("3220.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
-        this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(100f,
+                Float.valueOf("3220.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3120.58"),
                 JournalEntry.TransactionType.CREDIT));
+        this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012",
+                new JournalEntry(Float.valueOf("100.00"), JournalEntry.TransactionType.CREDIT));
         loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
         LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
     }
@@ -2274,9 +2260,8 @@ public class ClientLoanIntegrationTest {
         validateCharge(amountPlusInterestPercentageInstallmentFee, loanCharges, "1", "94.53", "31.51", "0.0");
 
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("157.57"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
+                JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(
                 loanID,
@@ -2303,9 +2288,7 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 2------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.55"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
+                new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3277.55"),
                         JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
@@ -2343,17 +2326,13 @@ public class ClientLoanIntegrationTest {
 
         // checking the journal entry as applied penalty has been collected
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("157.57"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
-                        JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
+                JournalEntry.TransactionType.CREDIT));
 
         System.out.println("----------Make repayment 3 advance------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", new JournalEntry(Float.valueOf("3303"),
-                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
-                        JournalEntry.TransactionType.CREDIT));
+                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.CREDIT));
         this.loanTransactionHelper.addChargesForLoan(
                 loanID,
                 LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
@@ -2377,9 +2356,9 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make over payment for repayment 4 ------------");
         this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3221.61"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
-                Float.valueOf("3221.61"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
-        this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(100.42f,
+                Float.valueOf("3221.61"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3121.19"),
+                JournalEntry.TransactionType.CREDIT));
+        this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(Float.valueOf("100.42"),
                 JournalEntry.TransactionType.CREDIT));
         loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
         LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
@@ -2468,9 +2447,8 @@ public class ClientLoanIntegrationTest {
         validateCharge(flatInstallmentFee, loanCharges, "50", "150.00", "50.0", "0.0");
 
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("150.00"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
+                JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
                 String.valueOf(flatSpecifiedDueDate), "29 October 2011", "100"));
@@ -2509,9 +2487,7 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 2------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.49"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100.00"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
+                new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3251.49"),
                         JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
@@ -2547,17 +2523,13 @@ public class ClientLoanIntegrationTest {
 
         // checking the journal entry as applied penalty has been collected
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("150"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2811.49"),
-                        JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
+                JournalEntry.TransactionType.CREDIT));
 
         System.out.println("----------Make repayment 3 advance------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.49"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.11"),
+                new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
                         JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
@@ -2581,8 +2553,8 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 4 ------------");
         this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3139.68"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
-                Float.valueOf("3139.68"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3139.68"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3139.68"),
+                JournalEntry.TransactionType.CREDIT));
         loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
         LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
     }
@@ -2673,9 +2645,8 @@ public class ClientLoanIntegrationTest {
         validateCharge(percentageInstallmentFee, loanCharges, "1", "90.89", "29.11", "0.0");
 
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("149.11"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
+                JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
                 String.valueOf(percentageSpecifiedDueDateCharge), "29 October 2011", "1"));
@@ -2715,9 +2686,7 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 2------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.49"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
+                new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3271.49"),
                         JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
@@ -2753,17 +2722,13 @@ public class ClientLoanIntegrationTest {
 
         // checking the journal entry as applied penalty has been collected
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("149.11"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
-                        JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
+                JournalEntry.TransactionType.CREDIT));
 
         System.out.println("----------Make repayment 3 advance------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.78"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
+                new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.78"),
                         JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
@@ -2787,8 +2752,8 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 4 ------------");
         this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3120.58"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
-                Float.valueOf("3120.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3120.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3120.58"),
+                JournalEntry.TransactionType.CREDIT));
         loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
         LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
     }
@@ -2880,9 +2845,8 @@ public class ClientLoanIntegrationTest {
         validateCharge(amountPlusInterestPercentageInstallmentFee, loanCharges, "1", "94.53", "31.51", "0.0");
 
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("157.57"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
+                JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(
                 loanID,
@@ -2925,9 +2889,7 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 2------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.55"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
-                new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"),
-                        JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
+                new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3277.55"),
                         JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
@@ -2965,17 +2927,13 @@ public class ClientLoanIntegrationTest {
 
         // checking the journal entry as applied penalty has been collected
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
-                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("157.57"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
-                        JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
+                JournalEntry.TransactionType.CREDIT));
 
         System.out.println("----------Make repayment 3 advance------------");
         this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", new JournalEntry(Float.valueOf("3303"),
-                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
-                        JournalEntry.TransactionType.CREDIT));
+                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.CREDIT));
 
         this.loanTransactionHelper.addChargesForLoan(
                 loanID,
@@ -3000,8 +2958,8 @@ public class ClientLoanIntegrationTest {
         System.out.println("----------Make repayment 4 ------------");
         this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3121.19"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
-                Float.valueOf("3121.19"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"),
-                JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
+                Float.valueOf("3121.19"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3121.19"),
+                JournalEntry.TransactionType.CREDIT));
         loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
         LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
     }
@@ -3198,7 +3156,7 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, null);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
                 LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0));
@@ -3305,7 +3263,8 @@ public class ClientLoanIntegrationTest {
         final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.DEFAULT_STRATEGY,
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
-                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseInterestStrategy, null);
+                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseInterestStrategy, null,
+                null, null);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
                 LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0));
@@ -3384,7 +3343,7 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, null);
 
         List<HashMap> charges = new ArrayList<>();
         Integer installmentCharge = ChargesHelper.createCharges(requestSpec, responseSpec,
@@ -3473,6 +3432,8 @@ public class ClientLoanIntegrationTest {
         Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         todaysDate.add(Calendar.DAY_OF_MONTH, -14);
         final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
+        Integer dayOfMonth = getDayOfMonth(todaysDate);
+        Integer dayOfWeek = getDayOfWeek(todaysDate);
 
         final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
         ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
@@ -3481,10 +3442,10 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", LOAN_DISBURSEMENT_DATE,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, dayOfWeek, null, dayOfWeek);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
-                LOAN_DISBURSEMENT_DATE, LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
+                LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
 
         Assert.assertNotNull(loanID);
         HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
@@ -3560,8 +3521,8 @@ public class ClientLoanIntegrationTest {
         paymentday.put("penaltyChargesDue", "0");
         addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
         expectedvalues.add(paymentday);
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.28", "11.63", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "1009.87", "4.66", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.31", "11.6", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "1009.84", "4.66", "0.0", "0.0");
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
         HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
@@ -3583,8 +3544,12 @@ public class ClientLoanIntegrationTest {
 
         Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         todaysDate.add(Calendar.DAY_OF_MONTH, -14);
+        Integer compoundingDayOfMonth = getDayOfMonth(todaysDate);
+        Integer compoundingDayOfWeek = getDayOfWeek(todaysDate);
         final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
         todaysDate.add(Calendar.DAY_OF_MONTH, -2);
+        Integer restDayOfMonth = getDayOfMonth(todaysDate);
+        Integer restDayOfWeek = getDayOfWeek(todaysDate);
         final String REST_START_DATE = dateFormat.format(todaysDate.getTime());
 
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
@@ -3609,10 +3574,11 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", LOAN_DISBURSEMENT_DATE,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, compoundingDayOfMonth, compoundingDayOfWeek,
+                restDayOfMonth, restDayOfWeek);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
-                REST_START_DATE, LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, charges);
+                LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, charges);
 
         Assert.assertNotNull(loanID);
         HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
@@ -3622,9 +3588,9 @@ public class ClientLoanIntegrationTest {
         List<Map<String, Object>> expectedvalues = new ArrayList<>();
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2486.03", "42.88", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.5", "31.41", "200", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2533.71", "19.93", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "200", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
         System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
@@ -3641,8 +3607,8 @@ public class ClientLoanIntegrationTest {
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
         addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.08", "46.83", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2488.82", "40.09", "200", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2546.34", "19.96", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "200", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2529.49", "11.67", "0.0", "0.0");
 
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
@@ -3656,9 +3622,9 @@ public class ClientLoanIntegrationTest {
         expectedvalues = new ArrayList<>();
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2486.03", "42.88", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.5", "31.41", "200", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2533.71", "19.93", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "200", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
         Float earlyPayment = new Float("5100");
@@ -3671,9 +3637,9 @@ public class ClientLoanIntegrationTest {
         expectedvalues = new ArrayList<>();
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "5100.0", "36.16", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "0", "11.16", "200", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2417.24", "11.16", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "5065.31", "34.69", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "0", "11.32", "200", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2451.93", "11.32", "0.0", "0.0");
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
         HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
@@ -3689,7 +3655,7 @@ public class ClientLoanIntegrationTest {
     @Test
     public void testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST_PRE_CLOSE_DATE() {
         String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE;
-        String preCloseAmount = "7766.82";
+        String preCloseAmount = "7761.89";
         testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
                 preCloseInterestStrategy, preCloseAmount);
 
@@ -3698,7 +3664,7 @@ public class ClientLoanIntegrationTest {
     @Test
     public void testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST_REST_DATE() {
         String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE;
-        String preCloseAmount = "7771.8";
+        String preCloseAmount = "7786.79";
         testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
                 preCloseInterestStrategy, preCloseAmount);
 
@@ -3715,7 +3681,9 @@ public class ClientLoanIntegrationTest {
         todaysDate.add(Calendar.DAY_OF_MONTH, -16);
         final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
         todaysDate.add(Calendar.DAY_OF_MONTH, -4);
-        final String REST_START_DATE = dateFormat.format(todaysDate.getTime());
+        Integer restDateOfMonth = getDayOfMonth(todaysDate);
+        Integer restDateOfWeek = getDayOfWeek(todaysDate);
+        final String REST_START_DATE = null;
 
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         todaysDate.add(Calendar.DAY_OF_MONTH, -16);
@@ -3738,7 +3706,8 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.DEFAULT_STRATEGY, LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST_AND_FEE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE,
-                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, null, null, preCloseInterestStrategy, null);
+                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, null, null, preCloseInterestStrategy, null,
+                null, null, restDateOfMonth, restDateOfWeek);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
                 REST_START_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, charges);
@@ -3751,9 +3720,9 @@ public class ClientLoanIntegrationTest {
         List<Map<String, Object>> expectedvalues = new ArrayList<>();
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2489.3", "39.61", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2500.78", "28.13", "200", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2527.16", "16.62", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "200", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
         System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
@@ -3770,8 +3739,8 @@ public class ClientLoanIntegrationTest {
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
         addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.08", "46.83", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2495.47", "33.44", "200", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2539.69", "16.66", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2481.87", "47.04", "200", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2553.29", "11.78", "0.0", "0.0");
 
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
@@ -3785,9 +3754,9 @@ public class ClientLoanIntegrationTest {
         expectedvalues = new ArrayList<>();
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2489.3", "39.61", "0.0", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2500.7", "28.21", "200", "0.0");
-        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2527.24", "16.62", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.05", "34.86", "200", "0.0");
+        addRepaymentValues(expectedvalues, todaysDate, 1, false, "2528.97", "11.67", "0.0", "0.0");
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
         HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
@@ -3831,7 +3800,7 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", REST_START_DATE,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, recalculationCompoundingFrequencyInterval,
                 recalculationCompoundingFrequencyDate, LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null,
-                overdueFeeChargeId.toString(), false);
+                overdueFeeChargeId.toString(), false, null, null, null, null);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
                 REST_START_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, null);
@@ -3940,7 +3909,7 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, accounts);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, accounts, null, null);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
                 LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0));
@@ -3983,6 +3952,7 @@ public class ClientLoanIntegrationTest {
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, LOAN_DISBURSEMENT_DATE, assetAccountInitialEntry);
         todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
         String runOndate = dateFormat.format(todaysDate.getTime());
+        System.out.println("runOndate : " + runOndate);
         this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(runOndate);
         this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant().minusDays(7), 46.15f, 0f, 0f, loanID);
         this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant(), 46.15f, 0f, 0f, loanID);
@@ -4002,6 +3972,7 @@ public class ClientLoanIntegrationTest {
         addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
         verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
 
+        this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(runOndate);
         this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant().minusDays(7), 46.15f, 0f, 0f, loanID);
         this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant(), 34.69f, 0f, 0f, loanID);
 
@@ -4036,7 +4007,8 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "1", LOAN_DISBURSEMENT_DATE,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, getDayOfMonth(todaysDate),
+                getDayOfWeek(todaysDate), getDayOfMonth(todaysDate), getDayOfWeek(todaysDate));
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
                 LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
@@ -4119,7 +4091,7 @@ public class ClientLoanIntegrationTest {
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, recalculationCompoundingFrequencyInterval,
                 recalculationCompoundingFrequencyDate, LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null,
-                true);
+                true, null, null, getDayOfMonth(todaysDate), getDayOfWeek(todaysDate));
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
                 LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
@@ -4206,10 +4178,10 @@ public class ClientLoanIntegrationTest {
         final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.DEFAULT_STRATEGY,
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
-                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseStrategy, null);
+                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseStrategy, null, null, null);
 
         final Integer loanID = applyForLoanApplicationForInterestRecalculationWithMoratorium(clientID, loanProductID,
-                LOAN_DISBURSEMENT_DATE, null, LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0), "1", null);
+                LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0), "1", null);
 
         Assert.assertNotNull(loanID);
         HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
@@ -4284,14 +4256,19 @@ public class ClientLoanIntegrationTest {
     private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
             final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
             final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
-            final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts) {
+            final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts,
+            final Integer recalculationRestFrequencyOnDayType, final Integer recalculationRestFrequencyDayOfWeekType) {
         final String recalculationCompoundingFrequencyType = null;
         final String recalculationCompoundingFrequencyInterval = null;
         final String recalculationCompoundingFrequencyDate = null;
+        final Integer recalculationCompoundingFrequencyOnDayType = null;
+        final Integer recalculationCompoundingFrequencyDayOfWeekType = null;
         return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
                 rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
                 recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
-                recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
+                recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false,
+                recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType,
+                recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType);
     }
 
     private Integer createLoanProductWithInterestRecalculationAndCompoundingDetails(final String repaymentStrategy,
@@ -4299,11 +4276,15 @@ public class ClientLoanIntegrationTest {
             final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
             final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
             final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
-            final String preCloseInterestCalculationStrategy, final Account[] accounts) {
+            final String preCloseInterestCalculationStrategy, final Account[] accounts,
+            final Integer recalculationCompoundingFrequencyOnDayType, final Integer recalculationCompoundingFrequencyDayOfWeekType,
+            final Integer recalculationRestFrequencyOnDayType, final Integer recalculationRestFrequencyDayOfWeekType) {
         return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
                 rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
                 recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
-                recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
+                recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false,
+                recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType,
+                recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType);
     }
 
     private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
@@ -4312,7 +4293,9 @@ public class ClientLoanIntegrationTest {
             final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
             final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
             final String preCloseInterestCalculationStrategy, final Account[] accounts, final String chargeId,
-            boolean isArrearsBasedOnOriginalSchedule) {
+            boolean isArrearsBasedOnOriginalSchedule, final Integer recalculationCompoundingFrequencyOnDayType,
+            final Integer recalculationCompoundingFrequencyDayOfWeekType, final Integer recalculationRestFrequencyOnDayType,
+            final Integer recalculationRestFrequencyDayOfWeekType) {
         System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
         LoanProductTestBuilder builder = new LoanProductTestBuilder()
                 .withPrincipal("10000000.00")
@@ -4328,9 +4311,10 @@ public class ClientLoanIntegrationTest {
                 .withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
                         preCloseInterestCalculationStrategy)
                 .withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
-                        recalculationRestFrequencyDate)
+                        recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType)
                 .withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
-                        recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
+                        recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType,
+                        recalculationCompoundingFrequencyDayOfWeekType);
         if (accounts != null) {
             builder = builder.withAccountingRulePeriodicAccrual(accounts);
         }
@@ -4342,30 +4326,27 @@ public class ClientLoanIntegrationTest {
     }
 
     private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
-            final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges) {
-        final String compoundingStartDate = null;
-        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
-                compoundingStartDate, repaymentStrategy, charges);
+            final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges) {
+        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges, null,
+                null);
     }
 
     private Integer applyForLoanApplicationForInterestRecalculationWithMoratorium(final Integer clientID, final Integer loanProductID,
-            final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges,
+            final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges,
             final String graceOnInterestPayment, final String graceOnPrincipalPayment) {
-        final String compoundingStartDate = null;
-        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
-                compoundingStartDate, repaymentStrategy, charges, graceOnInterestPayment, graceOnPrincipalPayment);
+        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges,
+                graceOnInterestPayment, graceOnPrincipalPayment);
     }
 
     private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
-            final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
-            final List<HashMap> charges) {
-        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
-                compoundingStartDate, repaymentStrategy, charges, null, null);
+            final String disbursementDate, final String compoundingStartDate, final String repaymentStrategy, final List<HashMap> charges) {
+        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges, null,
+                null);
     }
 
     private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
-            final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
-            final List<HashMap> charges, final String graceOnInterestPayment, final String graceOnPrincipalPayment) {
+            final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges,
+            final String graceOnInterestPayment, final String graceOnPrincipalPayment) {
         System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
         final String loanApplicationJSON = new LoanApplicationTestBuilder() //
                 .withPrincipal("10000.00") //
@@ -4380,8 +4361,6 @@ public class ClientLoanIntegrationTest {
                 .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
                 .withExpectedDisbursementDate(disbursementDate) //
                 .withSubmittedOnDate(disbursementDate) //
-                .withRestFrequencyDate(restStartDate)//
-                .withCompoundingFrequencyDate(compoundingStartDate)//
                 .withwithRepaymentStrategy(repaymentStrategy) //
                 .withPrincipalGrace(graceOnPrincipalPayment) //
                 .withInterestGrace(graceOnInterestPayment)//
@@ -4593,9 +4572,9 @@ public class ClientLoanIntegrationTest {
         final Account expenseAccount = this.accountHelper.createExpenseAccount();
         final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
 
-        final Integer loanProductID = createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, ACCRUAL_UPFRONT,
-                assetAccount, incomeAccount, expenseAccount, overpaymentAccount);// ,
-                                                                                 // LoanProductTestBuilder.EQUAL_INSTALLMENTS,
+        final Integer loanProductID = createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, ACCRUAL_UPFRONT, assetAccount,
+                incomeAccount, expenseAccount, overpaymentAccount);// ,
+                                                                   // LoanProductTestBuilder.EQUAL_INSTALLMENTS,
         // LoanProductTestBuilder.FLAT_BALANCE);
         Assert.assertNotNull(loanProductID);
 
@@ -4656,9 +4635,7 @@ public class ClientLoanIntegrationTest {
 
         this.loanTransactionHelper.makeRepayment(twoMonthsfromNow, Float.valueOf("2290"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, twoMonthsfromNow, new JournalEntry(Float.valueOf("2290"),
-                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2000"),
-                        JournalEntry.TransactionType.CREDIT));
+                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2290"), JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
         loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
@@ -4673,9 +4650,7 @@ public class ClientLoanIntegrationTest {
 
         this.loanTransactionHelper.makeRepayment(oneMonthfromNow, Float.valueOf("4580"), loanID);
         this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, oneMonthfromNow, new JournalEntry(Float.valueOf("4580"),
-                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"), JournalEntry.TransactionType.CREDIT),
-                new JournalEntry(Float.valueOf("480"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("4000"),
-                        JournalEntry.TransactionType.CREDIT));
+                JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("4580"), JournalEntry.TransactionType.CREDIT));
 
         loanSchedule.clear();
         loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
@@ -4967,10 +4942,9 @@ public class ClientLoanIntegrationTest {
         System.out.println("------------------------LOAN CREATED WITH ID------------------------------" + loanID);
 
         loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments()
-                .withRepaymentTypeAsMonth().withRepaymentAfterEvery("1")
-                .withRepaymentStrategy(LoanProductTestBuilder.DEFAULT_STRATEGY).withInterestTypeAsDecliningBalance()
-                .withInterestCalculationPeriodTypeAsDays().withInArrearsTolerance("10").withMoratorium("2", "3")
-                .withLoanProductConfiguration(loanProductConfigurationAsFalse).build(null));
+                .withRepaymentTypeAsMonth().withRepaymentAfterEvery("1").withRepaymentStrategy(LoanProductTestBuilder.DEFAULT_STRATEGY)
+                .withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeAsDays().withInArrearsTolerance("10")
+                .withMoratorium("2", "3").withLoanProductConfiguration(loanProductConfigurationAsFalse).build(null));
         System.out.println("-------------------LOAN PRODUCT CREATED WITH ATTRIBUTE CONFIGURATION AS FALSE----------------------"
                 + loanProductID);
         /*
@@ -4990,8 +4964,8 @@ public class ClientLoanIntegrationTest {
                 "inArrearsTolerance", "graceOnArrearsAgeing");
 
         for (String comparisonAttribute : comparisonAttributes) {
-        	Object val1 = JsonPath.from(loanProductDetails).get(comparisonAttribute);
-        	Object val2 = JsonPath.from(loanDetails).get(comparisonAttribute);
+            Object val1 = JsonPath.from(loanProductDetails).get(comparisonAttribute);
+            Object val2 = JsonPath.from(loanDetails).get(comparisonAttribute);
             assertEquals(val1, val2);
         }
     }
@@ -5050,4 +5024,26 @@ public class ClientLoanIntegrationTest {
 
         return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
     }
+
+    public Integer getDayOfWeek(Calendar date) {
+        Integer dayOfWeek = null;
+        if (null != date) {
+            dayOfWeek = date.get(Calendar.DAY_OF_WEEK) - 1;
+            if (dayOfWeek.compareTo(0) == 0) {
+                dayOfWeek = 7;
+            }
+        }
+        return dayOfWeek;
+    }
+
+    public Integer getDayOfMonth(Calendar date) {
+        Integer dayOfMonth = null;
+        if (null != date) {
+            dayOfMonth = date.get(Calendar.DAY_OF_MONTH);
+            if (dayOfMonth.compareTo(28) > 0) {
+                dayOfMonth = 28;
+            }
+        }
+        return dayOfMonth;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java
index d0018cd..b56f25d 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java
@@ -72,7 +72,6 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
         final String expectedDisbursementDate = "01 March 2015";
         final String disbursementDate = "01 March 2015";
         final String adjustRepaymentDate = "16 March 2015";
-        final String recalculationRestFrequencyDate = "01 January 2012";
          
         // CREATE CLIENT
     	final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014");
@@ -83,7 +82,7 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
         final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
-                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", recalculationRestFrequencyDate,
+                LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0",
                 LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
         
         // CREATE TRANCHES
@@ -98,7 +97,7 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
         
         // APPLY FOR TRANCHE LOAN WITH INTEREST RECALCULATION 
         final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate,
-        		recalculationRestFrequencyDate, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0), createTranches);
+                LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0), createTranches);
         
         HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
         
@@ -148,23 +147,28 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
     private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
             final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
             final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
-            final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts) {
+            final String preCloseInterestCalculationStrategy, final Account[] accounts) {
         final String recalculationCompoundingFrequencyType = null;
         final String recalculationCompoundingFrequencyInterval = null;
-        final String recalculationCompoundingFrequencyDate = null;
+        final Integer recalculationCompoundingFrequencyOnDayType = null;
+        final Integer recalculationCompoundingFrequencyDayOfWeekType = null;
+        final Integer recalculationRestFrequencyOnDayType = null;
+        final Integer recalculationRestFrequencyDayOfWeekType = null;
         return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
                 rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
-                recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
-                recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
+                recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval, preCloseInterestCalculationStrategy,
+                accounts, null, false, recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType,
+                recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType);
     }
     
     private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
             final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
             final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
-            final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
-            final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
+            final String recalculationCompoundingFrequencyType, final String recalculationCompoundingFrequencyInterval,
             final String preCloseInterestCalculationStrategy, final Account[] accounts, final String chargeId,
-            boolean isArrearsBasedOnOriginalSchedule) {
+            boolean isArrearsBasedOnOriginalSchedule, final Integer recalculationCompoundingFrequencyOnDayType,
+            final Integer recalculationCompoundingFrequencyDayOfWeekType, final Integer recalculationRestFrequencyOnDayType,
+            final Integer recalculationRestFrequencyDayOfWeekType) {
         System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
         LoanProductTestBuilder builder = new LoanProductTestBuilder()
                 .withPrincipal("10000.00")
@@ -180,9 +184,10 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
                 .withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
                         preCloseInterestCalculationStrategy)
                 .withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
-                        recalculationRestFrequencyDate)
+                        recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType)
                 .withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
-                        recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
+                        recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType,
+                        recalculationCompoundingFrequencyDayOfWeekType);
         if (accounts != null) {
             builder = builder.withAccountingRulePeriodicAccrual(accounts);
         }
@@ -194,17 +199,16 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
     }
     
     private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
-            final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges, List<HashMap> tranches) {
+            final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges, List<HashMap> tranches) {
         final String graceOnInterestPayment = null;
-        final String compoundingStartDate = null;
         final String graceOnPrincipalPayment = null;
-        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
-                compoundingStartDate, repaymentStrategy, charges, graceOnInterestPayment, graceOnPrincipalPayment,tranches);
+        return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges,
+                graceOnInterestPayment, graceOnPrincipalPayment, tranches);
     }
     
     private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
-            final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
-            final List<HashMap> charges, final String graceOnInterestPayment, final String graceOnPrincipalPayment, List<HashMap> tranches) {
+            final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges, final String graceOnInterestPayment,
+            final String graceOnPrincipalPayment, List<HashMap> tranches) {
         System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
         final String loanApplicationJSON = new LoanApplicationTestBuilder() //
                 .withPrincipal("10000.00") //
@@ -222,7 +226,6 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
                 .withInterestCalculationPeriodTypeAsDays() //
                 .withExpectedDisbursementDate(disbursementDate) //
                 .withSubmittedOnDate(disbursementDate) //
-                .withRestFrequencyDate(restStartDate)//
                 .withwithRepaymentStrategy(repaymentStrategy) //
                 .withCharges(charges)//
                 .build(clientID.toString(), loanProductID.toString(), null);


[03/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelDisbursementPeriod.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelDisbursementPeriod.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelDisbursementPeriod.java
index acb33a8..87d2332 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelDisbursementPeriod.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelDisbursementPeriod.java
@@ -19,8 +19,10 @@
 package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
 import org.joda.time.LocalDate;
 
@@ -122,4 +124,8 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
     public void addInterestAmount(@SuppressWarnings("unused") Money principalDue) {
         return;
     }
+    @Override
+    public List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
+        return null;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelPeriod.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelPeriod.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelPeriod.java
index 7792416..db67677 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelPeriod.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelPeriod.java
@@ -19,8 +19,10 @@
 package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
 import org.joda.time.LocalDate;
 
@@ -51,4 +53,5 @@ public interface LoanScheduleModelPeriod {
     void addPrincipalAmount(Money principalDue);
     
     void addInterestAmount(Money interestDue);
+    List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails();
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java
index 5b8208e..201e7ca 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java
@@ -19,8 +19,11 @@
 package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
 import org.joda.time.LocalDate;
 
@@ -40,6 +43,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
     private Money penaltyChargesDue;
     private Money totalDue;
     private final boolean recalculatedInterestComponent;
+    private final List<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new ArrayList<>();
 
     public static LoanScheduleModelRepaymentPeriod repayment(final int periodNumber, final LocalDate startDate,
             final LocalDate scheduledDueDate, final Money principalDue, final Money outstandingLoanBalance, final Money interestDue,
@@ -154,4 +158,8 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
         this.interestDue = this.interestDue.plus(interestDue);
         this.totalDue = this.totalDue.plus(principalDue);
     }
+    @Override
+    public List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
+        return this.loanCompoundingDetails;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
index 3761ce0..c82301d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
 
+import org.apache.fineract.portfolio.calendar.domain.Calendar;
 import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
@@ -28,7 +29,8 @@ public interface ScheduledDateGenerator {
     LocalDate getLastRepaymentDate(LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO);
 
     LocalDate idealDisbursementDateBasedOnFirstRepaymentDate(PeriodFrequencyType repaymentPeriodFrequencyType, int repaidEvery,
-            final LocalDate firstRepaymentDate);
+            final LocalDate firstRepaymentDate, final Calendar loanCalendar, final HolidayDetailDTO holidayDetailDTO,
+            final LoanApplicationTerms loanApplicationTerms);
 
     LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment,
             final HolidayDetailDTO holidayDetailDTO);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 56248ec..b86f2a7 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
@@ -68,6 +68,7 @@ import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
 import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
 import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
 import org.apache.fineract.portfolio.common.domain.DaysInYearType;
+import org.apache.fineract.portfolio.common.domain.NthDayType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
 import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
@@ -115,7 +116,6 @@ import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.joda.time.Days;
 import org.joda.time.LocalDate;
-import org.joda.time.LocalTime;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -256,6 +256,12 @@ public class LoanScheduleAssembler {
             final PeriodFrequencyType meetingPeriodFrequency = CalendarUtils.getMeetingPeriodFrequencyType(calendar.getRecurrence());
             validateRepaymentFrequencyIsSameAsMeetingFrequency(meetingPeriodFrequency.getValue(), repaymentFrequencyType,
                     CalendarUtils.getInterval(calendar.getRecurrence()), repaymentEvery);
+        } else {
+            if (repaymentPeriodFrequencyType == PeriodFrequencyType.MONTHS && nthDay != null && nthDay != NthDayType.INVALID.getValue()) {
+                LocalDate calendarStartDate = repaymentsStartingFromDate;
+                if (calendarStartDate == null) calendarStartDate = expectedDisbursementDate;
+                calendar = createLoanCalendar(calendarStartDate, repaymentEvery, CalendarFrequencyType.MONTHLY, dayOfWeek, nthDay);
+            }
         }
 
         /*
@@ -306,7 +312,8 @@ public class LoanScheduleAssembler {
         final Integer graceOnInterestPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element);
         final Integer graceOnInterestCharged = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestCharged", element);
         final LocalDate interestChargedFromDate = this.fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);
-        final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = this.configurationDomainService.isInterestChargedFromDateSameAsDisbursementDate();
+        final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = this.configurationDomainService
+                .isInterestChargedFromDateSameAsDisbursementDate();
 
         final Integer graceOnArrearsAgeing = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
                 LoanProductConstants.graceOnArrearsAgeingParameterName, element);
@@ -334,39 +341,47 @@ public class LoanScheduleAssembler {
         CalendarInstance restCalendarInstance = null;
         RecalculationFrequencyType compoundingFrequencyType = null;
         CalendarInstance compoundingCalendarInstance = null;
+        InterestRecalculationCompoundingMethod compoundingMethod = null;
+        boolean allowCompoundingOnEod = false;
         if (isInterestRecalculationEnabled) {
             LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails = loanProduct
                     .getProductInterestRecalculationDetails();
             recalculationFrequencyType = loanProductInterestRecalculationDetails.getRestFrequencyType();
+            Integer repeatsOnDay = null;
+            Integer recalculationFrequencyNthDay = loanProductInterestRecalculationDetails.getRestFrequencyOnDay();
+            if (recalculationFrequencyNthDay == null) {
+                recalculationFrequencyNthDay = loanProductInterestRecalculationDetails.getRestFrequencyNthDay();
+                repeatsOnDay = loanProductInterestRecalculationDetails.getRestFrequencyWeekday();
+            }
+            Integer frequency = loanProductInterestRecalculationDetails.getRestInterval();
             if (recalculationFrequencyType.isSameAsRepayment()) {
                 restCalendarInstance = createCalendarForSameAsRepayment(repaymentEvery, repaymentPeriodFrequencyType,
                         expectedDisbursementDate);
             } else {
-                LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
-                        LoanProductConstants.recalculationRestFrequencyDateParamName, element);
-                if (calendarStartDate == null) {
-                    calendarStartDate = expectedDisbursementDate;
-                }
+                LocalDate calendarStartDate = expectedDisbursementDate;
                 restCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, recalculationFrequencyType,
-                        loanProductInterestRecalculationDetails.getRestInterval());
+                        frequency, recalculationFrequencyNthDay, repeatsOnDay);
             }
-            InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
-                    .fromInt(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod());
+            compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(loanProductInterestRecalculationDetails
+                    .getInterestRecalculationCompoundingMethod());
             if (compoundingMethod.isCompoundingEnabled()) {
+                Integer compoundingRepeatsOnDay = null;
+                Integer recalculationCompoundingFrequencyNthDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay();
+                if (recalculationCompoundingFrequencyNthDay == null) {
+                    recalculationCompoundingFrequencyNthDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyNthDay();
+                    compoundingRepeatsOnDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday();
+                }
                 compoundingFrequencyType = loanProductInterestRecalculationDetails.getCompoundingFrequencyType();
                 if (compoundingFrequencyType.isSameAsRepayment()) {
                     compoundingCalendarInstance = createCalendarForSameAsRepayment(repaymentEvery, repaymentPeriodFrequencyType,
                             expectedDisbursementDate);
                 } else {
-                    LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
-                            LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
-                    if (calendarStartDate == null) {
-                        calendarStartDate = expectedDisbursementDate;
-                    }
+                    LocalDate calendarStartDate = expectedDisbursementDate;
                     compoundingCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, compoundingFrequencyType,
-                            loanProductInterestRecalculationDetails.getCompoundingInterval());
+                            loanProductInterestRecalculationDetails.getCompoundingInterval(), recalculationCompoundingFrequencyNthDay,
+                            compoundingRepeatsOnDay);
                 }
-
+                allowCompoundingOnEod = loanProductInterestRecalculationDetails.allowCompoundingOnEod();
             }
         }
 
@@ -405,6 +420,21 @@ public class LoanScheduleAssembler {
             }
         }
 
+        final Long clientId = this.fromApiJsonHelper.extractLongNamed("clientId", element);
+        Client client = null;
+        Long officeId = null;
+        if (clientId != null) {
+            client = this.clientRepository.findOneWithNotFoundDetection(clientId);
+            officeId = client.getOffice().getId();
+        } else if (groupId != null) {
+            group = this.groupRepository.findOneWithNotFoundDetection(groupId);
+            officeId = group.getOffice().getId();
+        }
+        final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
+        final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, expectedDisbursementDate.toDate(),
+                HolidayStatusType.ACTIVE.getValue());
+        final WorkingDays workingDays = this.workingDaysRepository.findOne();
+        HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
         return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
                 repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
                 interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -412,21 +442,24 @@ public class LoanScheduleAssembler {
                 calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged,
                 interestChargedFromDate, inArrearsToleranceMoney, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas,
                 maxOutstandingBalance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
-                recalculationFrequencyType, restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType,
+                recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
                 principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(),
-                calendar, BigDecimal.ZERO, loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled,numberOfDays, isSkipMeetingOnFirstDay);
+                calendar, BigDecimal.ZERO, loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled,numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
+                allowCompoundingOnEod);
 }
 
     private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
             final PeriodFrequencyType repaymentPeriodFrequencyType, final LocalDate expectedDisbursementDate) {
-
+        final Integer recalculationFrequencyNthDay = null;
+        final Integer repeatsOnDay = expectedDisbursementDate.getDayOfWeek();
         CalendarInstance restCalendarInstance = createInterestRecalculationCalendarInstance(expectedDisbursementDate, repaymentEvery,
-                CalendarFrequencyType.from(repaymentPeriodFrequencyType));
+                CalendarFrequencyType.from(repaymentPeriodFrequencyType), recalculationFrequencyNthDay, repeatsOnDay);
         return restCalendarInstance;
     }
 
     private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
-            final RecalculationFrequencyType recalculationFrequencyType, final Integer frequency) {
+            final RecalculationFrequencyType recalculationFrequencyType, final Integer frequency,
+            final Integer recalculationFrequencyNthDay, final Integer repeatsOnDay) {
 
         CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
         switch (recalculationFrequencyType) {
@@ -443,18 +476,26 @@ public class LoanScheduleAssembler {
             break;
         }
 
-        return createInterestRecalculationCalendarInstance(calendarStartDate, frequency, calendarFrequencyType);
+        return createInterestRecalculationCalendarInstance(calendarStartDate, frequency, calendarFrequencyType,
+                recalculationFrequencyNthDay, repeatsOnDay);
     }
 
     private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate, final Integer frequency,
-            CalendarFrequencyType calendarFrequencyType) {
-        final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
+            CalendarFrequencyType calendarFrequencyType, final Integer recalculationFrequencyNthDay, final Integer repeatsOnDay) {
         final String title = "loan_recalculation_detail";
         final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
-                calendarFrequencyType, frequency, repeatsOnDay);
+                calendarFrequencyType, frequency, repeatsOnDay, recalculationFrequencyNthDay);
         return CalendarInstance.from(calendar, null, CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
     }
 
+    private Calendar createLoanCalendar(final LocalDate calendarStartDate, final Integer frequency,
+            CalendarFrequencyType calendarFrequencyType, final Integer repeatsOnDay, final Integer repeatsOnNthDayOfMonth) {
+        final String title = "loan_schedule";
+        final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
+                calendarFrequencyType, frequency, repeatsOnDay, repeatsOnNthDayOfMonth);
+        return calendar;
+    }
+
     private List<DisbursementData> fetchDisbursementData(final JsonObject command) {
         final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(command);
         final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(command);
@@ -559,7 +600,7 @@ public class LoanScheduleAssembler {
 
         validateDisbursementDateIsOnNonWorkingDay(loanApplicationTerms.getExpectedDisbursementDate(), workingDays);
         validateDisbursementDateIsOnHoliday(loanApplicationTerms.getExpectedDisbursementDate(), isHolidayEnabled, holidays);
-        
+
         Set<LoanDisbursementDetails> loanDisbursementDetails = this.loanUtilService.fetchDisbursementData(element.getAsJsonObject());
 
         return assembleLoanScheduleFrom(loanApplicationTerms, isHolidayEnabled, holidays, workingDays, element, loanDisbursementDetails);
@@ -996,10 +1037,10 @@ public class LoanScheduleAssembler {
         final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = expectedDisbursementDate
                 .plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
 
-        if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendar != null) {
+        if (calendar != null) {
 
             final LocalDate refernceDateForCalculatingFirstRepaymentDate = expectedDisbursementDate;
-            derivedFirstRepayment = deriveFirstRepaymentDateForJLGLoans(repaymentEvery, expectedDisbursementDate,
+            derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate,
                     refernceDateForCalculatingFirstRepaymentDate, repaymentPeriodFrequencyType,
                     minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
 
@@ -1027,7 +1068,7 @@ public class LoanScheduleAssembler {
         return derivedFirstRepayment;
     }
 
-    private LocalDate deriveFirstRepaymentDateForJLGLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
+    private LocalDate deriveFirstRepaymentDateForLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
             final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
             final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar) {
         boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
@@ -1036,7 +1077,7 @@ public class LoanScheduleAssembler {
         final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
                 refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
         final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
-        return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment : deriveFirstRepaymentDateForJLGLoans(
+        return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment : deriveFirstRepaymentDateForLoans(
                 repaymentEvery, expectedDisbursementDate, derivedFirstRepayment, repaymentPeriodFrequencyType,
                 minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
index 9ab13ee..3a008ab 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
@@ -63,6 +63,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStat
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
@@ -370,13 +371,13 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
                 final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
                 List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
                 Collection<LoanCharge> waiveLoanCharges = new ArrayList<>();
-
+                final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
                 for (LoanRescheduleModelRepaymentPeriod period : periods) {
 
                     if (period.isNew()) {
                         LoanRepaymentScheduleInstallment repaymentScheduleInstallment = new LoanRepaymentScheduleInstallment(loan,
                                 period.periodNumber(), period.periodFromDate(), period.periodDueDate(), period.principalDue(),
-                                period.interestDue(), BigDecimal.ZERO, BigDecimal.ZERO, false);
+                                period.interestDue(), BigDecimal.ZERO, BigDecimal.ZERO, false, compoundingDetails);
 
                         repaymentScheduleInstallments.add(repaymentScheduleInstallment);
                     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java
index 48a5c51..a03fe9b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java
@@ -46,18 +46,29 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
     /**
      * The parameters supported for this command.
      */
-    final Set<String> supportedParameters = new HashSet<>(Arrays.asList("id", "clientId", "groupId", "loanType", "calendarId", "productId",
-            "accountNo", "externalId", "fundId", "loanOfficerId", "loanPurposeId", "transactionProcessingStrategyId", "principal",
-            "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "loanTermFrequency",
-            "loanTermFrequencyType", "repaymentFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
-            LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "interestRateFrequencyType", "expectedDisbursementDate",
-            "repaymentsStartingFromDate", "graceOnPrincipalPayment", "recurringMoratoriumOnPrincipalPeriods", "graceOnInterestPayment", "graceOnInterestCharged",
-            "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat", "charges", "collateral",
-            "syncDisbursementWithMeeting", "linkAccountId", LoanApiConstants.disbursementDataParameterName,
+    final Set<String> supportedParameters = new HashSet<>(Arrays.asList(LoanApiConstants.idParameterName,
+            LoanApiConstants.clientIdParameterName, LoanApiConstants.groupIdParameterName, LoanApiConstants.loanTypeParameterName,
+            LoanApiConstants.calendarIdParameterName, LoanApiConstants.productIdParameterName, LoanApiConstants.accountNoParameterName,
+            LoanApiConstants.externalIdParameterName, LoanApiConstants.fundIdParameterName, LoanApiConstants.loanOfficerIdParameterName,
+            LoanApiConstants.loanPurposeIdParameterName, LoanApiConstants.transactionProcessingStrategyIdParameterName,
+            LoanApiConstants.principalParamName, LoanApiConstants.inArrearsToleranceParameterName,
+            LoanApiConstants.interestRatePerPeriodParameterName, LoanApiConstants.repaymentEveryParameterName,
+            LoanApiConstants.numberOfRepaymentsParameterName, LoanApiConstants.loanTermFrequencyParameterName,
+            LoanApiConstants.loanTermFrequencyTypeParameterName, LoanApiConstants.repaymentFrequencyTypeParameterName,
+            LoanApiConstants.amortizationTypeParameterName, LoanApiConstants.interestTypeParameterName,
+            LoanApiConstants.interestCalculationPeriodTypeParameterName,
+            LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, LoanApiConstants.interestRateFrequencyTypeParameterName,
+            LoanApiConstants.disbursementDateParameterName, LoanApiConstants.repaymentsStartingFromDateParameterName,
+            LoanApiConstants.graceOnPrincipalPaymentParameterName, LoanApiConstants.graceOnInterestPaymentParameterName,
+            LoanApiConstants.graceOnInterestChargedParameterName, LoanApiConstants.interestChargedFromDateParameterName,
+            LoanApiConstants.submittedOnDateParameterName, LoanApiConstants.submittedOnNoteParameterName,
+            LoanApiConstants.localeParameterName, LoanApiConstants.dateFormatParameterName, LoanApiConstants.chargesParameterName,
+            LoanApiConstants.collateralParameterName, LoanApiConstants.syncDisbursementWithMeetingParameterName,
+            LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName,
             LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
-            LoanProductConstants.graceOnArrearsAgeingParameterName, LoanProductConstants.recalculationRestFrequencyDateParamName,
-            "createStandingInstructionAtDisbursement", LoanApiConstants.isFloatingInterestRateParameterName,
-            LoanApiConstants.interestRateDifferentialParameterName));
+            LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName,
+            LoanApiConstants.isFloatingInterestRateParameterName, LoanApiConstants.interestRateDifferentialParameterName,
+            LoanApiConstants.repaymentFrequencyNthDayTypeParameterName, LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName));
 
     private final FromJsonHelper fromApiJsonHelper;
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
index 6b2c4c4..0eaf4af 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
@@ -36,10 +36,10 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
 import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
+import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalculationDetails;
 import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
 import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
 import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
@@ -60,34 +60,38 @@ public final class LoanApplicationCommandFromApiJsonHelper {
     /**
      * The parameters supported for this command.
      */
-    final Set<String> supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType",
-            "productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery",
-            "repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType", "interestRatePerPeriod",
-            "amortizationType", "interestType", LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential,
-            "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName,
-            "interestRateFrequencyType", "expectedDisbursementDate", "repaymentsStartingFromDate",
-            "graceOnPrincipalPayment",
-            "recurringMoratoriumOnPrincipalPeriods",
-            "graceOnInterestPayment",
-            "graceOnInterestCharged",
-            "interestChargedFromDate",
-            "submittedOnDate",
-            "submittedOnNote",
-            "accountNo",
-            "externalId",
-            "fundId",
-            "loanOfficerId", // optional
-            "loanPurposeId",
-            "inArrearsTolerance",
-            "charges",
-            "collateral", // optional
-            "transactionProcessingStrategyId", // settings
-            "calendarId", // optional
-            "syncDisbursementWithMeeting",// optional
-            "linkAccountId", LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName,
-            LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName,
-            LoanProductConstants.recalculationRestFrequencyDateParamName,
-            LoanProductConstants.recalculationCompoundingFrequencyDateParamName, "createStandingInstructionAtDisbursement"));
+    final Set<String> supportedParameters = new HashSet<>(Arrays.asList(LoanApiConstants.dateFormatParameterName,
+            LoanApiConstants.localeParameterName, LoanApiConstants.idParameterName, LoanApiConstants.clientIdParameterName,
+            LoanApiConstants.groupIdParameterName, LoanApiConstants.loanTypeParameterName, LoanApiConstants.productIdParameterName,
+            LoanApiConstants.principalParamName, LoanApiConstants.loanTermFrequencyParameterName,
+            LoanApiConstants.loanTermFrequencyTypeParameterName, LoanApiConstants.numberOfRepaymentsParameterName,
+            LoanApiConstants.repaymentEveryParameterName, LoanApiConstants.repaymentFrequencyTypeParameterName,
+            LoanApiConstants.repaymentFrequencyNthDayTypeParameterName, LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName,
+            LoanApiConstants.interestRatePerPeriodParameterName, LoanApiConstants.amortizationTypeParameterName,
+            LoanApiConstants.interestTypeParameterName, LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential,
+            LoanApiConstants.interestCalculationPeriodTypeParameterName,
+            LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, LoanApiConstants.interestRateFrequencyTypeParameterName,
+            LoanApiConstants.disbursementDateParameterName, LoanApiConstants.repaymentsStartingFromDateParameterName,
+            LoanApiConstants.graceOnPrincipalPaymentParameterName,
+            LoanApiConstants.graceOnInterestPaymentParameterName,
+            LoanApiConstants.graceOnInterestChargedParameterName,
+            LoanApiConstants.interestChargedFromDateParameterName,
+            LoanApiConstants.submittedOnDateParameterName,
+            LoanApiConstants.submittedOnNoteParameterName,
+            LoanApiConstants.accountNoParameterName,
+            LoanApiConstants.externalIdParameterName,
+            LoanApiConstants.fundIdParameterName,
+            LoanApiConstants.loanOfficerIdParameterName, // optional
+            LoanApiConstants.loanPurposeIdParameterName,
+            LoanApiConstants.inArrearsToleranceParameterName,
+            LoanApiConstants.chargesParameterName,
+            LoanApiConstants.collateralParameterName, // optional
+            LoanApiConstants.transactionProcessingStrategyIdParameterName, // settings
+            LoanApiConstants.calendarIdParameterName, // optional
+            LoanApiConstants.syncDisbursementWithMeetingParameterName,// optional
+            LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName,
+            LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
+            LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName));
 
     private final FromJsonHelper fromApiJsonHelper;
     private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
@@ -214,6 +218,10 @@ public final class LoanApplicationCommandFromApiJsonHelper {
         baseDataValidator.reset().parameter(repaymentEveryFrequencyTypeParameterName).value(repaymentEveryType).notNull()
                 .inMinMaxRange(0, 3);
 
+        final String repaymentFrequencyNthDayTypeParameterName = "repaymentFrequencyNthDayType";
+        final String repaymentFrequencyDayOfWeekTypeParameterName = "repaymentFrequencyDayOfWeekType";
+        CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator, repaymentFrequencyNthDayTypeParameterName,
+                repaymentFrequencyDayOfWeekTypeParameterName, element, this.fromApiJsonHelper);
         final String interestTypeParameterName = "interestType";
         final Integer interestType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestTypeParameterName, element);
         baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
@@ -591,6 +599,10 @@ public final class LoanApplicationCommandFromApiJsonHelper {
                     element);
             baseDataValidator.reset().parameter(repaymentEveryTypeParameterName).value(repaymentEveryType).notNull().inMinMaxRange(0, 3);
         }
+        final String repaymentFrequencyNthDayTypeParameterName = "repaymentFrequencyNthDayType";
+        final String repaymentFrequencyDayOfWeekTypeParameterName = "repaymentFrequencyDayOfWeekType";
+        CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator, repaymentFrequencyNthDayTypeParameterName,
+                repaymentFrequencyDayOfWeekTypeParameterName, element, this.fromApiJsonHelper);
 
         final String interestTypeParameterName = "interestType";
         Integer interestType = null;
@@ -1095,14 +1107,6 @@ public final class LoanApplicationCommandFromApiJsonHelper {
 
     }
 
-    public void validateRecalcuationFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
-            final List<ApiParameterError> dataValidationErrors, final String paramName) {
-
-        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
-        baseDataValidator.reset().parameter(paramName).value(recalculationFrequencyDate).notNull()
-                .validateDateBeforeOrEqual(expectedDisbursementDate);
-    }
-
     public void validateLoanCharges(final Set<LoanCharge> charges, final List<ApiParameterError> dataValidationErrors) {
         if (charges == null) { return; }
         final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
@@ -1139,32 +1143,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
 
     public void validateLoanForInterestRecalculation(final Loan loan) {
         final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
-        LoanInterestRecalculationDetails interestRecalculationDetails = loan.loanInterestRecalculationDetails();
-        if (!interestRecalculationDetails.getRestFrequencyType().isSameAsRepayment()) {
-            String paramName = LoanProductConstants.recalculationRestFrequencyDateParamName;
-            validateRecalcuationFrequency(interestRecalculationDetails.getRestFrequencyLocalDate(), loan.getExpectedDisbursedOnLocalDate(),
-                    dataValidationErrors, paramName);
-        }
-
-        if (interestRecalculationDetails.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()
-                && !interestRecalculationDetails.getCompoundingFrequencyType().isSameAsRepayment()) {
-            String paramName = LoanProductConstants.recalculationCompoundingFrequencyDateParamName;
-            validateCompoundingFrequency(interestRecalculationDetails.getCompoundingFrequencyLocalDate(),
-                    loan.getExpectedDisbursedOnLocalDate(), dataValidationErrors, paramName);
-        }
 
         validateLoanCharges(loan.charges(), dataValidationErrors);
         if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
     }
 
-    public void validateCompoundingFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
-            final List<ApiParameterError> dataValidationErrors, final String paramName) {
-
-        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
-        baseDataValidator.reset().parameter(paramName).value(recalculationFrequencyDate).notNull()
-                .validateDateForEqual(expectedDisbursementDate);
-    }
-
     private void validatePartialPeriodSupport(final Integer interestCalculationPeriodType, final DataValidatorBuilder baseDataValidator,
             final JsonElement element, final LoanProduct loanProduct) {
         if (interestCalculationPeriodType != null) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java
index 8f48eeb..277fdd8 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformService.java
@@ -33,5 +33,6 @@ public interface LoanAccrualPlatformService {
     void addAccrualAccounting() throws JobExecutionException;
 
     void addPeriodicAccruals() throws JobExecutionException;
+    void addPeriodicAccrualsForLoansWithIncomePostedAsTransactions() throws JobExecutionException;
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java
index a790f4e..7365d15 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java
@@ -117,4 +117,24 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
         return sb.toString();
     }
 
+    @Override
+    @CronTarget(jobName = JobName.ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS)
+    public void addPeriodicAccrualsForLoansWithIncomePostedAsTransactions() throws JobExecutionException {
+        Collection<Long> loanIds = this.loanReadPlatformService.retrieveLoanIdsWithPendingIncomePostingTransactions();
+        if(loanIds != null && loanIds.size() > 0){
+            StringBuilder sb = new StringBuilder();
+            for (Long loanId : loanIds) {
+                try {
+                    this.loanAccrualWritePlatformService.addIncomeAndAccrualTransactions(loanId);
+                } catch (Exception e) {
+                    Throwable realCause = e;
+                    if (e.getCause() != null) {
+                        realCause = e.getCause();
+                    }
+                    sb.append("failed to add income and accrual transaction for loan " + loanId + " with message " + realCause.getMessage());
+                }
+            }
+            if (sb.length() > 0) { throw new JobExecutionException(sb.toString()); }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformService.java
index 1e63a7c..1044279 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformService.java
@@ -29,4 +29,5 @@ public interface LoanAccrualWritePlatformService {
 
     void addPeriodicAccruals(LocalDate tilldate, Long loanId, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas) throws Exception;
 
+    void addIncomeAndAccrualTransactions(Long loanId) throws Exception;
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
index 79c54ff..5ac0b64 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java
@@ -32,15 +32,22 @@ import javax.sql.DataSource;
 import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
+import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
+import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
+import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
 import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
+import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
 import org.joda.time.Days;
 import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -56,16 +63,23 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
     private final JdbcTemplate jdbcTemplate;
     private final DataSource dataSource;
     private final JournalEntryWritePlatformService journalEntryWritePlatformService;
+    private final AppUserRepositoryWrapper userRepository;
+    private final LoanRepository loanRepository;
+    private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
 
     @Autowired
     public LoanAccrualWritePlatformServiceImpl(final RoutingDataSource dataSource, final LoanReadPlatformService loanReadPlatformService,
             final JournalEntryWritePlatformService journalEntryWritePlatformService,
-            final LoanChargeReadPlatformService loanChargeReadPlatformService) {
+            final LoanChargeReadPlatformService loanChargeReadPlatformService, final AppUserRepositoryWrapper userRepository,
+            final LoanRepository loanRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository) {
         this.loanReadPlatformService = loanReadPlatformService;
         this.dataSource = dataSource;
         this.jdbcTemplate = new JdbcTemplate(this.dataSource);
         this.journalEntryWritePlatformService = journalEntryWritePlatformService;
         this.loanChargeReadPlatformService = loanChargeReadPlatformService;
+        this.userRepository = userRepository;
+        this.loanRepository = loanRepository;
+        this.applicationCurrencyRepository = applicationCurrencyRepository;
     }
 
     @Override
@@ -469,4 +483,29 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
         accrualData.updateAccruableIncome(interestIncome);
     }
 
+    @Override
+    @Transactional
+    public void addIncomeAndAccrualTransactions(Long loanId) throws Exception {
+        if (loanId != null) {
+            Loan loan = this.loanRepository.findOne(loanId);
+            if (loan == null) { throw new LoanNotFoundException(loanId); }
+            final List<Long> existingTransactionIds = new ArrayList<>();
+            final List<Long> existingReversedTransactionIds = new ArrayList<>();
+            existingTransactionIds.addAll(loan.findExistingTransactionIds());
+            existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
+            loan.processIncomeTransactions(this.userRepository.fetchSystemUser());
+            this.loanRepository.saveAndFlush(loan);
+            postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
+        }
+    }
+
+    private void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
+            final List<Long> existingReversedTransactionIds) {
+        final MonetaryCurrency currency = loan.getCurrency();
+        final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
+        boolean isAccountTransfer = false;
+        final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(),
+                existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
+        this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
index 8d5ce19..0bcdd09 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
@@ -55,6 +55,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
 import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
 import org.apache.fineract.portfolio.calendar.domain.CalendarType;
 import org.apache.fineract.portfolio.calendar.exception.CalendarNotFoundException;
+import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
 import org.apache.fineract.portfolio.charge.domain.Charge;
 import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator;
 import org.apache.fineract.portfolio.client.domain.Client;
@@ -64,6 +65,7 @@ import org.apache.fineract.portfolio.collateral.domain.LoanCollateral;
 import org.apache.fineract.portfolio.collateral.service.CollateralAssembler;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
+import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
 import org.apache.fineract.portfolio.fund.domain.Fund;
 import org.apache.fineract.portfolio.group.domain.Group;
@@ -88,6 +90,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInS
 import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
 import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
@@ -108,7 +111,6 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.joda.time.LocalDate;
-import org.joda.time.LocalTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -153,6 +155,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
     private final ConfigurationDomainService configurationDomainService;
     private final LoanScheduleAssembler loanScheduleAssembler;
     private final LoanUtilService loanUtilService;
+    private final CalendarReadPlatformService calendarReadPlatformService;
 
     @Autowired
     public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
@@ -171,7 +174,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
             final LoanReadPlatformService loanReadPlatformService,
             final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
             final BusinessEventNotifierService businessEventNotifierService, final ConfigurationDomainService configurationDomainService,
-            final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService) {
+            final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService, 
+            final CalendarReadPlatformService calendarReadPlatformService) {
         this.context = context;
         this.fromJsonHelper = fromJsonHelper;
         this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -201,6 +205,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
         this.configurationDomainService = configurationDomainService;
         this.loanScheduleAssembler = loanScheduleAssembler;
         this.loanUtilService = loanUtilService;
+        this.calendarReadPlatformService = calendarReadPlatformService;
     }
 
     private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -288,6 +293,26 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                 final CalendarInstance calendarInstance = new CalendarInstance(calendar, newLoanApplication.getId(),
                         CalendarEntityType.LOANS.getValue());
                 this.calendarInstanceRepository.save(calendarInstance);
+            } else {
+                final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(command.parsedJson());
+                final Integer repaymentFrequencyNthDayType = command.integerValueOfParameterNamed("repaymentFrequencyNthDayType");
+                if (loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.MONTHS
+                        && repaymentFrequencyNthDayType != null) {
+                    final String title = "loan_schedule_" + newLoanApplication.getId();
+                    LocalDate calendarStartDate = loanApplicationTerms.getRepaymentsStartingFromLocalDate();
+                    if (calendarStartDate == null) calendarStartDate = loanApplicationTerms.getExpectedDisbursementDate();
+                    final CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.MONTHLY;
+                    final Integer frequency = loanApplicationTerms.getRepaymentEvery();
+                    final Integer repeatsOnDay = loanApplicationTerms.getWeekDayType().getValue();
+                    final Integer repeatsOnNthDayOfMonth = loanApplicationTerms.getNthDay();
+                    final Integer calendarEntityType = CalendarEntityType.LOANS.getValue();
+                    final Calendar loanCalendar = Calendar.createRepeatingCalendar(title, calendarStartDate,
+                            CalendarType.COLLECTION.getValue(), calendarFrequencyType, frequency, repeatsOnDay, repeatsOnNthDayOfMonth);
+                    this.calendarRepository.save(loanCalendar);
+                    final CalendarInstance calendarInstance = CalendarInstance.from(loanCalendar, newLoanApplication.getId(),
+                            calendarEntityType);
+                    this.calendarInstanceRepository.save(calendarInstance);
+                }
             }
 
             // Save linked account information
@@ -357,43 +382,49 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
 
     private void createAndPersistCalendarInstanceForInterestRecalculation(final Loan loan) {
 
-        LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate();
-        if (calendarStartDate == null) {
-            calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
-        }
-        final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
+        LocalDate calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
+        Integer repeatsOnDay = null;
         final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType();
+        Integer recalculationFrequencyNthDay = loan.loanInterestRecalculationDetails().getRestFrequencyOnDay();
+        if (recalculationFrequencyNthDay == null) {
+            recalculationFrequencyNthDay = loan.loanInterestRecalculationDetails().getRestFrequencyNthDay();
+            repeatsOnDay = loan.loanInterestRecalculationDetails().getRestFrequencyWeekday();
+        }
 
         Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval();
         CalendarEntityType calendarEntityType = CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL;
         final String title = "loan_recalculation_detail_" + loan.loanInterestRecalculationDetails().getId();
 
-        createCalendar(loan, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency, calendarEntityType, title);
+        createCalendar(loan, calendarStartDate, recalculationFrequencyNthDay, repeatsOnDay, recalculationFrequencyType, frequency,
+                calendarEntityType, title);
 
         if (loan.loanInterestRecalculationDetails().getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
-            LocalDate compoundingStartDate = loan.loanInterestRecalculationDetails().getCompoundingFrequencyLocalDate();
-            if (compoundingStartDate == null) {
-                compoundingStartDate = loan.getExpectedDisbursedOnLocalDate();
-            }
-            final Integer compoundingRepeatsOnDay = compoundingStartDate.getDayOfWeek();
+            LocalDate compoundingStartDate = loan.getExpectedDisbursedOnLocalDate();
+            Integer compoundingRepeatsOnDay = null;
             final RecalculationFrequencyType recalculationCompoundingFrequencyType = loan.loanInterestRecalculationDetails()
                     .getCompoundingFrequencyType();
+            Integer recalculationCompoundingFrequencyNthDay = loan.loanInterestRecalculationDetails().getCompoundingFrequencyOnDay();
+            if (recalculationCompoundingFrequencyNthDay == null) {
+                recalculationCompoundingFrequencyNthDay = loan.loanInterestRecalculationDetails().getCompoundingFrequencyNthDay();
+                compoundingRepeatsOnDay = loan.loanInterestRecalculationDetails().getCompoundingFrequencyWeekday();
+            }
 
             Integer compoundingFrequency = loan.loanInterestRecalculationDetails().getCompoundingInterval();
             CalendarEntityType compoundingCalendarEntityType = CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL;
             final String compoundingCalendarTitle = "loan_recalculation_detail_compounding_frequency"
                     + loan.loanInterestRecalculationDetails().getId();
 
-            createCalendar(loan, compoundingStartDate, compoundingRepeatsOnDay, recalculationCompoundingFrequencyType,
-                    compoundingFrequency, compoundingCalendarEntityType, compoundingCalendarTitle);
+            createCalendar(loan, compoundingStartDate, recalculationCompoundingFrequencyNthDay, compoundingRepeatsOnDay,
+                    recalculationCompoundingFrequencyType, compoundingFrequency, compoundingCalendarEntityType, compoundingCalendarTitle);
         }
 
     }
 
-    private void createCalendar(final Loan loan, LocalDate calendarStartDate, final Integer repeatsOnDay,
-            final RecalculationFrequencyType recalculationFrequencyType, Integer frequency, CalendarEntityType calendarEntityType,
-            final String title) {
+    private void createCalendar(final Loan loan, LocalDate calendarStartDate, Integer recalculationFrequencyNthDay,
+            final Integer repeatsOnDay, final RecalculationFrequencyType recalculationFrequencyType, Integer frequency,
+            CalendarEntityType calendarEntityType, final String title) {
         CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
+        Integer updatedRepeatsOnDay = repeatsOnDay;
         switch (recalculationFrequencyType) {
             case DAILY:
                 calendarFrequencyType = CalendarFrequencyType.DAILY;
@@ -405,6 +436,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                 frequency = loan.repaymentScheduleDetail().getRepayEvery();
                 calendarFrequencyType = CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType());
                 calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
+                if (updatedRepeatsOnDay == null) {
+                    updatedRepeatsOnDay = calendarStartDate.getDayOfWeek();
+                }
             break;
             case WEEKLY:
                 calendarFrequencyType = CalendarFrequencyType.WEEKLY;
@@ -414,71 +448,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
         }
          
         final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
-                calendarFrequencyType, frequency, repeatsOnDay);
+                calendarFrequencyType, frequency, updatedRepeatsOnDay, recalculationFrequencyNthDay);
         final CalendarInstance calendarInstance = CalendarInstance.from(calendar, loan.loanInterestRecalculationDetails().getId(),
                 calendarEntityType.getValue());
         this.calendarInstanceRepository.save(calendarInstance);
     }
 
-    private void updateRestCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) {
-
-        Calendar interestRecalculationRecurrings = calendarInstance.getCalendar();
-        LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate();
-        if (calendarStartDate == null) {
-            calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
-        }
-        final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
-        final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType();
-
-        Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval();
-
-        updateCalendar(loan, interestRecalculationRecurrings, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency);
-
-    }
-
-    private void updateCompoundingCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) {
-
-        Calendar interestRecalculationRecurrings = calendarInstance.getCalendar();
-        LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getCompoundingFrequencyLocalDate();
-        if (calendarStartDate == null) {
-            calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
-        }
-        final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
-        final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getCompoundingFrequencyType();
-
-        Integer frequency = loan.loanInterestRecalculationDetails().getCompoundingInterval();
-
-        updateCalendar(loan, interestRecalculationRecurrings, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency);
-
-    }
-
-    private void updateCalendar(final Loan loan, Calendar interestRecalculationRecurrings, LocalDate calendarStartDate,
-            final Integer repeatsOnDay, final RecalculationFrequencyType recalculationFrequencyType, Integer frequency) {
-        CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
-        switch (recalculationFrequencyType) {
-            case DAILY:
-                calendarFrequencyType = CalendarFrequencyType.DAILY;
-            break;
-
-            case MONTHLY:
-                calendarFrequencyType = CalendarFrequencyType.MONTHLY;
-            break;
-            case SAME_AS_REPAYMENT_PERIOD:
-                calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
-                frequency = loan.repaymentScheduleDetail().getRepayEvery();
-                calendarFrequencyType = CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType());
-            break;
-            case WEEKLY:
-                calendarFrequencyType = CalendarFrequencyType.WEEKLY;
-            break;
-            default:
-            break;
-        }
-
-        interestRecalculationRecurrings.updateRepeatingCalendar(calendarStartDate, calendarFrequencyType, frequency, repeatsOnDay);
-        this.calendarRepository.save(interestRecalculationRecurrings);
-    }
-
     @Transactional
     @Override
     public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) {
@@ -551,7 +526,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                     }
                 }
             }
-            
+
             final Set<LoanCollateral> possiblyModifedLoanCollateralItems = this.loanCollateralAssembler
                     .fromParsedJson(command.parsedJson());
 
@@ -700,6 +675,11 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                 // loan
                 if (ciList != null && !ciList.isEmpty()) {
                     final CalendarInstance calendarInstance = ciList.get(0);
+                    final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(calendarInstance
+                            .getEntityId(), calendarInstance.getCalendar().getId(), CalendarEntityType.LOANS.getValue().longValue());
+                    if (isCalendarAssociatedWithEntity) {
+                        this.calendarRepository.delete(calendarInstance.getCalendar());
+                    }
                     if (calendarInstance.getCalendar().getId() != calendar.getId()) {
                         calendarInstance.updateCalendar(calendar);
                         this.calendarInstanceRepository.saveAndFlush(calendarInstance);
@@ -711,9 +691,65 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                     this.calendarInstanceRepository.save(calendarInstance);
                 }
 
-            } else if (ciList != null && !ciList.isEmpty()) {
-                final CalendarInstance calendarInstance = ciList.get(0);
-                this.calendarInstanceRepository.delete(calendarInstance);
+            } else {
+                if (ciList != null && !ciList.isEmpty()) {
+                    final CalendarInstance existingCalendarInstance = ciList.get(0);
+                    final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(
+                            existingCalendarInstance.getEntityId(), existingCalendarInstance.getCalendar().getId(),
+                            CalendarEntityType.GROUPS.getValue().longValue());
+                    if (isCalendarAssociatedWithEntity) {
+                        this.calendarInstanceRepository.delete(existingCalendarInstance);
+                    }
+                }
+                if (changes.containsKey("repaymentFrequencyNthDayType") || changes.containsKey("repaymentFrequencyDayOfWeekType")) {
+                    if (changes.get("repaymentFrequencyNthDayType") == null) {
+                        if (ciList != null && !ciList.isEmpty()) {
+                            final CalendarInstance calendarInstance = ciList.get(0);
+                            final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(
+                                    calendarInstance.getEntityId(), calendarInstance.getCalendar().getId(), CalendarEntityType.LOANS.getValue().longValue());
+                            if (isCalendarAssociatedWithEntity) {
+                                this.calendarInstanceRepository.delete(calendarInstance);
+                                this.calendarRepository.delete(calendarInstance.getCalendar());
+                            }
+                        }
+                    } else {
+                        Integer repaymentFrequencyTypeInt = command.integerValueOfParameterNamed("repaymentFrequencyType");
+                        if (repaymentFrequencyTypeInt != null) {
+                            if (PeriodFrequencyType.fromInt(repaymentFrequencyTypeInt) == PeriodFrequencyType.MONTHS) {
+                                final String title = "loan_schedule_" + existingLoanApplication.getId();
+                                final Integer typeId = CalendarType.COLLECTION.getValue();
+                                final CalendarFrequencyType repaymentFrequencyType = CalendarFrequencyType.MONTHLY;
+                                final Integer interval = command.integerValueOfParameterNamed("repaymentEvery");
+                                LocalDate startDate = command.localDateValueOfParameterNamed("repaymentsStartingFromDate");
+                                if (startDate == null) startDate = command.localDateValueOfParameterNamed("expectedDisbursementDate");
+                                final Calendar newCalendar = Calendar.createRepeatingCalendar(title, startDate, typeId,
+                                        repaymentFrequencyType, interval, (Integer) changes.get("repaymentFrequencyDayOfWeekType"),
+                                        (Integer) changes.get("repaymentFrequencyNthDayType"));
+                                if (ciList != null && !ciList.isEmpty()) {
+                                    final CalendarInstance calendarInstance = ciList.get(0);
+                                    final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(
+                                            calendarInstance.getEntityId(), calendarInstance.getCalendar().getId(), CalendarEntityType.LOANS.getValue().longValue());
+                                    if (isCalendarAssociatedWithEntity) {
+                                        final Calendar existingCalendar = calendarInstance.getCalendar();
+                                        if (existingCalendar != null) {
+                                            String existingRecurrence = existingCalendar.getRecurrence();
+                                            if (!existingRecurrence.equals(newCalendar.getRecurrence())) {
+                                                existingCalendar.setRecurrence(newCalendar.getRecurrence());
+                                                this.calendarRepository.save(existingCalendar);
+                                            }
+                                        }
+                                    }
+                                } else {
+                                    this.calendarRepository.save(newCalendar);
+                                    final Integer calendarEntityType = CalendarEntityType.LOANS.getValue();
+                                    final CalendarInstance calendarInstance = new CalendarInstance(newCalendar,
+                                            existingLoanApplication.getId(), calendarEntityType);
+                                    this.calendarInstanceRepository.save(calendarInstance);
+                                }
+                            }
+                        }
+                    }
+                }
             }
 
             // Save linked account information
@@ -776,20 +812,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                 this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(existingLoanApplication);
                 if (changes.containsKey(LoanProductConstants.isInterestRecalculationEnabledParameterName)) {
                     createAndPersistCalendarInstanceForInterestRecalculation(existingLoanApplication);
-                } else {
-                    if (changes.containsKey(LoanProductConstants.recalculationRestFrequencyDateParamName)) {
 
-                        CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
-                                existingLoanApplication.loanInterestRecalculationDetailId(),
-                                CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
-                        updateRestCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication);
-                    }
-                    if (changes.containsKey(LoanProductConstants.recalculationCompoundingFrequencyDateParamName)) {
-                        CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
-                                existingLoanApplication.loanInterestRecalculationDetailId(),
-                                CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
-                        updateCompoundingCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication);
-                    }
                 }
 
             }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
index 755a751..93df756 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
@@ -70,7 +70,6 @@ import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementData
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
-import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
@@ -82,6 +81,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
 import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+
 import com.google.gson.JsonElement;
 
 @Service
@@ -282,10 +282,6 @@ public class LoanAssembler {
             }
         }
 
-        final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(
-                LoanProductConstants.recalculationRestFrequencyDateParamName, element);
-        final LocalDate recalculationCompoundingFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(
-                LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
 
         final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element);
         final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
@@ -297,8 +293,7 @@ public class LoanAssembler {
         final LoanScheduleModel loanScheduleModel = this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms,
                 isHolidayEnabled, holidays, workingDays, element,disbursementDetails);
         loanApplication.loanApplicationSubmittal(currentUser, loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(),
-                submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay,
-                recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate);
+                submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
 
         return loanApplication;
     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
index e41860d..f6df4e4 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
@@ -126,4 +126,5 @@ public interface LoanReadPlatformService {
     LoanTransactionData retrieveRefundByCashTemplate(Long loanId);
     
     Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(Long loanId);
+    Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions();
 }
\ No newline at end of file


[10/10] incubator-fineract git commit: Merge branch 'PR95' into develop

Posted by ra...@apache.org.
Merge branch 'PR95' into develop


Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/ffe6a139
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/ffe6a139
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/ffe6a139

Branch: refs/heads/develop
Commit: ffe6a139f61bc812e2fdc34055462a0cf1ad8715
Parents: 92286b3 763cf18
Author: Adi Narayana Raju <ad...@confluxtechnologies.com>
Authored: Wed May 4 19:10:57 2016 +0530
Committer: Adi Narayana Raju <ad...@confluxtechnologies.com>
Committed: Wed May 4 19:10:57 2016 +0530

----------------------------------------------------------------------
 .../AccountingScenarioIntegrationTest.java      |   14 +-
 .../ClientLoanIntegrationTest.java              |  334 +-
 ...anRepaymentRescheduleAtDisbursementTest.java |   41 +-
 .../LoanReschedulingWithinCenterTest.java       |   26 +-
 .../loans/LoanApplicationTestBuilder.java       |   16 -
 .../common/loans/LoanProductTestBuilder.java    |   24 +-
 .../journalentry/domain/JournalEntry.java       |    3 +
 .../domain/JournalEntryRepository.java          |   12 +-
 .../service/AccountingProcessorHelper.java      |    8 +-
 .../AccrualBasedAccountingProcessorForLoan.java |  111 +-
 .../infrastructure/jobs/service/JobName.java    |    5 +-
 .../portfolio/calendar/CalendarConstants.java   |    3 +-
 .../calendar/api/CalendarsApiResource.java      |    3 +-
 .../portfolio/calendar/data/CalendarData.java   |   84 +-
 .../portfolio/calendar/domain/Calendar.java     |   77 +-
 .../calendar/domain/CalendarInstance.java       |    2 +-
 .../CalendarCommandFromApiJsonDeserializer.java |   11 +
 .../CalendarDropdownReadPlatformService.java    |    1 +
 ...CalendarDropdownReadPlatformServiceImpl.java |    4 +
 .../calendar/service/CalendarEnumerations.java  |   27 +-
 .../CalendarReadPlatformServiceImpl.java        |   16 +-
 .../calendar/service/CalendarUtils.java         |  113 +-
 ...arWritePlatformServiceJpaRepositoryImpl.java |    7 +-
 .../portfolio/common/domain/NthDayType.java     |   17 +
 .../service/CenterReadPlatformServiceImpl.java  |    5 +-
 .../loanaccount/api/LoanApiConstants.java       |   41 +-
 .../loanaccount/api/LoansApiResource.java       |   22 +-
 .../loanaccount/data/LoanAccountData.java       |   32 +
 .../data/LoanInterestRecalculationData.java     |   36 +-
 .../portfolio/loanaccount/domain/Loan.java      |  443 ++-
 .../domain/LoanInstallmentCharge.java           |    6 +
 ...nInterestRecalcualtionAdditionalDetails.java |   62 +
 .../LoanInterestRecalculationDetails.java       |  157 +-
 .../LoanRepaymentScheduleInstallment.java       |   17 +-
 .../loanaccount/domain/LoanTransaction.java     |   29 +
 .../loanaccount/domain/LoanTransactionType.java |    9 +-
 .../loanschedule/data/LoanScheduleParams.java   |   76 +-
 .../domain/AbstractLoanScheduleGenerator.java   |  502 ++-
 ...ingBalanceInterestLoanScheduleGenerator.java |   19 +-
 .../domain/DefaultScheduledDateGenerator.java   |   17 +-
 .../domain/LoanApplicationTerms.java            | 3363 ++++++++----------
 .../LoanScheduleModelDisbursementPeriod.java    |    6 +
 .../domain/LoanScheduleModelPeriod.java         |    3 +
 .../LoanScheduleModelRepaymentPeriod.java       |    8 +
 .../domain/ScheduledDateGenerator.java          |    4 +-
 .../service/LoanScheduleAssembler.java          |  103 +-
 ...scheduleRequestWritePlatformServiceImpl.java |    5 +-
 ...ulateLoanScheduleQueryFromApiJsonHelper.java |   33 +-
 ...LoanApplicationCommandFromApiJsonHelper.java |   99 +-
 .../service/LoanAccrualPlatformService.java     |    1 +
 .../service/LoanAccrualPlatformServiceImpl.java |   20 +
 .../LoanAccrualWritePlatformService.java        |    1 +
 .../LoanAccrualWritePlatformServiceImpl.java    |   41 +-
 ...onWritePlatformServiceJpaRepositoryImpl.java |  213 +-
 .../loanaccount/service/LoanAssembler.java      |    9 +-
 .../service/LoanReadPlatformService.java        |    1 +
 .../service/LoanReadPlatformServiceImpl.java    |  107 +-
 ...anWritePlatformServiceJpaRepositoryImpl.java |   54 +-
 .../loanproduct/LoanProductConstants.java       |   10 +-
 .../api/LoanProductsApiResource.java            |    7 +-
 .../loanproduct/data/LoanProductData.java       |   53 +-
 .../LoanProductInterestRecalculationData.java   |   76 +-
 ...LoanProductInterestRecalculationDetails.java |  272 +-
 .../domain/LoanProductRelatedDetail.java        |    4 +-
 .../serialization/LoanProductDataValidator.java |   69 +-
 .../LoanDropdownReadPlatformService.java        |    2 +
 .../LoanDropdownReadPlatformServiceImpl.java    |   28 +-
 .../loanproduct/service/LoanEnumerations.java   |   49 +
 .../LoanProductReadPlatformServiceImpl.java     |   46 +-
 ...ssWritePlatformServiceJpaRepositoryImpl.java |    4 +-
 ...req_and_insertion_script_for_accrual_job.sql |   60 +
 ...LoanRepaymentScheduleInstallmentBuilder.java |    6 +-
 72 files changed, 4180 insertions(+), 3009 deletions(-)
----------------------------------------------------------------------



[05/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 2f8b728..d06b3f1 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
@@ -45,6 +45,7 @@ import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
@@ -124,7 +125,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
         LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
                 loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO);
         final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
-                loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
+                loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate,
+                loanApplicationTerms.getLoanCalendar(), loanApplicationTerms.getHolidayDetailDTO(), loanApplicationTerms);
 
         if (!scheduleParams.isPartialUpdate()) {
             // Set Fixed Principal Amount
@@ -203,13 +205,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             if (scheduleParams.getPeriodStartDate().isAfter(scheduledDueDate)) { throw new ScheduleDateException(
                     "Due date can't be before period start date", scheduledDueDate); }
 
-            if (!scheduleParams.getLatePaymentMap().isEmpty()) {
-                populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, currentDate, loanApplicationTerms,
-                        holidayDetailDTO, scheduleParams.getCompoundingMap(), loanCharges, currency);
-                scheduleParams.getCompoundingDateVariations().put(scheduleParams.getPeriodStartDate(),
-                        new TreeMap<>(scheduleParams.getCompoundingMap()));
-            }
-
             if (extendTermForDailyRepayments) {
                 scheduleParams.setActualRepaymentDate(scheduledDueDate);
             }
@@ -220,6 +215,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                 scheduledDueDate = scheduleParams.getScheduleTillDate();
                 isNextRepaymentAvailable = false;
             }
+            if (loanApplicationTerms.isInterestRecalculationEnabled()) {
+                populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms,
+                        holidayDetailDTO, scheduleParams, loanCharges, currency);
+            }
 
             // populates the collection with transactions till the due date of
             // the period for interest recalculation enabled loans
@@ -316,6 +315,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                     currentPeriodParams.getFeeChargesForInstallment(), currentPeriodParams.getPenaltyChargesForInstallment(),
                     totalInstallmentDue, false);
 
+            addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
             // apply loan transactions on installments to identify early/late
             // payments for interest recalculation
             installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, currency, scheduleParams,
@@ -327,7 +327,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             // Updates principal paid map with efective date for reducing
             // the amount from outstanding balance(interest calculation)
             updateAmountsWithEffectiveDate(loanApplicationTerms, holidayDetailDTO, scheduleParams, scheduledDueDate, currentPeriodParams,
-                    installment);
+                    installment, lastRestDate);
 
             // handle cumulative fields
 
@@ -337,7 +337,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             scheduleParams.setPeriodStartDate(scheduledDueDate);
             scheduleParams.incrementInstalmentNumber();
             scheduleParams.incrementPeriodNumber();
-            scheduleParams.getCompoundingDateVariations().clear();
             if (termVariationParams.isRecalculateAmounts()) {
                 loanApplicationTerms.setCurrentPeriodFixedEmiAmount(null);
                 loanApplicationTerms.setCurrentPeriodFixedPrincipalAmount(null);
@@ -377,6 +376,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
         final BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
         final BigDecimal totalOutstanding = BigDecimal.ZERO;
 
+        updateCompoundingDetails(periods, scheduleParams, loanApplicationTerms);
         return LoanScheduleModel.from(periods, applicationCurrency, scheduleParams.getLoanTermInDays(),
                 scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativePrincipal().getAmount(), totalPrincipalPaid,
                 scheduleParams.getTotalCumulativeInterest().getAmount(), scheduleParams.getTotalFeeChargesCharged().getAmount(),
@@ -384,6 +384,30 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                 totalOutstanding);
     }
 
+    private void updateCompoundingDetails(final Collection<LoanScheduleModelPeriod> periods, final LoanScheduleParams params,
+            final LoanApplicationTerms loanApplicationTerms) {
+        final Map<LocalDate, Map<LocalDate, Money>> compoundingDetails = params.getCompoundingDateVariations();
+        if (compoundingDetails.isEmpty()) { return; }
+        for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
+            if (loanScheduleModelPeriod.isRepaymentPeriod() && loanScheduleModelPeriod.getLoanCompoundingDetails().isEmpty()) {
+                Map<LocalDate, Money> periodCompoundingDetails = compoundingDetails.get(loanScheduleModelPeriod.periodFromDate());
+                if (periodCompoundingDetails != null) {
+                    for (Map.Entry<LocalDate, Money> entry : periodCompoundingDetails.entrySet()) {
+                        if (entry.getValue().isGreaterThanZero() && !entry.getKey().isAfter(loanScheduleModelPeriod.periodDueDate())) {
+                            LocalDate effectiveDate = entry.getKey();
+                            if (loanApplicationTerms.allowCompoundingOnEod()) {
+                                effectiveDate = effectiveDate.minusDays(1);
+                            }
+                            LoanInterestRecalcualtionAdditionalDetails additionalDetails = new LoanInterestRecalcualtionAdditionalDetails(
+                                    effectiveDate, entry.getValue().getAmount());
+                            loanScheduleModelPeriod.getLoanCompoundingDetails().add(additionalDetails);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     private void applyChargesForCurrentPeriod(final Set<LoanCharge> loanCharges, final MonetaryCurrency currency,
             LoanScheduleParams scheduleParams, LocalDate scheduledDueDate, ScheduleCurrentPeriodParams currentPeriodParams) {
         PrincipalInterest principalInterest = new PrincipalInterest(currentPeriodParams.getPrincipalForThisPeriod(),
@@ -422,13 +446,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
 
     private void updateAmountsWithEffectiveDate(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
             LoanScheduleParams scheduleParams, LocalDate scheduledDueDate, ScheduleCurrentPeriodParams currentPeriodParams,
-            LoanScheduleModelPeriod installment) {
+            LoanScheduleModelPeriod installment, LocalDate lastRestDate) {
         LocalDate amountApplicableDate = installment.periodDueDate();
         if (loanApplicationTerms.isInterestRecalculationEnabled()) {
             amountApplicableDate = getNextRestScheduleDate(installment.periodDueDate().minusDays(1), loanApplicationTerms, holidayDetailDTO);
         }
         updateMapWithAmount(scheduleParams.getPrincipalPortionMap(),
                 currentPeriodParams.getPrincipalForThisPeriod().minus(currentPeriodParams.getReducedBalance()), amountApplicableDate);
+        updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, scheduleParams, lastRestDate, scheduledDueDate);
 
         // update outstanding balance for interest calculation
         updateOutstandingBalanceAsPerRest(scheduleParams, scheduledDueDate);
@@ -445,7 +470,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
         LoanScheduleModelPeriod modifiedInstallment = installment;
         if (scheduleParams.applyInterestRecalculation() && loanRepaymentScheduleTransactionProcessor != null) {
             Money principalProcessed = Money.zero(currency);
-            addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), modifiedInstallment);
             for (RecalculationDetail detail : applicableTransactions) {
                 if (!detail.isProcessed()) {
                     LocalDate transactionDate = detail.getTransactionDate();
@@ -489,10 +513,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                         }
 
                     }
+                    adjustCompoundedAmountWithPaidDetail(scheduleParams, lastRestDate, currentTransactions, loanApplicationTerms,
+                            holidayDetailDTO);
                 }
             }
             updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams.getLatePaymentMap(), scheduledDueDate,
-                    scheduleParams.getInstallments(), true, lastRestDate, scheduleParams.getCompoundingMap());
+                    scheduleParams.getInstallments(), true, lastRestDate);
             currentPeriodParams.minusPrincipalForThisPeriod(principalProcessed);
         }
         return modifiedInstallment;
@@ -600,9 +626,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             scheduleParams.getCompoundingMap().clear();
             scheduleParams.getCompoundingMap().putAll(
                     scheduleParams.getCompoundingDateVariations().get(periodStartDateApplicableForInterest));
-        } else {
-            scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
-                    new TreeMap<>(scheduleParams.getCompoundingMap()));
         }
     }
 
@@ -656,10 +679,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                             if (daysInPeriodApplicable > 0) {
                                 // 5 determine interest till the transaction
                                 // date
-                                if (!scheduleParams.getCompoundingDateVariations().containsKey(periodStartDateApplicableForInterest)) {
-                                    scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
-                                            new TreeMap<>(scheduleParams.getCompoundingMap()));
-                                }
                                 PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
                                         this.paymentPeriodsInOneYearCalculator,
                                         currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), scheduleParams
@@ -700,6 +719,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                                     scheduleParams.getOutstandingBalance(), interestForThisinstallment, feeChargesForInstallment,
                                     penaltyChargesForInstallment, totalInstallmentDue, true);
                             periods.add(installment);
+                            addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
+                            updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, scheduleParams, lastRestDate, scheduledDueDate);
 
                             // update outstanding balance for interest
                             // calculation as per the rest
@@ -716,10 +737,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                             periodStartDateApplicableForInterest = scheduleParams.getPeriodStartDate();
                             updateLatePaymentMap = true;
                             scheduleParams.incrementInstalmentNumber();
+                            populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms,
+                                    holidayDetailDTO, scheduleParams, loanCharges, currency);
                             // creates and insert Loan repayment schedule
                             // for
                             // the period
-                            addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
+
                         } else if (installment == null) {
                             installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1);
                         }
@@ -762,12 +785,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                         // identify late payments and add compounding
                         // details to
                         // map for interest calculation
-                        handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate,
-                                periodStartDateApplicableForInterest, detail);
+                        handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate, detail);
                         if (updateLatePaymentMap) {
                             updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams.getLatePaymentMap(),
-                                    scheduledDueDate, scheduleParams.getInstallments(), true, lastRestDate,
-                                    scheduleParams.getCompoundingMap());
+                                    scheduledDueDate, scheduleParams.getInstallments(), true, lastRestDate);
                         }
                     } else if (scheduleParams.getLoanRepaymentScheduleTransactionProcessor() != null) {
                         LocalDate applicableDate = getNextRestScheduleDate(transactionDate.minusDays(1), loanApplicationTerms,
@@ -776,9 +797,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                             List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
                             Money unprocessed = scheduleParams.getLoanRepaymentScheduleTransactionProcessor().handleRepaymentSchedule(
                                     currentTransactions, currency, scheduleParams.getInstallments());
-                            Money arrears = fetchCompoundedArrears(loanApplicationTerms, currency, detail.getTransaction());
+                            Money arrears = fetchArrears(loanApplicationTerms, currency, detail.getTransaction());
                             if (unprocessed.isGreaterThanZero()) {
-                                arrears = getTotalAmount(scheduleParams.getLatePaymentMap(), currency);
                                 updateMapWithAmount(scheduleParams.getPrincipalPortionMap(), unprocessed, applicableDate);
                                 currentPeriodParams.plusEarlyPaidAmount(unprocessed);
 
@@ -790,10 +810,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                                                 .calculateTillRestFrequencyEnabled()) {
 
                                     LocalDate calculateTill = transactionDate;
-                                    if (!scheduleParams.getCompoundingDateVariations().containsKey(periodStartDateApplicableForInterest)) {
-                                        scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
-                                                new TreeMap<>(scheduleParams.getCompoundingMap()));
-                                    }
                                     PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
                                             this.paymentPeriodsInOneYearCalculator,
                                             currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), scheduleParams
@@ -836,8 +852,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
 
                             }
                             if (arrears.isGreaterThanZero() && applicableDate.isBefore(lastRestDate)) {
-                                handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate,
-                                        periodStartDateApplicableForInterest, detail);
+                                handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate, detail);
                             }
                         }
 
@@ -862,12 +877,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
      * @param detail
      */
     private void handleLatePayments(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
-            final MonetaryCurrency currency, LoanScheduleParams scheduleParams, LocalDate lastRestDate,
-            LocalDate periodStartDateApplicableForInterest, RecalculationDetail detail) {
+            final MonetaryCurrency currency, LoanScheduleParams scheduleParams, LocalDate lastRestDate, RecalculationDetail detail) {
         updateLatePaidAmountsToPrincipalMap(detail.getTransaction(), loanApplicationTerms, currency, holidayDetailDTO, lastRestDate,
                 scheduleParams);
-        scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
-                new TreeMap<>(scheduleParams.getCompoundingMap()));
     }
 
     private void updateAmountsBasedOnEarlyPayment(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
@@ -1064,9 +1076,16 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
         return isAmountChanged;
     }
 
-    private Money fetchCompoundedArrears(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
+    private Money fetchArrears(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
             final LoanTransaction transaction) {
         Money arrears = transaction.getPrincipalPortion(currency);
+        arrears = arrears.plus(fetchCompoundedArrears(loanApplicationTerms, currency, transaction));
+        return arrears;
+    }
+
+    private Money fetchCompoundedArrears(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
+            final LoanTransaction transaction) {
+        Money arrears = Money.zero(currency);
         if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
             arrears = arrears.plus(transaction.getInterestPortion(currency));
         }
@@ -1096,7 +1115,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             final Collection<RecalculationDetail> transactions, final Set<LoanCharge> loanCharges, final LoanScheduleParams params) {
         boolean isFirstRepayment = false;
         LocalDate startDate = params.getPeriodStartDate();
-        Money outstanding = Money.zero(currency);
+        Money outstanding = params.getOutstandingBalanceAsPerRest();
         Money totalInterest = Money.zero(currency);
         Money totalCumulativeInterest = Money.zero(currency);
         double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0);
@@ -1111,15 +1130,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             if (params.getActualRepaymentDate().isAfter(currentDate)) {
                 params.setActualRepaymentDate(currentDate);
             }
-            outstanding = updateOutstandingFromLatePayment(params.getPeriodStartDate(), params.getLatePaymentMap(), outstanding);
 
             Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(
                     params.applyInterestRecalculation(), params.getActualRepaymentDate(), transactions);
 
-            if (!params.getLatePaymentMap().isEmpty()) {
-                populateCompoundingDatesInPeriod(params.getPeriodStartDate(), params.getActualRepaymentDate(), currentDate,
-                        loanApplicationTerms, holidayDetailDTO, params.getCompoundingMap(), loanCharges, currency);
-            }
+            populateCompoundingDatesInPeriod(params.getPeriodStartDate(), params.getActualRepaymentDate(), loanApplicationTerms,
+                    holidayDetailDTO, params, loanCharges, currency);
 
             for (RecalculationDetail detail : applicableTransactions) {
                 if (detail.isProcessed()) {
@@ -1146,22 +1162,30 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                     totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest);
                     totalInterest = totalInterest.zero();
                     addLoanRepaymentScheduleInstallment(params.getInstallments(), installment);
+                    updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, params, lastRestDate, transactionDate);
+                    populateCompoundingDatesInPeriod(installment.periodDueDate(), params.getActualRepaymentDate(), loanApplicationTerms,
+                            holidayDetailDTO, params, loanCharges, currency);
+                    params.setCompoundedInLastInstallment(params.getUnCompoundedAmount());
                     params.setPeriodStartDate(transactionDate);
                     startDate = transactionDate;
                 }
                 loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions, currency, params.getInstallments());
+                updateLatePaidAmountsToPrincipalMap(detail.getTransaction(), loanApplicationTerms, currency, holidayDetailDTO,
+                        lastRestDate, params);
                 updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, params.getLatePaymentMap(), currentDate,
-                        params.getInstallments(), false, lastRestDate, params.getCompoundingMap());
-                outstanding = outstanding.zero();
-                outstanding = updateOutstandingFromLatePayment(params.getPeriodStartDate(), params.getLatePaymentMap(), outstanding);
-                outstanding = updateBalanceForInterestCalculation(params.getPrincipalPortionMap(), params.getPeriodStartDate(),
-                        outstanding, false);
-                if (params.getLatePaymentMap().isEmpty() && !outstanding.isGreaterThanZero()) {
+                        params.getInstallments(), false, lastRestDate);
+                if (params.getLatePaymentMap().isEmpty() && isCompleted(params.getInstallments())) {
+                    outstanding = outstanding.zero();
+                } else {
+                    outstanding = updateBalanceForInterestCalculation(params.getPrincipalPortionMap(), params.getPeriodStartDate(),
+                            outstanding, false);
+                }
+                if (params.getLatePaymentMap().isEmpty() && outstanding.isZero()) {
                     break;
                 }
             }
 
-            if (outstanding.isGreaterThanZero()) {
+            if (!outstanding.isZero()) {
                 PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
                         this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(),
                         totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
@@ -1169,15 +1193,31 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                         params.getActualRepaymentDate(), applicableVariations);
                 Money interest = principalInterestForThisPeriod.interest();
                 totalInterest = totalInterest.plus(interest);
-                if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
-                    LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(params.getActualRepaymentDate().minusDays(1),
-                            loanApplicationTerms, holidayDetailDTO);
-                    params.getLatePaymentMap().put(compoundingEffectiveDate, interest);
 
+                Money uncompounded = params.getUnCompoundedAmount();
+                Money compounded = uncompounded.zero();
+                for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) {
+                    if (mapEntry.getKey().isAfter(params.getPeriodStartDate())) {
+                        compounded = compounded.plus(mapEntry.getValue());
+                    }
+                }
+                Money compoundedForThisPeriod = compounded.minus(uncompounded);
+                Money uncompoundedForThisPeriod = interest.minus(compoundedForThisPeriod);
+                params.setUnCompoundedAmount(uncompoundedForThisPeriod);
+                LocalDate compoundingDate = params.getPeriodStartDate();
+                if (loanApplicationTerms.allowCompoundingOnEod()) {
+                    compoundingDate = compoundingDate.minusDays(1);
+                }
+                compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO);
+                if(compoundingDate.isEqual(params.getActualRepaymentDate())){
+                    params.getCompoundingMap().put(compoundingDate, uncompoundedForThisPeriod);
+                    params.setUnCompoundedAmount(uncompoundedForThisPeriod.zero());
                 }
+                
+
             }
             params.setPeriodStartDate(params.getActualRepaymentDate());
-        } while (params.getActualRepaymentDate().isBefore(currentDate) && outstanding.isGreaterThanZero());
+        } while (params.getActualRepaymentDate().isBefore(currentDate) && !outstanding.isZero());
 
         if (totalInterest.isGreaterThanZero()) {
             LoanScheduleModelRepaymentPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(params.getInstalmentNumber(),
@@ -1185,11 +1225,23 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                     totalInterest.zero(), totalInterest.zero(), totalInterest, true);
             params.incrementInstalmentNumber();
             periods.add(installment);
+            params.getCompoundingDateVariations().put(startDate, new TreeMap<>(params.getCompoundingMap()));
             totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest);
         }
         return totalCumulativeInterest;
     }
 
+    private boolean isCompleted(List<LoanRepaymentScheduleInstallment> installments) {
+        boolean isCompleted = true;
+        for (LoanRepaymentScheduleInstallment installment : installments) {
+            if (installment.isNotFullyPaidOff()) {
+                isCompleted = false;
+                break;
+            }
+        }
+        return isCompleted;
+    }
+
     private Collection<RecalculationDetail> getApplicableTransactionsForPeriod(final boolean applyInterestRecalculation,
             LocalDate repaymentDate, final Collection<RecalculationDetail> transactions) {
         Collection<RecalculationDetail> applicableTransactions = new ArrayList<>();
@@ -1221,21 +1273,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
         currentTransactions.add(detail.getTransaction());
         detail.setProcessed(true);
         return currentTransactions;
-    }
 
-    private Money updateOutstandingFromLatePayment(LocalDate periodStartDate, Map<LocalDate, Money> latePaymentMap, Money outstanding) {
-        Map<LocalDate, Money> retainEntries = new HashMap<>();
-        for (Map.Entry<LocalDate, Money> mapEntry : latePaymentMap.entrySet()) {
-            if (!mapEntry.getKey().isAfter(periodStartDate)) {
-                outstanding = outstanding.plus(mapEntry.getValue());
-            } else {
-                retainEntries.put(mapEntry.getKey(), mapEntry.getValue());
-            }
-        }
-        latePaymentMap.clear();
-        latePaymentMap.putAll(retainEntries);
-        retainEntries.clear();
-        return outstanding;
     }
 
     /**
@@ -1315,22 +1353,13 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                 holidayDetailDTO);
 
         Money principalPortion = loanTransaction.getPrincipalPortion(currency);
-        Money compoundedLatePayments = Money.zero(currency);
-        if (applicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
-            compoundedLatePayments = compoundedLatePayments.plus(loanTransaction.getInterestPortion(currency));
-        }
-        if (applicationTerms.getInterestRecalculationCompoundingMethod().isFeeCompoundingEnabled()) {
-            compoundedLatePayments = compoundedLatePayments.plus(loanTransaction.getFeeChargesPortion(currency)).plus(
-                    loanTransaction.getPenaltyChargesPortion(currency));
-        }
 
-        updateCompoundingAmount(params.getPrincipalPortionMap(), params.getLatePaymentMap(), currency, lastRestDate, principalPortion,
-                applicableDate);
-        updateCompoundingAmount(params.getPrincipalPortionMap(), params.getCompoundingMap(), currency, lastRestDate,
-                compoundedLatePayments, applicableDate);
+        updateLatePaymentCompoundingAmount(params.getPrincipalPortionMap(), params.getLatePaymentMap(), currency, lastRestDate,
+                principalPortion, applicableDate);
+        adjustCompoundedAmountWithPaidDetail(params, lastRestDate, applicableDate, loanTransaction, applicationTerms);
     }
 
-    private void updateCompoundingAmount(final Map<LocalDate, Money> principalVariationMap,
+    private void updateLatePaymentCompoundingAmount(final Map<LocalDate, Money> principalVariationMap,
             final Map<LocalDate, Money> latePaymentCompoundingMap, final MonetaryCurrency currency, final LocalDate lastRestDate,
             Money compoundedPortion, final LocalDate applicableDate) {
         Money appliedOnPrincipalVariationMap = Money.zero(currency);
@@ -1368,17 +1397,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
      */
     private void updateLatePaymentsToMap(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
             final MonetaryCurrency currency, final Map<LocalDate, Money> latePaymentMap, final LocalDate scheduledDueDate,
-            List<LoanRepaymentScheduleInstallment> installments, boolean applyRestFrequencyForPrincipal, final LocalDate lastRestDate,
-            final TreeMap<LocalDate, Money> compoundingMap) {
+            List<LoanRepaymentScheduleInstallment> installments, boolean applyRestFrequencyForPrincipal, final LocalDate lastRestDate) {
         latePaymentMap.clear();
         LocalDate currentDate = DateUtils.getLocalDateOfTenant();
 
         Money totalCompoundingAmount = Money.zero(currency);
-        Money compoundedMoney = Money.zero(currency);
-        if (!compoundingMap.isEmpty()) {
-            compoundedMoney = compoundingMap.get(lastRestDate);
-        }
-        boolean clearCompoundingMap = true;
         for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
             if (loanRepaymentScheduleInstallment.isNotFullyPaidOff()
                     && !loanRepaymentScheduleInstallment.getDueDate().isAfter(scheduledDueDate)
@@ -1395,104 +1418,181 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                             .plus(loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency));
                 }
 
-                final Money changedCompoundedMoney = updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency,
-                        compoundingMap, loanRepaymentScheduleInstallment, lastRestDate, compoundedMoney, scheduledDueDate);
-                if (compoundedMoney.isZero() || !compoundedMoney.isEqualTo(changedCompoundedMoney)) {
-                    compoundedMoney = changedCompoundedMoney;
-                    clearCompoundingMap = false;
-                }
             }
         }
         if (totalCompoundingAmount.isGreaterThanZero()) {
             updateMapWithAmount(latePaymentMap, totalCompoundingAmount.negated(), lastRestDate);
         }
-        if (clearCompoundingMap) {
-            compoundingMap.clear();
-        }
     }
 
-    private Money updateMapWithCompoundingDetails(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
-            final MonetaryCurrency currency, final TreeMap<LocalDate, Money> compoundingMap,
-            final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment, final LocalDate lastRestDate,
-            final Money compoundedMoney, final LocalDate scheduledDueDate) {
-        Money ignoreMoney = compoundedMoney;
-        if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
-            LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(loanRepaymentScheduleInstallment.getDueDate().minusDays(1),
-                    loanApplicationTerms, holidayDetailDTO);
+    private void updateCompoundingMap(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
+            final LoanScheduleParams params, final LocalDate lastRestDate, final LocalDate scheduledDueDate) {
+        if (loanApplicationTerms.isInterestRecalculationEnabled()
+                && loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
+            final MonetaryCurrency currency = params.getCurrency();
+            Money totalCompoundedAmount = Money.zero(currency);
+            boolean lastInstallmentIsPastDate = false;
+            for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : params.getInstallments()) {
+                if (params.getCompoundingDateVariations().containsKey(loanRepaymentScheduleInstallment.getFromDate())) {
+                    lastInstallmentIsPastDate = params.applyInterestRecalculation()
+                            && loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
+                } else {
+                    final boolean isPastDate = params.applyInterestRecalculation()
+                            && loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
+                    boolean periodHasCompoundingDate = false;
+                    Money amountCharged = getIncomeForCompounding(loanApplicationTerms, currency, loanRepaymentScheduleInstallment);
+                    final Map<LocalDate, Money> compoundingMap = params.getCompoundingMap();
+                    LocalDate effectiveStartDate = loanRepaymentScheduleInstallment.getFromDate();
+                    if (loanApplicationTerms.allowCompoundingOnEod()) {
+                        effectiveStartDate = loanRepaymentScheduleInstallment.getFromDate().minusDays(1);
+                    }
+                    LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(effectiveStartDate, loanApplicationTerms,
+                            holidayDetailDTO);
+                    final LocalDate restDate = getNextRestScheduleDate(scheduledDueDate.minusDays(1), loanApplicationTerms,
+                            holidayDetailDTO);
+                    if (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
+                        totalCompoundedAmount = totalCompoundedAmount.minus(params.getUnCompoundedAmount());
+                        periodHasCompoundingDate = true;
+                    }
+                    while (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
+                        if (compoundingEffectiveDate.isEqual(loanRepaymentScheduleInstallment.getDueDate())) {
+                            Money amountToBeCompounding = amountCharged.minus(totalCompoundedAmount);
+                            updateMapWithAmount(compoundingMap, amountToBeCompounding, compoundingEffectiveDate);
+                            totalCompoundedAmount = totalCompoundedAmount.plus(amountToBeCompounding);
+
+                        } else if (compoundingMap.containsKey(compoundingEffectiveDate)) {
+                            Money compounedAmount = compoundingMap.get(compoundingEffectiveDate);
+                            totalCompoundedAmount = totalCompoundedAmount.plus(compounedAmount);
+                        }
 
-            if (compoundingEffectiveDate.isBefore(DateUtils.getLocalDateOfTenant())) {
-                Money amount = Money.zero(currency);
-                switch (loanApplicationTerms.getInterestRecalculationCompoundingMethod()) {
-                    case INTEREST:
-                        amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
-                    break;
-                    case FEE:
-                        amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
-                        amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
-                    break;
-                    case INTEREST_AND_FEE:
-                        amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
-                        amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
-                        amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
-                    break;
-                    default:
-                    break;
-                }
-                if (compoundingEffectiveDate.isBefore(scheduledDueDate)) {
-                    ignoreMoney = ignoreMoney.plus(amount);
-                    if (ignoreMoney.isGreaterThanZero()) {
-                        updateMapWithAmount(compoundingMap, ignoreMoney, compoundingEffectiveDate);
-                        updateMapWithAmount(compoundingMap, ignoreMoney.negated(), lastRestDate);
-                        ignoreMoney = ignoreMoney.zero();
+                        if (!loanApplicationTerms.allowCompoundingOnEod()) {
+                            compoundingEffectiveDate = compoundingEffectiveDate.plusDays(1);
+                        }
+                        compoundingEffectiveDate = getNextCompoundScheduleDate(compoundingEffectiveDate, loanApplicationTerms,
+                                holidayDetailDTO);
                     }
-                } else {
-                    if (ignoreMoney.isLessThanZero()) {
-                        LocalDate firstKey = compoundingMap.firstKey();
-                        updateMapWithAmount(compoundingMap, ignoreMoney, firstKey);
-                        updateMapWithAmount(compoundingMap, ignoreMoney.negated(), lastRestDate);
-                        ignoreMoney = ignoreMoney.zero();
+                    if (periodHasCompoundingDate) {
+                        if (isPastDate) {
+                            updateMapWithAmount(params.getPrincipalPortionMap(),
+                                    totalCompoundedAmount.plus(params.getUnCompoundedAmount()), lastRestDate);
+                        } else {
+                            Money amountToBeEffected = amountCharged;
+                            if (lastInstallmentIsPastDate) {
+                                amountToBeEffected = amountToBeEffected.plus(params.getUnCompoundedAmount());
+                            }
+                            updateMapWithAmount(params.getPrincipalPortionMap(), amountToBeEffected, restDate);
+                        }
+                    }
+                    if (totalCompoundedAmount.isGreaterThanZero()) {
+                        params.getCompoundingDateVariations().put(loanRepaymentScheduleInstallment.getFromDate(),
+                                new TreeMap<>(params.getCompoundingMap()));
+                        for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) {
+                            if (!mapEntry.getKey().isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
+                                updateMapWithAmount(params.getPrincipalPortionMap(), mapEntry.getValue().negated(), mapEntry.getKey());
+                            }else if(params.getUnCompoundedAmount().isEqualTo( mapEntry.getValue())){
+                                totalCompoundedAmount = totalCompoundedAmount.plus(params.getUnCompoundedAmount());
+                            }
+                        }
+                        params.minusUnCompoundedAmount(params.getUnCompoundedAmount());
+                        params.getCompoundingMap().clear();
+                        params.addUnCompoundedAmount(amountCharged.minus(totalCompoundedAmount.minus(params.getCompoundedInLastInstallment())));
+                    } else {
+                        params.getCompoundingMap().clear();
+                        params.getCompoundingDateVariations().put(loanRepaymentScheduleInstallment.getFromDate(),
+                                new TreeMap<>(params.getCompoundingMap()));
+                        params.addUnCompoundedAmount(amountCharged);
                     }
-                    updateMapWithAmount(compoundingMap, amount, compoundingEffectiveDate);
-                    updateMapWithAmount(compoundingMap, amount.negated(), lastRestDate);
+                    params.setCompoundedInLastInstallment(amountCharged.zero());
+                    lastInstallmentIsPastDate = isPastDate;
                 }
+
             }
         }
-        return ignoreMoney;
+
+    }
+
+    private Money getIncomeForCompounding(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
+            LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
+        Money interestCharged = Money.zero(currency);
+        Money feeCharged = Money.zero(currency);
+        Money penaltyCharged = Money.zero(currency);
+        Money amountCharged = Money.zero(currency);
+        switch (loanApplicationTerms.getInterestRecalculationCompoundingMethod()) {
+            case INTEREST:
+                interestCharged = interestCharged.plus(loanRepaymentScheduleInstallment.getInterestCharged(currency));
+            break;
+            case FEE:
+                feeCharged = feeCharged.plus(loanRepaymentScheduleInstallment.getFeeChargesCharged(currency));
+                penaltyCharged = penaltyCharged.plus(loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency));
+            break;
+            case INTEREST_AND_FEE:
+                interestCharged = interestCharged.plus(loanRepaymentScheduleInstallment.getInterestCharged(currency));
+                feeCharged = feeCharged.plus(loanRepaymentScheduleInstallment.getFeeChargesCharged(currency));
+                penaltyCharged = penaltyCharged.plus(loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency));
+            break;
+            default:
+            break;
+        }
+        amountCharged = interestCharged.plus(feeCharged).plus(penaltyCharged);
+        return amountCharged;
+    }
+
+    private void adjustCompoundedAmountWithPaidDetail(final LoanScheduleParams params, final LocalDate lastRestDate,
+            final Collection<LoanTransaction> transactions, final LoanApplicationTerms loanApplicationTerms,
+            HolidayDetailDTO holidayDetailDTO) {
+        for (LoanTransaction loanTransaction : transactions) {
+            final LocalDate amountApplicableDate = getNextRestScheduleDate(loanTransaction.getTransactionDate().minusDays(1),
+                    loanApplicationTerms, holidayDetailDTO);
+            adjustCompoundedAmountWithPaidDetail(params, lastRestDate, amountApplicableDate, loanTransaction, loanApplicationTerms);
+        }
+    }
+
+    private void adjustCompoundedAmountWithPaidDetail(final LoanScheduleParams params, final LocalDate lastRestDate,
+            final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms) {
+        adjustCompoundedAmountWithPaidDetail(params.getPrincipalPortionMap(), lastRestDate, amountApplicableDate, transaction,
+                loanApplicationTerms, params.getCurrency());
+    }
+
+    private void adjustCompoundedAmountWithPaidDetail(final Map<LocalDate, Money> principalPortionMap, final LocalDate lastRestDate,
+            final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms,
+            final MonetaryCurrency currency) {
+        if (!amountApplicableDate.isEqual(lastRestDate)) {
+            Money compoundedIncome = fetchCompoundedArrears(loanApplicationTerms, currency, transaction);
+            updateMapWithAmount(principalPortionMap, compoundedIncome, amountApplicableDate);
+            updateMapWithAmount(principalPortionMap, compoundedIncome.negated(), lastRestDate);
+        }
     }
 
-    private void populateCompoundingDatesInPeriod(final LocalDate startDate, final LocalDate endDate, final LocalDate currentDate,
+    private void populateCompoundingDatesInPeriod(final LocalDate startDate, final LocalDate endDate,
             final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
-            final Map<LocalDate, Money> compoundingMap, final Set<LoanCharge> charges, MonetaryCurrency currency) {
+            final LoanScheduleParams scheduleParams, final Set<LoanCharge> charges, MonetaryCurrency currency) {
         if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
+            final Map<LocalDate, Money> compoundingMap = scheduleParams.getCompoundingMap();
             LocalDate lastCompoundingDate = startDate;
             LocalDate compoundingDate = startDate;
-            while (compoundingDate.isBefore(endDate) && compoundingDate.isBefore(currentDate)) {
+            boolean addUncompounded = true;
+            while (compoundingDate.isBefore(endDate)) {
+                if (loanApplicationTerms.allowCompoundingOnEod()) {
+                    compoundingDate = compoundingDate.minusDays(1);
+                }
                 compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO);
-                if (!compoundingDate.isBefore(currentDate)) {
-                    break;
-                } else if (compoundingDate.isAfter(endDate)) {
-                    updateMapWithAmount(compoundingMap, Money.zero(currency), compoundingDate);
-                } else {
+
+                if (compoundingDate.isBefore(endDate)) {
                     Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(lastCompoundingDate, compoundingDate, charges, currency,
                             null, loanApplicationTerms.getPrincipal(), null, false);
                     Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(lastCompoundingDate, compoundingDate, charges,
                             currency, null, loanApplicationTerms.getPrincipal(), null, false);
-                    updateMapWithAmount(compoundingMap, feeChargesForInstallment.plus(penaltyChargesForInstallment), compoundingDate);
+                    Money compoundAmount = feeChargesForInstallment.plus(penaltyChargesForInstallment);
+                    if (addUncompounded) {
+                        compoundAmount = compoundAmount.plus(scheduleParams.getUnCompoundedAmount());
+                        addUncompounded = false;
+                    }
+                    updateMapWithAmount(compoundingMap, compoundAmount, compoundingDate);
                 }
-                lastCompoundingDate = compoundingDate;
-            }
-        }
-    }
 
-    protected void clearMapDetails(final LocalDate startDate, final Map<LocalDate, Money> compoundingMap) {
-        Map<LocalDate, Money> temp = new HashMap<>();
-        for (LocalDate date : compoundingMap.keySet()) {
-            if (!date.isBefore(startDate)) {
-                temp.put(date, compoundingMap.get(date));
+                lastCompoundingDate = compoundingDate;
             }
         }
-        compoundingMap.clear();
-        compoundingMap.putAll(temp);
     }
 
     /**
@@ -1580,16 +1680,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             principalPaid = map.get(amountApplicableDate).plus(principalPaid);
         }
         map.put(amountApplicableDate, principalPaid);
-    }
 
-    private Money getTotalAmount(final Map<LocalDate, Money> map, final MonetaryCurrency currency) {
-        Money total = Money.zero(currency);
-        for (Map.Entry<LocalDate, Money> mapEntry : map.entrySet()) {
-            if (mapEntry.getKey().isBefore(DateUtils.getLocalDateOfTenant())) {
-                total = total.plus(mapEntry.getValue());
-            }
-        }
-        return total;
     }
 
     @Override
@@ -1737,8 +1828,9 @@ 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, isSkipRepaymentonmonthFirst, numberofdays);
+            final LoanApplicationTerms loanApplicationTerms = loan
+                    .getLoanApplicationTerms(applicationCurrency, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
+                            floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays, holidayDetailDTO);
 
             // for applying variations
             Collection<LoanTermVariationsData> loanTermVariations = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
@@ -2117,6 +2209,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             // action will be performed on this value
             Money reducePrincipal = outstandingBalanceAsPerRest.zero();
 
+            Money uncompoundedAmount = outstandingBalanceAsPerRest.zero();
             // principal changes will be added along with date(after applying
             // rest)
             // from when these amounts will effect the outstanding balance for
@@ -2133,6 +2226,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             // from when these amounts will effect the outstanding balance for
             // interest calculation
             final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
+            final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
             LocalDate currentDate = DateUtils.getLocalDateOfTenant();
             LocalDate lastRestDate = currentDate;
             if (loanApplicationTerms.getRestCalendarInstance() != null) {
@@ -2179,6 +2273,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                 // process the installment only if recalculate from date is
                 // greater than due date
                 if (installment.getDueDate().isAfter(lastInstallmentDate)) {
+                    if (totalCumulativePrincipal.isGreaterThanOrEqualTo(loanApplicationTerms.getTotalDisbursedAmount())) {
+                        break;
+                    }
                     LocalDate previousRepaymentDate = actualRepaymentDate;
                     actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
                             isFirstRepayment, holidayDetailDTO);
@@ -2272,6 +2369,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                 // updates map with the installment principal amount excluding
                 // unprocessed amount since this amount is already accounted.
                 updateMapWithAmount(principalPortionMap, installment.getPrincipal(currency).minus(unprocessed), amountApplicableDate);
+                uncompoundedAmount = updateCompoundingDetailsForPartialScheduleGeneration(installment, loanApplicationTerms,
+                        principalPortionMap, compoundingDateVariations, uncompoundedAmount, applicableTransactions, lastRestDate,
+                        holidayDetailDTO);
                 // update outstanding balance for interest calculation
                 outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap, installment.getDueDate(),
                         outstandingBalanceAsPerRest, false);
@@ -2284,7 +2384,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
 
             // updates the map with over due amounts
             updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, lastInstallmentDate,
-                    newRepaymentScheduleInstallments, true, lastRestDate, compoundingMap);
+                    newRepaymentScheduleInstallments, true, lastRestDate);
 
             // for partial schedule generation
             if (!newRepaymentScheduleInstallments.isEmpty() && totalCumulativeInterest.isGreaterThanZero()) {
@@ -2293,10 +2393,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                         loanTermInDays, periodStartDate, actualRepaymentDate, totalCumulativePrincipal, totalCumulativeInterest,
                         totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
                         totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap,
-                        disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest,
+                        uncompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest,
                         newRepaymentScheduleInstallments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
                         scheduleTillDate, currency, applyInterestRecalculation);
                 retainedInstallments.addAll(newRepaymentScheduleInstallments);
+                loanScheduleParams.getCompoundingDateVariations().putAll(compoundingDateVariations);
             }
 
         }
@@ -2328,6 +2429,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
             final Map<LocalDate, Money> principalPortionMap, LoanRepaymentScheduleInstallment installment,
             Collection<RecalculationDetail> applicableTransactions, Money actualPrincipalPortion) {
         Money unprocessed = Money.zero(currency);
+        Money totalUnprocessed = Money.zero(currency);
         for (RecalculationDetail detail : applicableTransactions) {
             if (!detail.isProcessed()) {
                 Money principalProcessed = installment.getPrincipalCompleted(currency);
@@ -2357,10 +2459,53 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                 LocalDate applicableDate = getNextRestScheduleDate(detail.getTransactionDate().minusDays(1), loanApplicationTerms,
                         holidayDetailDTO);
                 updateMapWithAmount(principalPortionMap, unprocessed, applicableDate);
+                totalUnprocessed = totalUnprocessed.plus(unprocessed);
+
+            }
+        }
+        return totalUnprocessed;
+    }
 
+    private Money updateCompoundingDetailsForPartialScheduleGeneration(final LoanRepaymentScheduleInstallment installment,
+            LoanApplicationTerms loanApplicationTerms, Map<LocalDate, Money> principalMap,
+            final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations, final Money uncompoundedAmount,
+            final Collection<RecalculationDetail> applicableTransactions, LocalDate lastRestDate, HolidayDetailDTO holidayDetailDTO) {
+        Money uncompounded = uncompoundedAmount;
+        MonetaryCurrency currency = uncompoundedAmount.getCurrency();
+        for (RecalculationDetail detail : applicableTransactions) {
+            LocalDate applicableDate = getNextRestScheduleDate(detail.getTransactionDate().minusDays(1), loanApplicationTerms,
+                    holidayDetailDTO);
+            adjustCompoundedAmountWithPaidDetail(principalMap, lastRestDate, applicableDate, detail.getTransaction(), loanApplicationTerms,
+                    currency);
+        }
+        Money amountCharged = getIncomeForCompounding(loanApplicationTerms, currency, installment);
+        final List<LoanInterestRecalcualtionAdditionalDetails> details = installment.getLoanCompoundingDetails();
+        Money totalCompounded = Money.zero(currency);
+        Map<LocalDate, Money> compoundingMap = new TreeMap<>();
+        for (LoanInterestRecalcualtionAdditionalDetails additionalDetails : details) {
+            LocalDate effectiveDate = additionalDetails.getEffectiveDate();
+            if (loanApplicationTerms.allowCompoundingOnEod()) {
+                effectiveDate = effectiveDate.plusDays(1);
+            }
+            compoundingMap.put(effectiveDate, Money.of(currency, additionalDetails.getAmount()));
+            totalCompounded = totalCompounded.plus(additionalDetails.getAmount());
+            updateMapWithAmount(principalMap, Money.of(currency, additionalDetails.getAmount()).negated(), effectiveDate);
+        }
+        compoundingDateVariations.put(installment.getFromDate(), compoundingMap);
+        if (totalCompounded.isGreaterThanZero()) {
+            final boolean isPastDate = installment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
+            final LocalDate restDate = getNextRestScheduleDate(installment.getDueDate().minusDays(1), loanApplicationTerms,
+                    holidayDetailDTO);
+            if (isPastDate) {
+                updateMapWithAmount(principalMap, totalCompounded, lastRestDate);
+            } else {
+                updateMapWithAmount(principalMap, totalCompounded, restDate);
             }
+            uncompounded = amountCharged.plus(uncompounded).minus(totalCompounded);
+        } else {
+            uncompounded = uncompounded.plus(amountCharged);
         }
-        return unprocessed;
+        return uncompounded;
     }
 
     private void updateAmortization(final MathContext mc, final LoanApplicationTerms loanApplicationTerms, int periodNumber,
@@ -2432,7 +2577,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                     scheduledLoanInstallment.periodFromDate(), scheduledLoanInstallment.periodDueDate(),
                     scheduledLoanInstallment.principalDue(), scheduledLoanInstallment.interestDue(),
                     scheduledLoanInstallment.feeChargesDue(), scheduledLoanInstallment.penaltyChargesDue(),
-                    scheduledLoanInstallment.isRecalculatedInterestComponent());
+                    scheduledLoanInstallment.isRecalculatedInterestComponent(), scheduledLoanInstallment.getLoanCompoundingDetails());
             installments.add(installment);
         }
         return installment;
@@ -2473,6 +2618,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
         } else {
             CalendarInstance calendarInstance = loanApplicationTerms.getCompoundingCalendarInstance();
             nextScheduleDate = CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), startDate);
+            if (loanApplicationTerms.allowCompoundingOnEod()) {
+                nextScheduleDate = nextScheduleDate.plusDays(1);
+            }
         }
 
         return nextScheduleDate;
@@ -2510,9 +2658,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
                 penaltyCharges = penaltyCharges.plus(currentInstallment.getPenaltyChargesOutstanding(currency));
             }
         }
-
+        final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
         return new LoanRepaymentScheduleInstallment(null, 0, onDate, onDate, totalPrincipal.getAmount(), totalInterest.getAmount(),
-                feeCharges.getAmount(), penaltyCharges.getAmount(), false);
+                feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
index f53a50e..1bbefa4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
@@ -25,7 +25,6 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.TreeMap;
 
-import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
@@ -70,7 +69,6 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
 
         LocalDate interestStartDate = periodStartDate;
         Money interestForThisInstallment = totalCumulativePrincipal.zero();
-        Money compoundedMoney = totalCumulativePrincipal.zero();
         Money compoundedInterest = totalCumulativePrincipal.zero();
         Money balanceForInterestCalculation = outstandingBalance;
         Money cumulatingInterestDueToGrace = cumulatingInterestPaymentDueToGrace;
@@ -89,13 +87,6 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
             }
         }
         if (principalVariation != null) {
-            // identifies rest date after current date for reducing all
-            // compounding
-            // values
-            LocalDate compoundingEndDate = principalVariation.ceilingKey(DateUtils.getLocalDateOfTenant());
-            if (compoundingEndDate == null) {
-                compoundingEndDate = DateUtils.getLocalDateOfTenant();
-            }
 
             for (Map.Entry<LocalDate, Money> principal : principalVariation.entrySet()) {
 
@@ -120,7 +111,7 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
                         }
                         // fee compounding will be done after calculation
                         compoundFee = compoundingMap.get(principal.getKey());
-                        compoundedMoney = compoundedMoney.plus(interestToBeCompounded).plus(compoundFee);
+                        compoundingMap.put(principal.getKey(), interestToBeCompounded.plus(compoundFee));
                     }
                     balanceForInterestCalculation = balanceForInterestCalculation.plus(principal.getValue()).plus(compoundFee);
                     if (interestRates.containsKey(principal.getKey())) {
@@ -129,14 +120,6 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
                 }
 
             }
-            if (!periodEndDate.isBefore(compoundingEndDate)) {
-                balanceForInterestCalculation = balanceForInterestCalculation.minus(compoundedMoney);
-                compoundingMap.clear();
-            } else if (compoundedMoney.isGreaterThanZero()) {
-                compoundingMap.put(periodEndDate, compoundedMoney);
-                compoundingMap.put(compoundingEndDate, compoundedMoney.negated());
-                clearMapDetails(periodEndDate, compoundingMap);
-            }
         }
 
         final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 7afc002..b57f215 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
@@ -62,8 +62,8 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
         } else {
             Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
             dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
-                    loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, loanApplicationTerms.getNthDay(),
-                    loanApplicationTerms.getWeekDayType());
+                    loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, null,
+                    null);
             dueRepaymentPeriodDate = CalendarUtils.adjustDate(dueRepaymentPeriodDate, loanApplicationTerms.getSeedDate(),
                     loanApplicationTerms.getRepaymentPeriodFrequencyType());
             if (currentCalendar != null) {
@@ -219,7 +219,8 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
 
     @Override
     public LocalDate idealDisbursementDateBasedOnFirstRepaymentDate(final PeriodFrequencyType repaymentPeriodFrequencyType,
-            final int repaidEvery, final LocalDate firstRepaymentDate) {
+            final int repaidEvery, final LocalDate firstRepaymentDate, final Calendar loanCalendar, final HolidayDetailDTO holidayDetailDTO, 
+            final LoanApplicationTerms loanApplicationTerms) {
 
         LocalDate idealDisbursementDate = null;
 
@@ -231,7 +232,15 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
                 idealDisbursementDate = firstRepaymentDate.minusWeeks(repaidEvery);
             break;
             case MONTHS:
-                idealDisbursementDate = firstRepaymentDate.minusMonths(repaidEvery);
+                if (loanCalendar == null) {
+                    idealDisbursementDate = firstRepaymentDate.minusMonths(repaidEvery);
+                } else {
+                    idealDisbursementDate = CalendarUtils.getNewRepaymentMeetingDate(loanCalendar.getRecurrence(),
+                            firstRepaymentDate.minusMonths(repaidEvery), firstRepaymentDate.minusMonths(repaidEvery), repaidEvery,
+                            CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType),
+                            holidayDetailDTO.getWorkingDays(), loanApplicationTerms.isSkipRepaymentOnFirstDayofMonth(),
+                            loanApplicationTerms.getNumberOfdays());
+                }
             break;
             case YEARS:
                 idealDisbursementDate = firstRepaymentDate.minusYears(repaidEvery);


[02/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 772ea77..ac732b5 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -550,7 +550,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
                     + " l.principal_amount_proposed as proposedPrincipal, l.principal_amount as principal, l.approved_principal as approvedPrincipal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery,"
                     + " l.grace_on_principal_periods as graceOnPrincipalPayment, l.recurring_moratorium_principal_periods as recurringMoratoriumOnPrincipalPeriods, l.grace_on_interest_periods as graceOnInterestPayment, l.grace_interest_free_periods as graceOnInterestCharged,l.grace_on_arrears_ageing as graceOnArrearsAgeing,"
                     + " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
-                    + " l.repayment_period_frequency_enum as repaymentFrequencyType, l.repayment_frequency_nth_day_enum as repaymentFrequencyNthDayType, l.repayment_frequency_day_of_week_enum as repaymentFrequencyDayOfWeekType, l.interest_period_frequency_enum as interestRateFrequencyType, "
+                    + " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
                     + " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, "
                     + " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
                     + " l.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion,"
@@ -600,9 +600,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
                     + " l.interest_recalculation_enabled as isInterestRecalculationEnabled, "
                     + " lir.id as lirId, lir.loan_id as loanId, lir.compound_type_enum as compoundType, lir.reschedule_strategy_enum as rescheduleStrategy, "
                     + " lir.rest_frequency_type_enum as restFrequencyEnum, lir.rest_frequency_interval as restFrequencyInterval, "
-                    + " lir.rest_freqency_date as restFrequencyDate, "
+                    + " lir.rest_frequency_nth_day_enum as restFrequencyNthDayEnum, "
+                    + " lir.rest_frequency_weekday_enum as restFrequencyWeekDayEnum, "
+                    + " lir.rest_frequency_on_day as restFrequencyOnDay, "
                     + " lir.compounding_frequency_type_enum as compoundingFrequencyEnum, lir.compounding_frequency_interval as compoundingInterval, "
-                    + " lir.compounding_freqency_date as compoundingFrequencyDate, "
+                    + " lir.compounding_frequency_nth_day_enum as compoundingFrequencyNthDayEnum, "
+                    + " lir.compounding_frequency_weekday_enum as compoundingFrequencyWeekDayEnum, "
+                    + " lir.compounding_frequency_on_day as compoundingFrequencyOnDay, "
+                    + " lir.is_compounding_to_be_posted_as_transaction as isCompoundingToBePostedAsTransaction, "
+                    + " lir.allow_compounding_on_eod as allowCompoundingOnEod, "
                     + " l.is_floating_interest_rate as isFloatingInterestRate, "
                     + " l.interest_rate_differential as interestRateDifferential, "
                     + " l.create_standing_instruction_at_disbursement as createStandingInstructionAtDisbursement, "
@@ -752,14 +758,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
             final int repaymentFrequencyTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyType");
             final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeInt);
 
-            final Integer repaymentFrequencyNthDayTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyNthDayType");
-            final EnumOptionData repaymentFrequencyNthDayType = LoanEnumerations
-                    .repaymentFrequencyNthDayType(repaymentFrequencyNthDayTypeInt);
-
-            final Integer repaymentFrequencyDayOfWeekTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyDayOfWeekType");
-            final EnumOptionData repaymentFrequencyDayOfWeekType = LoanEnumerations
-                    .repaymentFrequencyDayOfWeekType(repaymentFrequencyDayOfWeekTypeInt);
-
             final int interestRateFrequencyTypeInt = JdbcSupport.getInteger(rs, "interestRateFrequencyType");
             final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeInt);
 
@@ -877,7 +875,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
                 final int restFrequencyEnumValue = JdbcSupport.getInteger(rs, "restFrequencyEnum");
                 final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue);
                 final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval");
-                final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate");
+                final Integer restFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyNthDayEnum");
+                EnumOptionData restFrequencyNthDayEnum = null;
+                if (restFrequencyNthDayEnumValue != null) {
+                    restFrequencyNthDayEnum = LoanEnumerations.interestRecalculationCompoundingNthDayType(restFrequencyNthDayEnumValue);
+                }
+                final Integer restFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyWeekDayEnum");
+                EnumOptionData restFrequencyWeekDayEnum = null;
+                if (restFrequencyWeekDayEnumValue != null) {
+                    restFrequencyWeekDayEnum = LoanEnumerations
+                            .interestRecalculationCompoundingDayOfWeekType(restFrequencyWeekDayEnumValue);
+                }
+                final Integer restFrequencyOnDay = JdbcSupport.getInteger(rs, "restFrequencyOnDay");
                 final CalendarData compoundingCalendarData = null;
                 final Integer compoundingFrequencyEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyEnum");
                 EnumOptionData compoundingFrequencyType = null;
@@ -885,25 +894,41 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
                     compoundingFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(compoundingFrequencyEnumValue);
                 }
                 final Integer compoundingInterval = JdbcSupport.getInteger(rs, "compoundingInterval");
-                final LocalDate compoundingFrequencyDate = JdbcSupport.getLocalDate(rs, "compoundingFrequencyDate");
+                final Integer compoundingFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyNthDayEnum");
+                EnumOptionData compoundingFrequencyNthDayEnum = null;
+                if (compoundingFrequencyNthDayEnumValue != null) {
+                    compoundingFrequencyNthDayEnum = LoanEnumerations
+                            .interestRecalculationCompoundingNthDayType(compoundingFrequencyNthDayEnumValue);
+                }
+                final Integer compoundingFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyWeekDayEnum");
+                EnumOptionData compoundingFrequencyWeekDayEnum = null;
+                if (compoundingFrequencyWeekDayEnumValue != null) {
+                    compoundingFrequencyWeekDayEnum = LoanEnumerations
+                            .interestRecalculationCompoundingDayOfWeekType(compoundingFrequencyWeekDayEnumValue);
+                }
+                final Integer compoundingFrequencyOnDay = JdbcSupport.getInteger(rs, "compoundingFrequencyOnDay");
 
+                final Boolean isCompoundingToBePostedAsTransaction = rs.getBoolean("isCompoundingToBePostedAsTransaction");
+                final Boolean allowCompoundingOnEod = rs.getBoolean("allowCompoundingOnEod");
                 interestRecalculationData = new LoanInterestRecalculationData(lprId, productId, interestRecalculationCompoundingType,
-                        rescheduleStrategyType, calendarData, restFrequencyType, restFrequencyInterval, restFrequencyDate,
-                        compoundingCalendarData, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate);
+                        rescheduleStrategyType, calendarData, restFrequencyType, restFrequencyInterval, restFrequencyNthDayEnum,
+                        restFrequencyWeekDayEnum, restFrequencyOnDay, compoundingCalendarData, compoundingFrequencyType,
+                        compoundingInterval, compoundingFrequencyNthDayEnum, compoundingFrequencyWeekDayEnum, compoundingFrequencyOnDay,
+                        isCompoundingToBePostedAsTransaction, allowCompoundingOnEod);
             }
 
             return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
                     clientOfficeId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
                     isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
                     currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency,
-                    termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
-                    repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType,
-                    interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate,
-                    interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion,
-                    expectedFirstRepaymentOnDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged,
-                    interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting,
-                    loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance,
-                    inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
+                    termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, null, null, transactionStrategyId,
+                    transactionStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate,
+                    interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
+                    allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment,
+                    recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate,
+                    timeline, loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter,
+                    loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, inArrears,
+                    graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
                     interestRecalculationData, createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap,
                     maximumGap);
         }
@@ -1569,10 +1594,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
         sqlBuilder
                 .append("select ")
                 .append(mapper.schema())
-                .append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
+                .append(" where (recaldet.is_compounding_to_be_posted_as_transaction is null or recaldet.is_compounding_to_be_posted_as_transaction = 0) ")
+                .append(" and (((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
                 .append(" or ( ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
                 .append(" or ( ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
-                .append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=0 and ls.duedate <= CURDATE() ");
+                .append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=0 and ls.duedate <= CURDATE()) ");
         if(organisationStartDate != null){
             sqlBuilder.append(" and ls.duedate > :organisationstartdate ");
         }
@@ -1594,11 +1620,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
         sqlBuilder
                 .append("select ")
                 .append(mapper.schema())
-                .append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
+                .append(" where  (recaldet.is_compounding_to_be_posted_as_transaction is null or recaldet.is_compounding_to_be_posted_as_transaction = 0) ")
+                .append(" and (((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
                 .append(" or (ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
                 .append(" or (ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
                 .append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and (loan.closedon_date <= :tilldate or loan.closedon_date is null)")
-                .append(" and loan.is_npa=0 and (ls.duedate <= :tilldate or (ls.duedate > :tilldate and ls.fromdate < :tilldate)) ");
+                .append(" and loan.is_npa=0 and (ls.duedate <= :tilldate or (ls.duedate > :tilldate and ls.fromdate < :tilldate))) ");
         if(organisationStartDate != null){
             sqlBuilder.append(" and ls.duedate > :organisationstartdate ");
         }
@@ -1632,7 +1659,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
                     .append(" from m_loan_repayment_schedule ls ").append(" left join m_loan loan on loan.id=ls.loan_id ")
                     .append(" left join m_product_loan mpl on mpl.id = loan.product_id")
                     .append(" left join m_client mc on mc.id = loan.client_id ").append(" left join m_group mg on mg.id = loan.group_id")
-                    .append(" left join m_currency curr on curr.code = loan.currency_code");
+                    .append(" left join m_currency curr on curr.code = loan.currency_code")
+                    .append(" left join m_loan_recalculation_details as recaldet on loan.id = recaldet.loan_id ");
             return sqlBuilder.toString();
         }
 
@@ -1693,7 +1721,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
                     .append(" from m_loan_repayment_schedule ls ").append(" left join m_loan loan on loan.id=ls.loan_id ")
                     .append(" left join m_product_loan mpl on mpl.id = loan.product_id")
                     .append(" left join m_client mc on mc.id = loan.client_id ").append(" left join m_group mg on mg.id = loan.group_id")
-                    .append(" left join m_currency curr on curr.code = loan.currency_code");
+                    .append(" left join m_currency curr on curr.code = loan.currency_code")
+                    .append(" left join m_loan_recalculation_details as recaldet on loan.id = recaldet.loan_id ");
             return sqlBuilder.toString();
         }
 
@@ -2034,4 +2063,24 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
         }
     }
 
+    @Override
+    public Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions() {
+        StringBuilder sqlBuilder = new StringBuilder()
+            .append(" select distinct loan.id ")
+            .append(" from m_loan as loan ")
+            .append(" inner join m_loan_recalculation_details as recdet on (recdet.loan_id = loan.id and recdet.is_compounding_to_be_posted_as_transaction is not null and recdet.is_compounding_to_be_posted_as_transaction = 1) ")
+            .append(" inner join m_loan_repayment_schedule as repsch on repsch.loan_id = loan.id ")
+            .append(" inner join m_loan_interest_recalculation_additional_details as adddet on adddet.loan_repayment_schedule_id = repsch.id ")
+            .append(" left join m_loan_transaction as trans on (trans.is_reversed <> 1 and trans.transaction_type_enum = 19 and trans.loan_id = loan.id and trans.transaction_date = adddet.effective_date) ")
+            .append(" where loan.loan_status_id = 300 ")
+            .append(" and adddet.effective_date is not null ")
+            .append(" and trans.transaction_date is null ")
+            .append(" and adddet.effective_date < ? ");
+        try {
+            String currentdate = formatter.print(DateUtils.getLocalDateOfTenant());
+            return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, new Object[] { currentdate });
+        } catch (final EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index b6c7ba1..1699182 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -90,14 +90,14 @@ import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
 import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
+import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException.LOAN_CHARGE_CANNOT_BE_PAYED_REASON;
+import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON;
+import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
+import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException;
 import org.apache.fineract.portfolio.client.domain.Client;
 import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
 import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
@@ -126,6 +126,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
@@ -304,7 +305,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
 
         final Loan loan = this.loanAssembler.assembleFrom(loanId);
         checkClientOrGroupActive(loan);
-        
+
         final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling();
         final Date rescheduledRepaymentDate = command.DateValueOfParameterNamed("adjustRepaymentDate");
 
@@ -336,8 +337,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         final Map<String, Object> changes = new LinkedHashMap<>();
 
         final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
-        
-        final Boolean isPaymnetypeApplicableforDisbursementCharge=configurationDomainService.isPaymnetypeApplicableforDisbursementCharge();
+
+        final Boolean isPaymnetypeApplicableforDisbursementCharge = configurationDomainService
+                .isPaymnetypeApplicableforDisbursementCharge();
 
         updateLoanCounters(loan, actualDisbursementDate);
         Money amountBeforeAdjust = loan.getPrincpal();
@@ -366,10 +368,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
                 this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
                         loan, null);
             }
-            if(isPaymnetypeApplicableforDisbursementCharge){
-            	changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,paymentDetail);
-            }else{
-            	changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,null);
+            if (isPaymnetypeApplicableforDisbursementCharge) {
+                changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, paymentDetail);
+            } else {
+                changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, null);
             }
         }
         if (!changes.isEmpty()) {
@@ -549,7 +551,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         final SingleDisbursalCommand[] disbursalCommand = bulkDisbursalCommand.getDisburseTransactions();
         final Map<String, Object> changes = new LinkedHashMap<>();
         if (disbursalCommand == null) { return changes; }
-        
+
         final LocalDate nextPossibleRepaymentDate = null;
         final Date rescheduledRepaymentDate = null;
 
@@ -597,15 +599,16 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
                 }
                 LocalDate recalculateFrom = null;
                 final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
-                regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, rescheduledRepaymentDate);
+                regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate,
+                        rescheduledRepaymentDate);
                 if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
                     this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
                             loan.fetchRepaymentScheduleInstallments(), loan, null);
                 }
-                if(configurationDomainService.isPaymnetypeApplicableforDisbursementCharge()){
-                	changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,paymentDetail);
-                }else{
-                	changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,null);
+                if (configurationDomainService.isPaymnetypeApplicableforDisbursementCharge()) {
+                    changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, paymentDetail);
+                } else {
+                    changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, null);
                 }
             }
             if (!changes.isEmpty()) {
@@ -1990,8 +1993,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         // loop through each loan to reschedule the repayment dates
         for (final Loan loan : loans) {
             if (loan != null) {
-
-                if(loan.getExpectedFirstRepaymentOnDate() != null && loan.getExpectedFirstRepaymentOnDate().equals(presentMeetingDate)){
+                if (loan.getExpectedFirstRepaymentOnDate() != null && loan.getExpectedFirstRepaymentOnDate().equals(presentMeetingDate)) {
                     final String defaultUserMessage = "Meeting calendar date update is not supported since its a first repayment date";
                     throw new CalendarParameterUpdateNotSupportedException("meeting.for.first.repayment.date", defaultUserMessage,
                             loan.getExpectedFirstRepaymentOnDate(), presentMeetingDate);
@@ -2337,9 +2339,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
                 BigDecimal interest = BigDecimal.ZERO;
                 BigDecimal feeCharges = BigDecimal.ZERO;
                 BigDecimal penaltyCharges = BigDecimal.ONE;
+                final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
                 LoanRepaymentScheduleInstallment newEntry = new LoanRepaymentScheduleInstallment(loan, installments.size() + 1,
                         lastInstallment.getDueDate(), lastChargeDate, principal, interest, feeCharges, penaltyCharges,
-                        recalculatedInterestComponent);
+                        recalculatedInterestComponent, compoundingDetails);
                 installments.add(newEntry);
             }
         }
@@ -2548,8 +2551,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
 
         if (command.entityId() != null) {
 
-            changedTransactionDetail = loan.updateDisbursementDateAndAmountForTranche(loanDisbursementDetails, command,
-                    changes, scheduleGeneratorDTO, currentUser);
+            changedTransactionDetail = loan.updateDisbursementDateAndAmountForTranche(loanDisbursementDetails, command, changes,
+                    scheduleGeneratorDTO, currentUser);
         } else {
             // BigDecimal setAmount = loan.getApprovedPrincipal();
             Collection<LoanDisbursementDetails> loanDisburseDetails = loan.getDisbursementDetails();
@@ -2735,8 +2738,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         AppUser currentUser = getAppUserIfPresent();
         final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
         BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
-        loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount, currentUser, 
-        		nextPossibleRepaymentDate, rescheduledRepaymentDate);
+        loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount, currentUser,
+                nextPossibleRepaymentDate, rescheduledRepaymentDate);
     }
 
     private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
@@ -2747,7 +2750,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
                         scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
                         scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
                         scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
-                        scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent());
+                        scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent(),
+                        scheduledLoanInstallment.getLoanCompoundingDetails());
                 installments.add(installment);
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
index f476e46..f704925 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/LoanProductConstants.java
@@ -86,12 +86,17 @@ public interface LoanProductConstants {
     public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
     public static final String recalculationRestFrequencyTypeParameterName = "recalculationRestFrequencyType";
     public static final String recalculationRestFrequencyIntervalParameterName = "recalculationRestFrequencyInterval";
-    public static final String recalculationRestFrequencyDateParamName = "recalculationRestFrequencyDate";
+    public static final String recalculationRestFrequencyWeekdayParamName = "recalculationRestFrequencyDayOfWeekType";
+    public static final String recalculationRestFrequencyNthDayParamName = "recalculationRestFrequencyNthDayType";
+    public static final String recalculationRestFrequencyOnDayParamName = "recalculationRestFrequencyOnDayType";
     public static final String isArrearsBasedOnOriginalScheduleParamName = "isArrearsBasedOnOriginalSchedule";
     public static final String preClosureInterestCalculationStrategyParamName = "preClosureInterestCalculationStrategy";
     public static final String recalculationCompoundingFrequencyTypeParameterName = "recalculationCompoundingFrequencyType";
     public static final String recalculationCompoundingFrequencyIntervalParameterName = "recalculationCompoundingFrequencyInterval";
-    public static final String recalculationCompoundingFrequencyDateParamName = "recalculationCompoundingFrequencyDate";
+    public static final String recalculationCompoundingFrequencyWeekdayParamName = "recalculationCompoundingFrequencyDayOfWeekType";
+    public static final String recalculationCompoundingFrequencyNthDayParamName = "recalculationCompoundingFrequencyNthDayType";
+    public static final String recalculationCompoundingFrequencyOnDayParamName = "recalculationCompoundingFrequencyOnDayType";
+    public static final String isCompoundingToBePostedAsTransactionParamName = "isCompoundingToBePostedAsTransaction";
 
     // Guarantee related
     public static final String holdGuaranteeFundsParamName = "holdGuaranteeFunds";
@@ -115,6 +120,7 @@ public interface LoanProductConstants {
     public static final String inArrearsToleranceParamName = "inArrearsTolerance";
     public static final String repaymentEveryParamName = "repaymentEvery";
     public static final String graceOnPrincipalAndInterestPaymentParamName = "graceOnPrincipalAndInterestPayment";
+    public static final String allowCompoundingOnEodParamName = "allowCompoundingOnEod";
     
     //Variable Installments Settings
     public static final String allowVariableInstallmentsParamName = "allowVariableInstallments" ;

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
index a7d1816..a269d54 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java
@@ -298,6 +298,10 @@ public class LoanProductsApiResource {
         final List<EnumOptionData> rescheduleStrategyTypeOptions = dropdownReadPlatformService.retrieveRescheduleStrategyTypeOptions();
         final List<EnumOptionData> interestRecalculationFrequencyTypeOptions = dropdownReadPlatformService
                 .retrieveInterestRecalculationFrequencyTypeOptions();
+        final List<EnumOptionData> interestRecalculationNthDayTypeOptions = dropdownReadPlatformService
+                .retrieveInterestRecalculationNthDayTypeOptions();
+        final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions = dropdownReadPlatformService
+                .retrieveInterestRecalculationDayOfWeekTypeOptions();
         final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = dropdownReadPlatformService
                 .retrivePreCloseInterestCalculationStrategyOptions();
         final List<FloatingRateData> floatingRateOptions = this.floatingRateReadPlatformService.retrieveLookupActive();
@@ -307,7 +311,8 @@ public class LoanProductsApiResource {
                 interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
                 accountingRuleTypeOptions, loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
                 interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
-                preCloseInterestCalculationStrategyOptions, floatingRateOptions);
+                preCloseInterestCalculationStrategyOptions, floatingRateOptions, interestRecalculationNthDayTypeOptions, 
+                interestRecalculationDayOfWeekTypeOptions);
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
index 48f730a..2418945 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java
@@ -159,6 +159,10 @@ public class LoanProductData {
     @SuppressWarnings("unused")
     private final List<EnumOptionData> interestRecalculationCompoundingTypeOptions;
     @SuppressWarnings("unused")
+    private final List<EnumOptionData> interestRecalculationNthDayTypeOptions;
+    @SuppressWarnings("unused")
+    private final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions;
+    @SuppressWarnings("unused")
     private final List<EnumOptionData> rescheduleStrategyTypeOptions;
     @SuppressWarnings("unused")
     private final List<EnumOptionData> preClosureInterestCalculationStrategyOptions;
@@ -585,6 +589,8 @@ public class LoanProductData {
         this.interestRecalculationCompoundingTypeOptions = null;
         this.rescheduleStrategyTypeOptions = null;
         this.interestRecalculationFrequencyTypeOptions = null;
+        this.interestRecalculationNthDayTypeOptions = null;
+        this.interestRecalculationDayOfWeekTypeOptions = null;
 
         this.canDefineInstallmentAmount = canDefineInstallmentAmount;
         this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
@@ -602,7 +608,9 @@ public class LoanProductData {
             final List<EnumOptionData> valueConditionTypeOptions, final List<EnumOptionData> daysInMonthTypeOptions,
             final List<EnumOptionData> daysInYearTypeOptions, final List<EnumOptionData> interestRecalculationCompoundingTypeOptions,
             final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
-            final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions) {
+            final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions,
+            final List<EnumOptionData> interestRecalculationNthDayTypeOptions,
+            final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions) {
         this.id = productData.id;
         this.name = productData.name;
         this.shortName = productData.shortName;
@@ -686,6 +694,8 @@ public class LoanProductData {
         this.amortizationTypeOptions = amortizationTypeOptions;
         this.interestTypeOptions = interestTypeOptions;
         this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions;
+        this.interestRecalculationNthDayTypeOptions = interestRecalculationNthDayTypeOptions;
+        this.interestRecalculationDayOfWeekTypeOptions = interestRecalculationDayOfWeekTypeOptions;
         this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions;
         this.interestRateFrequencyTypeOptions = interestRateFrequencyTypeOptions;
 
@@ -946,8 +956,11 @@ public class LoanProductData {
         final CalendarData compoundingCalendarData = null;
         return new LoanInterestRecalculationData(id, loanId, getInterestRecalculationCompoundingType(), getRescheduleStrategyType(),
                 calendarData, getRecalculationRestFrequencyType(), getRecalculationRestFrequencyInterval(),
-                getRecalculationRestFrequencyDate(), compoundingCalendarData, getRecalculationCompoundingFrequencyType(),
-                getRecalculationCompoundingFrequencyInterval(), getRecalculationCompoundingFrequencyDate());
+                getInterestRecalculationRestNthDayType(), getInterestRecalculationRestWeekDayType(),
+                getInterestRecalculationRestOnDayType(), compoundingCalendarData, getRecalculationCompoundingFrequencyType(),
+                getRecalculationCompoundingFrequencyInterval(), getInterestRecalculationCompoundingNthDayType(),
+                getInterestRecalculationCompoundingWeekDayType(), getInterestRecalculationCompoundingOnDayType(),
+                isCompoundingToBePostedAsTransaction(), allowCompoundingOnEod());
     }
 
     private EnumOptionData getRescheduleStrategyType() {
@@ -960,8 +973,16 @@ public class LoanProductData {
         return null;
     }
 
-    private LocalDate getRecalculationRestFrequencyDate() {
-        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyDate(); }
+    private EnumOptionData getInterestRecalculationCompoundingNthDayType() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyNthDay(); }
+        return null;
+    }
+    private EnumOptionData getInterestRecalculationCompoundingWeekDayType() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyWeekday(); }
+        return null;
+    }
+    private Integer getInterestRecalculationCompoundingOnDayType() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyOnDay(); }
         return null;
     }
 
@@ -975,8 +996,18 @@ public class LoanProductData {
         return null;
     }
 
-    private LocalDate getRecalculationCompoundingFrequencyDate() {
-        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyDate(); }
+    private EnumOptionData getInterestRecalculationRestNthDayType() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyNthDay(); }
+        return null;
+    }
+
+    private EnumOptionData getInterestRecalculationRestWeekDayType() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyWeekday(); }
+        return null;
+    }
+
+    private Integer getInterestRecalculationRestOnDayType() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyOnDay(); }
         return null;
     }
 
@@ -989,6 +1020,14 @@ public class LoanProductData {
         if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyInterval(); }
         return null;
     }
+    public Boolean isCompoundingToBePostedAsTransaction() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.isCompoundingToBePostedAsTransaction(); }
+        return null;
+    }
+    public Boolean allowCompoundingOnEod() {
+        if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.allowCompoundingOnEod(); }
+        return null;
+    }
 
     public boolean canDefineInstallmentAmount() {
         return this.canDefineInstallmentAmount;

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java
index 42b3683..12dc470 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java
@@ -26,7 +26,6 @@ import org.apache.fineract.infrastructure.core.data.EnumOptionData;
 import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
-import org.joda.time.LocalDate;
 
 public class LoanProductInterestRecalculationData {
 
@@ -38,33 +37,48 @@ public class LoanProductInterestRecalculationData {
     private final EnumOptionData rescheduleStrategyType;
     private final EnumOptionData recalculationRestFrequencyType;
     private final Integer recalculationRestFrequencyInterval;
-    private final LocalDate recalculationRestFrequencyDate;
+    private final EnumOptionData recalculationRestFrequencyNthDay;
+    private final EnumOptionData recalculationRestFrequencyWeekday;
+    private final Integer recalculationRestFrequencyOnDay;
     private final EnumOptionData recalculationCompoundingFrequencyType;
     private final Integer recalculationCompoundingFrequencyInterval;
-    private final LocalDate recalculationCompoundingFrequencyDate;
+    private final EnumOptionData recalculationCompoundingFrequencyNthDay;
+    private final EnumOptionData recalculationCompoundingFrequencyWeekday;
+    private final Integer recalculationCompoundingFrequencyOnDay;
     @SuppressWarnings("unused")
     private final boolean isArrearsBasedOnOriginalSchedule;
+    private final boolean isCompoundingToBePostedAsTransaction;
     @SuppressWarnings("unused")
     private final EnumOptionData preClosureInterestCalculationStrategy;
+    private final boolean allowCompoundingOnEod;
 
     public LoanProductInterestRecalculationData(final Long id, final Long productId,
             final EnumOptionData interestRecalculationCompoundingType, final EnumOptionData rescheduleStrategyType,
             final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval,
-            final LocalDate recalculationRestFrequencyDate, final EnumOptionData recalculationCompoundingFrequencyType,
-            final Integer recalculationCompoundingFrequencyInterval, final LocalDate recalculationCompoundingFrequencyDate,
-            final boolean isArrearsBasedOnOriginalSchedule, final EnumOptionData preCloseInterestCalculationStrategy) {
+            final EnumOptionData recalculationRestFrequencyNthDay, final EnumOptionData recalculationRestFrequencyWeekday,
+            final Integer recalculationRestFrequencyOnDay, final EnumOptionData recalculationCompoundingFrequencyType,
+            final Integer recalculationCompoundingFrequencyInterval, final EnumOptionData recalculationCompoundingFrequencyNthDay,
+            final EnumOptionData recalculationCompoundingFrequencyWeekday, final Integer recalculationCompoundingFrequencyOnDay,
+            final boolean isArrearsBasedOnOriginalSchedule, boolean isCompoundingToBePostedAsTransaction,
+            final EnumOptionData preCloseInterestCalculationStrategy, final boolean allowCompoundingOnEod) {
         this.id = id;
         this.productId = productId;
         this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
         this.rescheduleStrategyType = rescheduleStrategyType;
         this.recalculationRestFrequencyType = recalculationRestFrequencyType;
         this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
-        this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
+        this.recalculationRestFrequencyNthDay = recalculationRestFrequencyNthDay;
+        this.recalculationRestFrequencyOnDay = recalculationRestFrequencyOnDay;
+        this.recalculationRestFrequencyWeekday = recalculationRestFrequencyWeekday;
         this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
         this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
-        this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
+        this.recalculationCompoundingFrequencyNthDay = recalculationCompoundingFrequencyNthDay;
+        this.recalculationCompoundingFrequencyOnDay = recalculationCompoundingFrequencyOnDay;
+        this.recalculationCompoundingFrequencyWeekday = recalculationCompoundingFrequencyWeekday;
         this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
         this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
+        this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
+        this.allowCompoundingOnEod = allowCompoundingOnEod;
     }
 
     public static LoanProductInterestRecalculationData sensibleDefaultsForNewLoanProductCreation() {
@@ -74,16 +88,24 @@ public class LoanProductInterestRecalculationData {
         final EnumOptionData rescheduleStrategyType = rescheduleStrategyType(LoanRescheduleStrategyMethod.REDUCE_EMI_AMOUNT);
         final EnumOptionData recalculationRestFrequencyType = null;
         final Integer recalculationRestFrequencyInterval = null;
-        final LocalDate recalculationRestFrequencyDate = null;
+        final EnumOptionData recalculationRestFrequencyNthDay = null;
+        final EnumOptionData recalculationRestFrequencyWeekday = null;
+        final Integer recalculationRestFrequencyOnDay = null;
         final EnumOptionData recalculationCompoundingFrequencyType = null;
         final Integer recalculationCompoundingFrequencyInterval = null;
-        final LocalDate recalculationCompoundingFrequencyDate = null;
+        final EnumOptionData recalculationCompoundingFrequencyNthDay = null;
+        final EnumOptionData recalculationCompoundingFrequencyWeekday = null;
+        final Integer recalculationCompoundingFrequencyOnDay = null;
         final boolean isArrearsBasedOnOriginalSchedule = false;
+        final boolean isCompoundingToBePostedAsTransaction = false;
         final EnumOptionData preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE);
+        final boolean allowCompoundingOnEod = false;
         return new LoanProductInterestRecalculationData(id, productId, interestRecalculationCompoundingType, rescheduleStrategyType,
-                recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyDate,
-                recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate,
-                isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
+                recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyNthDay,
+                recalculationRestFrequencyWeekday, recalculationRestFrequencyOnDay, recalculationCompoundingFrequencyType,
+                recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyNthDay,
+                recalculationCompoundingFrequencyWeekday, recalculationCompoundingFrequencyOnDay, isArrearsBasedOnOriginalSchedule,
+                isCompoundingToBePostedAsTransaction, preCloseInterestCalculationStrategy, allowCompoundingOnEod);
     }
 
     public EnumOptionData getInterestRecalculationCompoundingType() {
@@ -92,10 +114,7 @@ public class LoanProductInterestRecalculationData {
 
     public EnumOptionData getRescheduleStrategyType() {
         return this.rescheduleStrategyType;
-    }
 
-    public LocalDate getRecalculationRestFrequencyDate() {
-        return this.recalculationRestFrequencyDate;
     }
 
     public EnumOptionData getRecalculationRestFrequencyType() {
@@ -114,8 +133,29 @@ public class LoanProductInterestRecalculationData {
         return this.recalculationCompoundingFrequencyInterval;
     }
 
-    public LocalDate getRecalculationCompoundingFrequencyDate() {
-        return this.recalculationCompoundingFrequencyDate;
+    public EnumOptionData getRecalculationRestFrequencyNthDay() {
+        return this.recalculationRestFrequencyNthDay;
+    }
+    public EnumOptionData getRecalculationRestFrequencyWeekday() {
+        return this.recalculationRestFrequencyWeekday;
+    }
+    public Integer getRecalculationRestFrequencyOnDay() {
+        return this.recalculationRestFrequencyOnDay;
+    }
+    public EnumOptionData getRecalculationCompoundingFrequencyNthDay() {
+        return this.recalculationCompoundingFrequencyNthDay;
     }
 
+    public EnumOptionData getRecalculationCompoundingFrequencyWeekday() {
+        return this.recalculationCompoundingFrequencyWeekday;
+    }
+    public Integer getRecalculationCompoundingFrequencyOnDay() {
+        return this.recalculationCompoundingFrequencyOnDay;
+    }
+    public boolean isCompoundingToBePostedAsTransaction() {
+        return this.isCompoundingToBePostedAsTransaction;
+    }
+    public boolean allowCompoundingOnEod() {
+        return this.allowCompoundingOnEod;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java
index 4456054..1b5a34f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java
@@ -18,7 +18,6 @@
  */
 package org.apache.fineract.portfolio.loanproduct.domain;
 
-import java.util.Date;
 import java.util.Map;
 
 import javax.persistence.Column;
@@ -26,12 +25,9 @@ import javax.persistence.Entity;
 import javax.persistence.JoinColumn;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
 
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
-import org.joda.time.LocalDate;
 import org.springframework.data.jpa.domain.AbstractPersistable;
 
 /**
@@ -66,9 +62,14 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
     @Column(name = "rest_frequency_interval", nullable = false)
     private Integer restInterval;
 
-    @Temporal(TemporalType.DATE)
-    @Column(name = "rest_freqency_date")
-    private Date restFrequencyDate;
+    @Column(name = "rest_frequency_nth_day_enum", nullable = true)
+    private Integer restFrequencyNthDay;
+
+    @Column(name = "rest_frequency_weekday_enum", nullable = true)
+    private Integer restFrequencyWeekday;
+
+    @Column(name = "rest_frequency_on_day", nullable = true)
+    private Integer restFrequencyOnDay;
 
     @Column(name = "compounding_frequency_type_enum", nullable = true)
     private Integer compoundingFrequencyType;
@@ -76,9 +77,14 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
     @Column(name = "compounding_frequency_interval", nullable = true)
     private Integer compoundingInterval;
 
-    @Temporal(TemporalType.DATE)
-    @Column(name = "compounding_freqency_date")
-    private Date compoundingFrequencyDate;
+    @Column(name = "compounding_frequency_nth_day_enum", nullable = true)
+    private Integer compoundingFrequencyNthDay;
+
+    @Column(name = "compounding_frequency_weekday_enum", nullable = true)
+    private Integer compoundingFrequencyWeekday;
+
+    @Column(name = "compounding_frequency_on_day", nullable = true)
+    private Integer compoundingFrequencyOnDay;
 
     @Column(name = "arrears_based_on_original_schedule")
     private boolean isArrearsBasedOnOriginalSchedule;
@@ -86,6 +92,12 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
     @Column(name = "pre_close_interest_calculation_strategy")
     private Integer preClosureInterestCalculationStrategy;
 
+    @Column(name = "is_compounding_to_be_posted_as_transaction")
+    private Boolean isCompoundingToBePostedAsTransaction;
+
+    @Column(name = "allow_compounding_on_eod")
+    private Boolean allowCompoundingOnEod;
+
     protected LoanProductInterestRecalculationDetails() {
         //
     }
@@ -100,19 +112,16 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
 
         final Integer recurrenceFrequency = command
                 .integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName);
-        final LocalDate recurrenceOnLocalDate = command
-                .localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
+        final Integer recurrenceOnNthDay = command
+                .integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName);
+        final Integer recurrenceOnDay = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName);
+        final Integer recurrenceOnWeekday = command
+                .integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName);
         Integer recurrenceInterval = command
                 .integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName);
         final boolean isArrearsBasedOnOriginalSchedule = command
                 .booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName);
         RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(recurrenceFrequency);
-        Date recurrenceOnDate = null;
-        if (recurrenceOnLocalDate != null) {
-            if (!frequencyType.isSameAsRepayment()) {
-                recurrenceOnDate = recurrenceOnLocalDate.toDate();
-            }
-        }
         if (frequencyType.isSameAsRepayment()) {
             recurrenceInterval = 0;
         }
@@ -121,7 +130,10 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
                 .fromInt(interestRecalculationCompoundingMethod);
         Integer compoundingRecurrenceFrequency = null;
         Integer compoundingInterval = null;
-        Date recurrenceOnCompoundingDate = null;
+        Integer compoundingRecurrenceOnNthDay = null;
+        Integer compoundingRecurrenceOnDay = null;
+        Integer compoundingRecurrenceOnWeekday = null;
+        boolean allowCompoundingOnEod = false;
         if (compoundingMethod.isCompoundingEnabled()) {
             compoundingRecurrenceFrequency = command
                     .integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName);
@@ -131,14 +143,14 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
             if (compoundingFrequencyType.isSameAsRepayment()) {
                 recurrenceInterval = 0;
             }
-            final LocalDate compoundingRecurrenceOnLocalDate = command
-                    .localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
-
-            if (compoundingRecurrenceOnLocalDate != null) {
-                if (!compoundingFrequencyType.isSameAsRepayment()) {
-                    recurrenceOnCompoundingDate = compoundingRecurrenceOnLocalDate.toDate();
-                }
-            }
+            compoundingRecurrenceOnNthDay = command
+                    .integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName);
+            compoundingRecurrenceOnDay = command
+                    .integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName);
+            compoundingRecurrenceOnWeekday = command
+                    .integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName);
+            if (!compoundingFrequencyType.isDaily())
+                allowCompoundingOnEod = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName);
         }
 
         Integer preCloseInterestCalculationStrategy = command
@@ -147,25 +159,39 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
             preCloseInterestCalculationStrategy = LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue();
         }
 
+        final boolean isCompoundingToBePostedAsTransaction = command
+                .booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName);
+
         return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod,
-                recurrenceFrequency, recurrenceInterval, recurrenceOnDate, compoundingRecurrenceFrequency, compoundingInterval,
-                recurrenceOnCompoundingDate, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
+                recurrenceFrequency, recurrenceInterval, recurrenceOnNthDay, recurrenceOnDay, recurrenceOnWeekday,
+                compoundingRecurrenceFrequency, compoundingInterval, compoundingRecurrenceOnNthDay, compoundingRecurrenceOnDay,
+                compoundingRecurrenceOnWeekday, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy,
+                isCompoundingToBePostedAsTransaction, allowCompoundingOnEod);
     }
 
     private LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod,
             final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
-            final Date restFrequencyDate, Integer compoundingFrequencyType, Integer compoundingInterval, Date compoundingFrequencyDate,
-            final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy) {
+            final Integer restFrequencyNthDay, final Integer restFrequencyOnDay, final Integer restFrequencyWeekday,
+            Integer compoundingFrequencyType, Integer compoundingInterval, final Integer compoundingFrequencyNthDay,
+            final Integer compoundingFrequencyOnDay, final Integer compoundingFrequencyWeekday,
+            final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy,
+            final boolean isCompoundingToBePostedAsTransaction, final boolean allowCompoundingOnEod) {
         this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
         this.rescheduleStrategyMethod = rescheduleStrategyMethod;
         this.restFrequencyType = restFrequencyType;
         this.restInterval = restInterval;
-        this.restFrequencyDate = restFrequencyDate;
-        this.compoundingFrequencyDate = compoundingFrequencyDate;
+        this.restFrequencyNthDay = restFrequencyNthDay;
+        this.restFrequencyOnDay = restFrequencyOnDay;
+        this.restFrequencyWeekday = restFrequencyWeekday;
         this.compoundingFrequencyType = compoundingFrequencyType;
         this.compoundingInterval = compoundingInterval;
+        this.compoundingFrequencyNthDay = compoundingFrequencyNthDay;
+        this.compoundingFrequencyOnDay = compoundingFrequencyOnDay;
+        this.compoundingFrequencyWeekday = compoundingFrequencyWeekday;
         this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
         this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
+        this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
+        this.allowCompoundingOnEod = allowCompoundingOnEod;
     }
 
     public void updateProduct(final LoanProduct loanProduct) {
@@ -209,7 +235,9 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
         RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(this.restFrequencyType);
         if (frequencyType.isSameAsRepayment()) {
             this.restInterval = 0;
-            this.restFrequencyDate = null;
+            this.restFrequencyNthDay = null;
+            this.restFrequencyWeekday = null;
+            this.restFrequencyOnDay = null;
         } else {
             if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
                     this.restInterval)) {
@@ -220,16 +248,46 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
                 this.restInterval = newValue;
             }
 
-            if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName,
-                    getRestFrequencyLocalDate())) {
-                final LocalDate newValue = command
-                        .localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
-                Date recurrenceOnDate = null;
-                if (newValue != null) {
-                    recurrenceOnDate = newValue.toDate();
-                }
-                actualChanges.put(LoanProductConstants.recalculationRestFrequencyDateParamName, newValue);
-                this.restFrequencyDate = recurrenceOnDate;
+            if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName,
+                    getRestFrequencyNthDay())) {
+                Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName);
+                actualChanges.put(LoanProductConstants.recalculationRestFrequencyNthDayParamName, newValue);
+                actualChanges.put("locale", localeAsInput);
+                this.restFrequencyNthDay = newValue;
+                this.restFrequencyOnDay = null;
+            }
+            if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName,
+                    getRestFrequencyWeekday())) {
+                Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName);
+                actualChanges.put(LoanProductConstants.recalculationRestFrequencyWeekdayParamName, newValue);
+                actualChanges.put("locale", localeAsInput);
+                this.restFrequencyWeekday = newValue;
+                this.restFrequencyOnDay = null;
+            }
+            if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName,
+                    getRestFrequencyOnDay())) {
+                Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName);
+                actualChanges.put(LoanProductConstants.recalculationRestFrequencyOnDayParamName, newValue);
+                actualChanges.put("locale", localeAsInput);
+                this.restFrequencyOnDay = newValue;
+                this.restFrequencyNthDay = null;
+                this.restFrequencyWeekday = null;
+            }
+
+            if (frequencyType.isWeekly()) {
+            	this.restFrequencyNthDay = null;
+            	this.restFrequencyOnDay = null;
+            } else if (frequencyType.isMonthly()) {
+            	if(command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName) != null) {
+            		this.restFrequencyNthDay = null;
+            		this.restFrequencyWeekday = null;
+            	} else {
+            		this.restFrequencyOnDay = null;
+            	}
+            } else if (frequencyType.isDaily()) {
+            	this.restFrequencyNthDay = null;
+        		this.restFrequencyWeekday = null;
+        		this.restFrequencyOnDay = null;
             }
         }
 
@@ -247,7 +305,9 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
             RecalculationFrequencyType compoundingfrequencyType = RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
             if (compoundingfrequencyType.isSameAsRepayment()) {
                 this.compoundingInterval = null;
-                this.compoundingFrequencyDate = null;
+                this.compoundingFrequencyNthDay = null;
+                this.compoundingFrequencyWeekday = null;
+                this.compoundingFrequencyOnDay = null;
             } else {
                 if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
                         this.compoundingInterval)) {
@@ -257,22 +317,66 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
                     this.compoundingInterval = newValue;
                 }
 
-                if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
-                        getCompoundingFrequencyLocalDate())) {
-                    final LocalDate newValue = command
-                            .localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
-                    Date recurrenceOnDate = null;
-                    if (newValue != null) {
-                        recurrenceOnDate = newValue.toDate();
-                    }
-                    actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyDateParamName, newValue);
-                    this.compoundingFrequencyDate = recurrenceOnDate;
+                if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
+                        getCompoundingFrequencyNthDay())) {
+                    Integer newValue = command
+                            .integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName);
+                    actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName, newValue);
+                    actualChanges.put("locale", localeAsInput);
+                    this.compoundingFrequencyNthDay = newValue;
+                    this.compoundingFrequencyOnDay = null;
+                }
+                if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
+                        getCompoundingFrequencyWeekday())) {
+                    Integer newValue = command
+                            .integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName);
+                    actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName, newValue);
+                    actualChanges.put("locale", localeAsInput);
+                    this.compoundingFrequencyWeekday = newValue;
+                    this.compoundingFrequencyOnDay = null;
+                }
+                if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
+                        getCompoundingFrequencyOnDay())) {
+                    Integer newValue = command
+                            .integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName);
+                    actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName, newValue);
+                    actualChanges.put("locale", localeAsInput);
+                    this.compoundingFrequencyOnDay = newValue;
+                    this.compoundingFrequencyNthDay = null;
+                    this.compoundingFrequencyWeekday = null;
+                }
+                
+                if (compoundingfrequencyType.isWeekly()) {
+                	this.compoundingFrequencyNthDay = null;
+                	this.compoundingFrequencyOnDay = null;
+                } else if (compoundingfrequencyType.isMonthly()) {
+                	if(command.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName) != null) {
+                		this.compoundingFrequencyNthDay = null;
+                		this.compoundingFrequencyWeekday = null;
+                	} else {
+                		this.compoundingFrequencyOnDay = null;
+                	}
+                } else if (compoundingfrequencyType.isDaily()) {
+                	this.compoundingFrequencyNthDay = null;
+            		this.compoundingFrequencyWeekday = null;
+            		this.compoundingFrequencyOnDay = null;
                 }
             }
+            if (!compoundingfrequencyType.isDaily()) {
+                if (command.isChangeInBooleanParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName, allowCompoundingOnEod())) {
+                    boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName);
+                    actualChanges.put(LoanProductConstants.allowCompoundingOnEodParamName, newValue);
+                    this.allowCompoundingOnEod = newValue;
+                }
+            } else {
+                this.allowCompoundingOnEod = false;
+            }
         } else {
             this.compoundingFrequencyType = null;
             this.compoundingInterval = null;
-            this.compoundingFrequencyDate = null;
+            this.compoundingFrequencyNthDay = null;
+    		this.compoundingFrequencyWeekday = null;
+    		this.compoundingFrequencyOnDay = null;
         }
 
         if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
@@ -292,15 +396,15 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
             actualChanges.put(LoanProductConstants.preClosureInterestCalculationStrategyParamName, newValue);
             this.preClosureInterestCalculationStrategy = newValue;
         }
-
-    }
-
-    public LocalDate getRestFrequencyLocalDate() {
-        LocalDate recurrenceOnLocalDate = null;
-        if (this.restFrequencyDate != null) {
-            recurrenceOnLocalDate = new LocalDate(this.restFrequencyDate);
+        
+        if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName,
+                this.isCompoundingToBePostedAsTransaction)) {
+            final boolean newValue = command
+                    .booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName);
+            actualChanges.put(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, newValue);
+            this.isCompoundingToBePostedAsTransaction = newValue;
         }
-        return recurrenceOnLocalDate;
+
     }
 
     public RecalculationFrequencyType getRestFrequencyType() {
@@ -311,14 +415,6 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
         return this.restInterval;
     }
 
-    public LocalDate getCompoundingFrequencyLocalDate() {
-        LocalDate recurrenceOnLocalDate = null;
-        if (this.compoundingFrequencyDate != null) {
-            recurrenceOnLocalDate = new LocalDate(this.compoundingFrequencyDate);
-        }
-        return recurrenceOnLocalDate;
-    }
-
     public RecalculationFrequencyType getCompoundingFrequencyType() {
         return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
     }
@@ -334,4 +430,36 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
     public LoanPreClosureInterestCalculationStrategy preCloseInterestCalculationStrategy() {
         return LoanPreClosureInterestCalculationStrategy.fromInt(this.preClosureInterestCalculationStrategy);
     }
+
+    public Integer getRestFrequencyNthDay() {
+        return this.restFrequencyNthDay;
+    }
+
+    public Integer getRestFrequencyWeekday() {
+        return this.restFrequencyWeekday;
+    }
+
+    public Integer getRestFrequencyOnDay() {
+        return this.restFrequencyOnDay;
+    }
+
+    public Integer getCompoundingFrequencyNthDay() {
+        return this.compoundingFrequencyNthDay;
+    }
+
+    public Integer getCompoundingFrequencyWeekday() {
+        return this.compoundingFrequencyWeekday;
+    }
+
+    public Integer getCompoundingFrequencyOnDay() {
+        return this.compoundingFrequencyOnDay;
+    }
+
+    public Boolean getIsCompoundingToBePostedAsTransaction() {
+        return this.isCompoundingToBePostedAsTransaction;
+    }
+
+    public Boolean allowCompoundingOnEod() {
+        return this.allowCompoundingOnEod;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
index 1d7aaf6..b7dbc8a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
@@ -346,8 +346,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
             actualChanges.put(repaymentFrequencyTypeParamName, newValue);
             actualChanges.put("locale", localeAsInput);
             this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue);
-
+        }
             if (this.repaymentPeriodFrequencyType == PeriodFrequencyType.MONTHS) {
+        	Integer newValue = null;
                 final String repaymentFrequencyNthDayTypeParamName = "repaymentFrequencyNthDayType";
                 newValue = command.integerValueOfParameterNamed(repaymentFrequencyNthDayTypeParamName);
                 actualChanges.put(repaymentFrequencyNthDayTypeParamName, newValue);
@@ -357,7 +358,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
                 actualChanges.put(repaymentFrequencyDayOfWeekTypeParamName, newValue);
 
                 actualChanges.put("locale", localeAsInput);
-            }
         }
 
         final String numberOfRepaymentsParamName = "numberOfRepayments";


[04/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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
old mode 100755
new mode 100644
index 7be11d3..c1f91ea
--- 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
@@ -30,12 +30,14 @@ import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
 import org.apache.fineract.portfolio.calendar.domain.Calendar;
 import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
+import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
 import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
 import org.apache.fineract.portfolio.common.domain.DaysInYearType;
 import org.apache.fineract.portfolio.common.domain.NthDayType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
+import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalculationDetails;
@@ -57,1864 +59,1521 @@ import org.joda.time.Years;
 
 public final class LoanApplicationTerms {
 
-	private final ApplicationCurrency currency;
+    private final ApplicationCurrency currency;
 
-	private final Calendar loanCalendar;
-	private Integer loanTermFrequency;
-	private final PeriodFrequencyType loanTermPeriodFrequencyType;
-	private Integer numberOfRepayments;
-	private Integer actualNumberOfRepayments;
-	private final Integer repaymentEvery;
-	private final PeriodFrequencyType repaymentPeriodFrequencyType;
-	private final Integer nthDay;
+    private final Calendar loanCalendar;
+    private Integer loanTermFrequency;
+    private final PeriodFrequencyType loanTermPeriodFrequencyType;
+    private Integer numberOfRepayments;
+    private Integer actualNumberOfRepayments;
+    private final Integer repaymentEvery;
+    private final PeriodFrequencyType repaymentPeriodFrequencyType;
+    private final Integer nthDay;
 
-	private final DayOfWeekType weekDayType;
-	private final AmortizationMethod amortizationMethod;
+    private final DayOfWeekType weekDayType;
+    private final AmortizationMethod amortizationMethod;
 
-	private final InterestMethod interestMethod;
-	private BigDecimal interestRatePerPeriod;
-	private final PeriodFrequencyType interestRatePeriodFrequencyType;
-	private BigDecimal annualNominalInterestRate;
-	private final InterestCalculationPeriodMethod interestCalculationPeriodMethod;
-	private final boolean allowPartialPeriodInterestCalcualtion;
+    private final InterestMethod interestMethod;
+    private BigDecimal interestRatePerPeriod;
+    private final PeriodFrequencyType interestRatePeriodFrequencyType;
+    private BigDecimal annualNominalInterestRate;
+    private final InterestCalculationPeriodMethod interestCalculationPeriodMethod;
+    private final boolean allowPartialPeriodInterestCalcualtion;
 
-	private Money principal;
-	private final LocalDate expectedDisbursementDate;
-	private final LocalDate repaymentsStartingFromDate;
-	private final LocalDate calculatedRepaymentsStartingFromDate;
-	/**
-	 * Integer representing the number of 'repayment frequencies' or
-	 * installments where 'grace' should apply to the principal component of a
-	 * loans repayment period (installment).
-	 */
-	private Integer principalGrace;
-	private Integer recurringMoratoriumOnPrincipalPeriods;
+    private Money principal;
+    private final LocalDate expectedDisbursementDate;
+    private final LocalDate repaymentsStartingFromDate;
+    private final LocalDate calculatedRepaymentsStartingFromDate;
+    /**
+     * Integer representing the number of 'repayment frequencies' or
+     * installments where 'grace' should apply to the principal component of a
+     * loans repayment period (installment).
+     */
+    private Integer principalGrace;
+    private Integer recurringMoratoriumOnPrincipalPeriods;
 
-	/**
-	 * Integer representing the number of 'repayment frequencies' or
-	 * installments where 'grace' should apply to the payment of interest in a
-	 * loans repayment period (installment).
-	 * 
-	 * <b>Note:</b> Interest is still calculated taking into account the full
-	 * loan term, the interest is simply offset to a later period.
-	 */
-	private Integer interestPaymentGrace;
+    /**
+     * Integer representing the number of 'repayment frequencies' or
+     * installments where 'grace' should apply to the payment of interest in a
+     * loans repayment period (installment).
+     * 
+     * <b>Note:</b> Interest is still calculated taking into account the full
+     * loan term, the interest is simply offset to a later period.
+     */
+    private Integer interestPaymentGrace;
 
-	/**
-	 * Integer representing the number of 'repayment frequencies' or
-	 * installments where 'grace' should apply to the charging of interest in a
-	 * loans repayment period (installment).
-	 * 
-	 * <b>Note:</b> The loan is <i>interest-free</i> for the period of time
-	 * indicated.
-	 */
-	private final Integer interestChargingGrace;
+    /**
+     * Integer representing the number of 'repayment frequencies' or
+     * installments where 'grace' should apply to the charging of interest in a
+     * loans repayment period (installment).
+     * 
+     * <b>Note:</b> The loan is <i>interest-free</i> for the period of time
+     * indicated.
+     */
+    private final Integer interestChargingGrace;
 
-	/**
-	 * Legacy method of support 'grace' on the charging of interest on a loan.
-	 * 
-	 * <p>
-	 * For the typical structured loan, its reasonable to use an integer to
-	 * indicate the number of 'repayment frequency' periods the 'grace' should
-	 * apply to but for slightly <b>irregular</b> loans where the period between
-	 * disbursement and the date of the 'first repayment period' isnt doest
-	 * match the 'repayment frequency' but can be less (15days instead of 1
-	 * month) or more (6 weeks instead of 1 month) - The idea was to use a date
-	 * to indicate from whence interest should be charged.
-	 * </p>
-	 */
-	private LocalDate interestChargedFromDate;
-	private final Money inArrearsTolerance;
-
-	private final Integer graceOnArrearsAgeing;
-
-	// added
-	private LocalDate loanEndDate;
-
-	private final List<DisbursementData> disbursementDatas;
-
-	private final boolean multiDisburseLoan;
-
-	private BigDecimal fixedEmiAmount;
-
-	private BigDecimal fixedPrincipalAmount;
-
-	private BigDecimal currentPeriodFixedEmiAmount;
-
-	private BigDecimal currentPeriodFixedPrincipalAmount;
-
-	private final BigDecimal actualFixedEmiAmount;
-
-	private final BigDecimal maxOutstandingBalance;
-
-	private Money totalInterestDue;
-
-	private final DaysInMonthType daysInMonthType;
-
-	private final DaysInYearType daysInYearType;
-
-	private final boolean interestRecalculationEnabled;
-
-	private final LoanRescheduleStrategyMethod rescheduleStrategyMethod;
-
-	private final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod;
-
-	private final CalendarInstance restCalendarInstance;
-
-	private final RecalculationFrequencyType recalculationFrequencyType;
-
-	private final CalendarInstance compoundingCalendarInstance;
-
-	private final RecalculationFrequencyType compoundingFrequencyType;
-
-	private final BigDecimal principalThresholdForLastInstalment;
-	private final Integer installmentAmountInMultiplesOf;
-
-	private final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy;
-
-	private Money approvedPrincipal = null;
-
-	private final LoanTermVariationsDataWrapper variationsDataWrapper;
-
-	private Money adjustPrincipalForFlatLoans;
-
-	private final LocalDate seedDate;
-
-	private final CalendarHistoryDataWrapper calendarHistoryDataWrapper;
-
-	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,
-			final AmortizationMethod amortizationMethod,
-			final InterestMethod interestMethod,
-			final BigDecimal interestRatePerPeriod,
-			final PeriodFrequencyType interestRatePeriodFrequencyType,
-			final BigDecimal annualNominalInterestRate,
-			final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
-			final boolean allowPartialPeriodInterestCalcualtion,
-			final Money principalMoney,
-			final LocalDate expectedDisbursementDate,
-			final LocalDate repaymentsStartingFromDate,
-			final LocalDate calculatedRepaymentsStartingFromDate,
-			final Integer graceOnPrincipalPayment,
-			final Integer recurringMoratoriumOnPrincipalPeriods,
-			final Integer graceOnInterestPayment,
-			final Integer graceOnInterestCharged,
-			final LocalDate interestChargedFromDate,
-			final Money inArrearsTolerance,
-			final boolean multiDisburseLoan,
-			final BigDecimal emiAmount,
-			final List<DisbursementData> disbursementDatas,
-			final BigDecimal maxOutstandingBalance,
-			final Integer graceOnArrearsAgeing,
-			final DaysInMonthType daysInMonthType,
-			final DaysInYearType daysInYearType,
-			final boolean isInterestRecalculationEnabled,
-			final RecalculationFrequencyType recalculationFrequencyType,
-			final CalendarInstance restCalendarInstance,
-			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,
-			final Integer numberOfdays, boolean isSkipRepaymentOnFirstDayofMonth) {
-
-		final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
-		final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
-		final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
-		return new LoanApplicationTerms(currency, loanTermFrequency,
-				loanTermPeriodFrequencyType, numberOfRepayments,
-				repaymentEvery, repaymentPeriodFrequencyType, nthDay,
-				weekDayType, amortizationMethod, interestMethod,
-				interestRatePerPeriod, interestRatePeriodFrequencyType,
-				annualNominalInterestRate, interestCalculationPeriodMethod,
-				allowPartialPeriodInterestCalcualtion, principalMoney,
-				expectedDisbursementDate, repaymentsStartingFromDate,
-				calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment,
-				recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment,
-				graceOnInterestCharged, interestChargedFromDate,
-				inArrearsTolerance, multiDisburseLoan, emiAmount,
-				disbursementDatas, maxOutstandingBalance, graceOnArrearsAgeing,
-				daysInMonthType, daysInYearType,
-				isInterestRecalculationEnabled, rescheduleStrategyMethod,
-				interestRecalculationCompoundingMethod, restCalendarInstance,
-				recalculationFrequencyType, compoundingCalendarInstance,
-				compoundingFrequencyType, principalThresholdForLastInstalment,
-				installmentAmountInMultiplesOf,
-				preClosureInterestCalculationStrategy, loanCalendar,
-				approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
-				isInterestChargedFromDateSameAsDisbursalDateEnabled,
-				numberOfdays, isSkipRepaymentOnFirstDayofMonth);
-
-	}
-
-	public static LoanApplicationTerms assembleFrom(
-			final ApplicationCurrency applicationCurrency,
-			final Integer loanTermFrequency,
-			final PeriodFrequencyType loanTermPeriodFrequencyType,
-			NthDayType nthDay,
-			DayOfWeekType dayOfWeek,
-			final LocalDate expectedDisbursementDate,
-			final LocalDate repaymentsStartingFromDate,
-			final LocalDate calculatedRepaymentsStartingFromDate,
-			final Money inArrearsTolerance,
-			final LoanProductRelatedDetail loanProductRelatedDetail,
-			final boolean multiDisburseLoan,
-			final BigDecimal emiAmount,
-			final List<DisbursementData> disbursementDatas,
-			final BigDecimal maxOutstandingBalance,
-			final LocalDate interestChargedFromDate,
-			final BigDecimal principalThresholdForLastInstalment,
-			final Integer installmentAmountInMultiplesOf,
-			final RecalculationFrequencyType recalculationFrequencyType,
-			final CalendarInstance restCalendarInstance,
-			final InterestRecalculationCompoundingMethod compoundingMethod,
-			final CalendarInstance compoundingCalendarInstance,
-			final RecalculationFrequencyType compoundingFrequencyType,
-			final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
-			final LoanRescheduleStrategyMethod rescheduleStrategyMethod,
-			BigDecimal approvedAmount, BigDecimal annualNominalInterestRate,
-			List<LoanTermVariationsData> loanTermVariations,
-			final Integer numberOfdays,
-			final boolean isSkipRepaymentOnFirstDayofMonth) {
-		final Calendar loanCalendar = null;
-		final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
-
-		return assembleFrom(applicationCurrency, loanTermFrequency,
-				loanTermPeriodFrequencyType, nthDay, dayOfWeek,
-				expectedDisbursementDate, repaymentsStartingFromDate,
-				calculatedRepaymentsStartingFromDate, inArrearsTolerance,
-				loanProductRelatedDetail, multiDisburseLoan, emiAmount,
-				disbursementDatas, maxOutstandingBalance,
-				interestChargedFromDate, principalThresholdForLastInstalment,
-				installmentAmountInMultiplesOf, recalculationFrequencyType,
-				restCalendarInstance, compoundingMethod,
-				compoundingCalendarInstance, compoundingFrequencyType,
-				loanPreClosureInterestCalculationStrategy,
-				rescheduleStrategyMethod, loanCalendar, approvedAmount,
-				annualNominalInterestRate, loanTermVariations,
-				calendarHistoryDataWrapper, numberOfdays,
-				isSkipRepaymentOnFirstDayofMonth);
-	}
-
-	public static LoanApplicationTerms assembleFrom(
-			final ApplicationCurrency applicationCurrency,
-			final Integer loanTermFrequency,
-			final PeriodFrequencyType loanTermPeriodFrequencyType,
-			NthDayType nthDay,
-			DayOfWeekType dayOfWeek,
-			final LocalDate expectedDisbursementDate,
-			final LocalDate repaymentsStartingFromDate,
-			final LocalDate calculatedRepaymentsStartingFromDate,
-			final Money inArrearsTolerance,
-			final LoanProductRelatedDetail loanProductRelatedDetail,
-			final boolean multiDisburseLoan,
-			final BigDecimal emiAmount,
-			final List<DisbursementData> disbursementDatas,
-			final BigDecimal maxOutstandingBalance,
-			final LocalDate interestChargedFromDate,
-			final BigDecimal principalThresholdForLastInstalment,
-			final Integer installmentAmountInMultiplesOf,
-			final RecalculationFrequencyType recalculationFrequencyType,
-			final CalendarInstance restCalendarInstance,
-			final InterestRecalculationCompoundingMethod compoundingMethod,
-			final CalendarInstance compoundingCalendarInstance,
-			final RecalculationFrequencyType compoundingFrequencyType,
-			final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
-			final LoanRescheduleStrategyMethod rescheduleStrategyMethod,
-			final Calendar loanCalendar, BigDecimal approvedAmount,
-			BigDecimal annualNominalInterestRate,
-			final List<LoanTermVariationsData> loanTermVariations,
-			final CalendarHistoryDataWrapper calendarHistoryDataWrapper,
-			final Integer numberOfdays,
-			final boolean isSkipRepaymentOnFirstDayofMonth) {
-
-		final Integer numberOfRepayments = loanProductRelatedDetail
-				.getNumberOfRepayments();
-		final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
-		final PeriodFrequencyType repaymentPeriodFrequencyType = loanProductRelatedDetail
-				.getRepaymentPeriodFrequencyType();
-		final AmortizationMethod amortizationMethod = loanProductRelatedDetail
-				.getAmortizationMethod();
-		final InterestMethod interestMethod = loanProductRelatedDetail
-				.getInterestMethod();
-		final BigDecimal interestRatePerPeriod = loanProductRelatedDetail
-				.getNominalInterestRatePerPeriod();
-		final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail
-				.getInterestPeriodFrequencyType();
-		final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
-				.getInterestCalculationPeriodMethod();
-		final boolean allowPartialPeriodInterestCalcualtion = loanProductRelatedDetail
-				.isAllowPartialPeriodInterestCalcualtion();
-		final Money principalMoney = loanProductRelatedDetail.getPrincipal();
-
-		//
-		final Integer graceOnPrincipalPayment = loanProductRelatedDetail
-				.graceOnPrincipalPayment();
-		final Integer recurringMoratoriumOnPrincipalPeriods = loanProductRelatedDetail
-				.recurringMoratoriumOnPrincipalPeriods();
-		final Integer graceOnInterestPayment = loanProductRelatedDetail
-				.graceOnInterestPayment();
-		final Integer graceOnInterestCharged = loanProductRelatedDetail
-				.graceOnInterestCharged();
-
-		// Interest recalculation settings
-		final DaysInMonthType daysInMonthType = loanProductRelatedDetail
-				.fetchDaysInMonthType();
-		final DaysInYearType daysInYearType = loanProductRelatedDetail
-				.fetchDaysInYearType();
-		final boolean isInterestRecalculationEnabled = loanProductRelatedDetail
-				.isInterestRecalculationEnabled();
-		final boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = false;
-		return new LoanApplicationTerms(applicationCurrency, loanTermFrequency,
-				loanTermPeriodFrequencyType, numberOfRepayments,
-				repaymentEvery, repaymentPeriodFrequencyType,
-				nthDay.getValue(), dayOfWeek, amortizationMethod,
-				interestMethod, interestRatePerPeriod,
-				interestRatePeriodFrequencyType, annualNominalInterestRate,
-				interestCalculationPeriodMethod,
-				allowPartialPeriodInterestCalcualtion, principalMoney,
-				expectedDisbursementDate, repaymentsStartingFromDate,
-				calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment,
-				recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment,
-				graceOnInterestCharged, interestChargedFromDate,
-				inArrearsTolerance, multiDisburseLoan, emiAmount,
-				disbursementDatas, maxOutstandingBalance,
-				loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType,
-				daysInYearType, isInterestRecalculationEnabled,
-				rescheduleStrategyMethod, compoundingMethod,
-				restCalendarInstance, recalculationFrequencyType,
-				compoundingCalendarInstance, compoundingFrequencyType,
-				principalThresholdForLastInstalment,
-				installmentAmountInMultiplesOf,
-				loanPreClosureInterestCalculationStrategy, loanCalendar,
-				approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
-				isInterestChargedFromDateSameAsDisbursalDateEnabled,
-				numberOfdays, isSkipRepaymentOnFirstDayofMonth);
-	}
-
-	public static LoanApplicationTerms assembleFrom(
-			final ApplicationCurrency applicationCurrency,
-			final Integer loanTermFrequency,
-			final PeriodFrequencyType loanTermPeriodFrequencyType,
-			final LocalDate expectedDisbursementDate,
-			final LocalDate repaymentsStartingFromDate,
-			final LocalDate calculatedRepaymentsStartingFromDate,
-			final Money inArrearsTolerance,
-			final LoanProductRelatedDetail loanProductRelatedDetail,
-			final boolean multiDisburseLoan,
-			final BigDecimal emiAmount,
-			final List<DisbursementData> disbursementDatas,
-			final BigDecimal maxOutstandingBalance,
-			final LocalDate interestChargedFromDate,
-			final LoanInterestRecalculationDetails interestRecalculationDetails,
-			final CalendarInstance restCalendarInstance,
-			final RecalculationFrequencyType recalculationFrequencyType,
-			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,
-			Integer numberOfdays, boolean isSkipRepaymentOnFirstDayofMonth) {
-
-		final Integer numberOfRepayments = loanProductRelatedDetail
-				.getNumberOfRepayments();
-		final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
-		final PeriodFrequencyType repaymentPeriodFrequencyType = loanProductRelatedDetail
-				.getRepaymentPeriodFrequencyType();
-		final AmortizationMethod amortizationMethod = loanProductRelatedDetail
-				.getAmortizationMethod();
-		final InterestMethod interestMethod = loanProductRelatedDetail
-				.getInterestMethod();
-		final BigDecimal interestRatePerPeriod = loanProductRelatedDetail
-				.getNominalInterestRatePerPeriod();
-		final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail
-				.getInterestPeriodFrequencyType();
-		final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
-				.getInterestCalculationPeriodMethod();
-		final boolean allowPartialPeriodInterestCalcualtion = loanProductRelatedDetail
-				.isAllowPartialPeriodInterestCalcualtion();
-		final Money principalMoney = loanProductRelatedDetail.getPrincipal();
-
-		//
-		final Integer graceOnPrincipalPayment = loanProductRelatedDetail
-				.graceOnPrincipalPayment();
-		final Integer recurringMoratoriumOnPrincipalPeriods = loanProductRelatedDetail
-				.recurringMoratoriumOnPrincipalPeriods();
-		final Integer graceOnInterestPayment = loanProductRelatedDetail
-				.graceOnInterestPayment();
-		final Integer graceOnInterestCharged = loanProductRelatedDetail
-				.graceOnInterestCharged();
-
-		// Interest recalculation settings
-		final DaysInMonthType daysInMonthType = loanProductRelatedDetail
-				.fetchDaysInMonthType();
-		final DaysInYearType daysInYearType = loanProductRelatedDetail
-				.fetchDaysInYearType();
-		final boolean isInterestRecalculationEnabled = loanProductRelatedDetail
-				.isInterestRecalculationEnabled();
-		LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
-		InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
-		if (isInterestRecalculationEnabled) {
-			rescheduleStrategyMethod = interestRecalculationDetails
-					.getRescheduleStrategyMethod();
-			interestRecalculationCompoundingMethod = interestRecalculationDetails
-					.getInterestRecalculationCompoundingMethod();
-		}
-		final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
-		final boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = false;
-
-		return new LoanApplicationTerms(applicationCurrency, loanTermFrequency,
-				loanTermPeriodFrequencyType, numberOfRepayments,
-				repaymentEvery, repaymentPeriodFrequencyType, null, null,
-				amortizationMethod, interestMethod, interestRatePerPeriod,
-				interestRatePeriodFrequencyType, annualNominalInterestRate,
-				interestCalculationPeriodMethod,
-				allowPartialPeriodInterestCalcualtion, principalMoney,
-				expectedDisbursementDate, repaymentsStartingFromDate,
-				calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment,
-				recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment,
-				graceOnInterestCharged, interestChargedFromDate,
-				inArrearsTolerance, multiDisburseLoan, emiAmount,
-				disbursementDatas, maxOutstandingBalance,
-				loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType,
-				daysInYearType, isInterestRecalculationEnabled,
-				rescheduleStrategyMethod,
-				interestRecalculationCompoundingMethod, restCalendarInstance,
-				recalculationFrequencyType, compoundingCalendarInstance,
-				compoundingFrequencyType, principalThresholdForLastInstalment,
-				installmentAmountInMultiplesOf,
-				loanPreClosureInterestCalculationStrategy, loanCalendar,
-				approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
-				isInterestChargedFromDateSameAsDisbursalDateEnabled,
-				numberOfdays, isSkipRepaymentOnFirstDayofMonth);
-
-	}
-
-	public static LoanApplicationTerms assembleFrom(
-			final LoanApplicationTerms applicationTerms,
-			final List<LoanTermVariationsData> loanTermVariations) {
-		return new LoanApplicationTerms(
-				applicationTerms.currency,
-				applicationTerms.loanTermFrequency,
-				applicationTerms.loanTermPeriodFrequencyType,
-				applicationTerms.numberOfRepayments,
-				applicationTerms.repaymentEvery,
-				applicationTerms.repaymentPeriodFrequencyType,
-				applicationTerms.nthDay,
-				applicationTerms.weekDayType,
-				applicationTerms.amortizationMethod,
-				applicationTerms.interestMethod,
-				applicationTerms.interestRatePerPeriod,
-				applicationTerms.interestRatePeriodFrequencyType,
-				applicationTerms.annualNominalInterestRate,
-				applicationTerms.interestCalculationPeriodMethod,
-				applicationTerms.allowPartialPeriodInterestCalcualtion,
-				applicationTerms.principal,
-				applicationTerms.expectedDisbursementDate,
-				applicationTerms.repaymentsStartingFromDate,
-				applicationTerms.calculatedRepaymentsStartingFromDate,
-				applicationTerms.principalGrace,
-				applicationTerms.recurringMoratoriumOnPrincipalPeriods,
-				applicationTerms.interestPaymentGrace,
-				applicationTerms.interestChargingGrace,
-				applicationTerms.interestChargedFromDate,
-				applicationTerms.inArrearsTolerance,
-				applicationTerms.multiDisburseLoan,
-				applicationTerms.actualFixedEmiAmount,
-				applicationTerms.disbursementDatas,
-				applicationTerms.maxOutstandingBalance,
-				applicationTerms.graceOnArrearsAgeing,
-				applicationTerms.daysInMonthType,
-				applicationTerms.daysInYearType,
-				applicationTerms.interestRecalculationEnabled,
-				applicationTerms.rescheduleStrategyMethod,
-				applicationTerms.interestRecalculationCompoundingMethod,
-				applicationTerms.restCalendarInstance,
-				applicationTerms.recalculationFrequencyType,
-				applicationTerms.compoundingCalendarInstance,
-				applicationTerms.compoundingFrequencyType,
-				applicationTerms.principalThresholdForLastInstalment,
-				applicationTerms.installmentAmountInMultiplesOf,
-				applicationTerms.preClosureInterestCalculationStrategy,
-				applicationTerms.loanCalendar,
-				applicationTerms.approvedPrincipal.getAmount(),
-				loanTermVariations,
-				applicationTerms.calendarHistoryDataWrapper,
-				applicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled,
-				applicationTerms.numberOfDays,
-				applicationTerms.isSkipRepaymentOnFirstDayOfMonth);
-	}
-
-	private LoanApplicationTerms(
-			final ApplicationCurrency currency,
-			final Integer loanTermFrequency,
-			final PeriodFrequencyType loanTermPeriodFrequencyType,
-			final Integer numberOfRepayments,
-			final Integer repaymentEvery,
-			final PeriodFrequencyType repaymentPeriodFrequencyType,
-			final Integer nthDay,
-			final DayOfWeekType weekDayType,
-			final AmortizationMethod amortizationMethod,
-			final InterestMethod interestMethod,
-			final BigDecimal interestRatePerPeriod,
-			final PeriodFrequencyType interestRatePeriodFrequencyType,
-			final BigDecimal annualNominalInterestRate,
-			final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
-			final boolean allowPartialPeriodInterestCalcualtion,
-			final Money principal,
-			final LocalDate expectedDisbursementDate,
-			final LocalDate repaymentsStartingFromDate,
-			final LocalDate calculatedRepaymentsStartingFromDate,
-			final Integer principalGrace,
-			final Integer recurringMoratoriumOnPrincipalPeriods,
-			final Integer interestPaymentGrace,
-			final Integer interestChargingGrace,
-			final LocalDate interestChargedFromDate,
-			final Money inArrearsTolerance,
-			final boolean multiDisburseLoan,
-			final BigDecimal emiAmount,
-			final List<DisbursementData> disbursementDatas,
-			final BigDecimal maxOutstandingBalance,
-			final Integer graceOnArrearsAgeing,
-			final DaysInMonthType daysInMonthType,
-			final DaysInYearType daysInYearType,
-			final boolean isInterestRecalculationEnabled,
-			final LoanRescheduleStrategyMethod rescheduleStrategyMethod,
-			final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod,
-			final CalendarInstance restCalendarInstance,
-			final RecalculationFrequencyType recalculationFrequencyType,
-			final CalendarInstance compoundingCalendarInstance,
-			final RecalculationFrequencyType compoundingFrequencyType,
-			final BigDecimal principalThresholdForLastInstalment,
-			final Integer installmentAmountInMultiplesOf,
-			final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy,
-			final Calendar loanCalendar, BigDecimal approvedAmount,
-			List<LoanTermVariationsData> loanTermVariations,
-			final CalendarHistoryDataWrapper calendarHistoryDataWrapper,
-			Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled,
-			final Integer numberOfdays,
-			final boolean isSkipRepaymentOnFirstDayofMonth) {
-
-		this.currency = currency;
-		this.loanTermFrequency = loanTermFrequency;
-		this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
-		this.numberOfRepayments = numberOfRepayments;
-		this.repaymentEvery = repaymentEvery;
-		this.repaymentPeriodFrequencyType = repaymentPeriodFrequencyType;
-		this.nthDay = nthDay;
-		this.weekDayType = weekDayType;
-		this.amortizationMethod = amortizationMethod;
-
-		this.interestMethod = interestMethod;
-		this.interestRatePerPeriod = interestRatePerPeriod;
-		this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType;
-		this.annualNominalInterestRate = annualNominalInterestRate;
-		this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
-		this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion;
-
-		this.principal = principal;
-		this.expectedDisbursementDate = expectedDisbursementDate;
-		this.repaymentsStartingFromDate = repaymentsStartingFromDate;
-		this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
-
-		this.principalGrace = principalGrace;
-		this.recurringMoratoriumOnPrincipalPeriods = recurringMoratoriumOnPrincipalPeriods;
-		this.interestPaymentGrace = interestPaymentGrace;
-		this.interestChargingGrace = interestChargingGrace;
-		this.interestChargedFromDate = interestChargedFromDate;
-
-		this.inArrearsTolerance = inArrearsTolerance;
-		this.multiDisburseLoan = multiDisburseLoan;
-		this.fixedEmiAmount = emiAmount;
-		this.actualFixedEmiAmount = emiAmount;
-		this.disbursementDatas = disbursementDatas;
-		this.maxOutstandingBalance = maxOutstandingBalance;
-		this.graceOnArrearsAgeing = graceOnArrearsAgeing;
-		this.daysInMonthType = daysInMonthType;
-		this.daysInYearType = daysInYearType;
-		this.interestRecalculationEnabled = isInterestRecalculationEnabled;
-		this.rescheduleStrategyMethod = rescheduleStrategyMethod;
-		this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
-		this.restCalendarInstance = restCalendarInstance;
-		this.compoundingCalendarInstance = compoundingCalendarInstance;
-		this.recalculationFrequencyType = recalculationFrequencyType;
-		this.compoundingFrequencyType = compoundingFrequencyType;
-		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);
-		this.variationsDataWrapper = new LoanTermVariationsDataWrapper(
-				loanTermVariations);
-		this.actualNumberOfRepayments = numberOfRepayments
-				+ getLoanTermVariations().adjustNumberOfRepayments();
-		this.adjustPrincipalForFlatLoans = principal.zero();
-		if (this.calculatedRepaymentsStartingFromDate == null) {
-			this.seedDate = this.expectedDisbursementDate;
-		} else {
-			this.seedDate = this.calculatedRepaymentsStartingFromDate;
-		}
-		this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
-		this.isInterestChargedFromDateSameAsDisbursalDateEnabled = isInterestChargedFromDateSameAsDisbursalDateEnabled;
-	}
-
-	public Money adjustPrincipalIfLastRepaymentPeriod(
-			final Money principalForPeriod,
-			final Money totalCumulativePrincipalToDate, final int periodNumber) {
-
-		Money adjusted = principalForPeriod;
-
-		final Money totalPrincipalRemaining = this.principal
-				.minus(totalCumulativePrincipalToDate);
-		if (totalPrincipalRemaining.isLessThanZero()) {
-			// paid too much principal, subtract amount that overpays from
-			// principal paid for period.
-			adjusted = principalForPeriod.minus(totalPrincipalRemaining.abs());
-		} else if (this.actualFixedEmiAmount != null) {
-			final Money difference = this.principal
-					.minus(totalCumulativePrincipalToDate);
-			final Money principalThreshold = principalForPeriod.multipliedBy(
-					this.principalThresholdForLastInstalment).dividedBy(100,
-					MoneyHelper.getRoundingMode());
-			if (difference.isLessThan(principalThreshold)) {
-				adjusted = principalForPeriod.plus(difference.abs());
-			}
-		} else if (isLastRepaymentPeriod(this.actualNumberOfRepayments,
-				periodNumber)) {
-
-			final Money difference = totalCumulativePrincipalToDate
-					.minus(this.principal);
-			if (difference.isLessThanZero()) {
-				adjusted = principalForPeriod.plus(difference.abs());
-			} else if (difference.isGreaterThanZero()) {
-				adjusted = principalForPeriod.minus(difference.abs());
-			}
-		}
-
-		return adjusted;
-	}
-
-	public Money adjustInterestIfLastRepaymentPeriod(
-			final Money interestForThisPeriod,
-			final Money totalCumulativeInterestToDate,
-			final Money totalInterestDueForLoan, final int periodNumber) {
-
-		Money adjusted = interestForThisPeriod;
-
-		final Money totalInterestRemaining = totalInterestDueForLoan
-				.minus(totalCumulativeInterestToDate);
-		if (totalInterestRemaining.isLessThanZero()) {
-			// paid too much interest, subtract amount that overpays from
-			// interest paid for period.
-			adjusted = interestForThisPeriod
-					.minus(totalInterestRemaining.abs());
-		} else if (isLastRepaymentPeriod(this.actualNumberOfRepayments,
-				periodNumber)) {
-			final Money interestDifference = totalCumulativeInterestToDate
-					.minus(totalInterestDueForLoan);
-			if (interestDifference.isLessThanZero()) {
-				adjusted = interestForThisPeriod.plus(interestDifference.abs());
-			} else if (interestDifference.isGreaterThanZero()) {
-				adjusted = interestForThisPeriod
-						.minus(interestDifference.abs());
-			}
-		}
-		if (adjusted.isLessThanZero()) {
-			adjusted = adjusted.plus(adjusted);
-		}
-		return adjusted;
-	}
-
-	/**
-	 * Calculates the total interest to be charged on loan taking into account
-	 * grace settings.
-	 * 
-	 */
-	public Money calculateTotalInterestCharged(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final MathContext mc) {
-
-		Money totalInterestCharged = this.principal.zero();
-
-		switch (this.interestMethod) {
-		case FLAT:
-			final Money totalInterestChargedForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(
-					calculator, mc);
-
-			final Money totalInterestPerInstallment = calculateTotalInterestPerInstallmentWithoutGrace(
-					calculator, mc);
-
-			final Money totalGraceOnInterestCharged = totalInterestPerInstallment
-					.multiplyRetainScale(getInterestChargingGrace(),
-							mc.getRoundingMode());
-
-			totalInterestCharged = totalInterestChargedForLoanTerm
-					.minus(totalGraceOnInterestCharged);
-			break;
-		case DECLINING_BALANCE:
-		case INVALID:
-			break;
-		}
-
-		return totalInterestCharged;
-	}
-
-	public Money calculateTotalPrincipalForPeriod(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final Money outstandingBalance, final int periodNumber,
-			final MathContext mc, Money interestForThisInstallment) {
-
-		Money principalForInstallment = this.principal.zero();
-
-		switch (this.interestMethod) {
-		case FLAT:
-			principalForInstallment = calculateTotalPrincipalPerPeriodWithoutGrace(
-					mc, periodNumber);
-			break;
-		case DECLINING_BALANCE:
-			switch (this.amortizationMethod) {
-			case EQUAL_INSTALLMENTS:
-				Money totalPmtForThisInstallment = pmtForInstallment(
-						calculator, outstandingBalance, periodNumber, mc);
-				principalForInstallment = calculatePrincipalDueForInstallment(
-						periodNumber, totalPmtForThisInstallment,
-						interestForThisInstallment);
-				break;
-			case EQUAL_PRINCIPAL:
-				principalForInstallment = calculateEqualPrincipalDueForInstallment(
-						mc, periodNumber);
-				break;
-			case INVALID:
-				break;
-			}
-			break;
-		case INVALID:
-			break;
-		}
-
-		return principalForInstallment;
-	}
-
-	public Money pmtForInstallment(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final Money outstandingBalance, final int periodNumber,
-			final MathContext mc) {
-		// Calculate exact period from disbursement date
-		final LocalDate periodStartDate = getExpectedDisbursementDate()
-				.withDayOfMonth(1);
-		final LocalDate periodEndDate = getPeriodEndDate(periodStartDate);
-		// equal installments
-		final int periodsElapsed = periodNumber - 1;
-		// with periodic interest for default month and year for
-		// equal installment
-		final BigDecimal periodicInterestRateForRepaymentPeriod = periodicInterestRate(
-				calculator, mc, DaysInMonthType.DAYS_30,
-				DaysInYearType.DAYS_365, periodStartDate, periodEndDate);
-		Money totalPmtForThisInstallment = calculateTotalDueForEqualInstallmentRepaymentPeriod(
-				periodicInterestRateForRepaymentPeriod, outstandingBalance,
-				periodsElapsed);
-		return totalPmtForThisInstallment;
-	}
-
-	private LocalDate getPeriodEndDate(final LocalDate startDate) {
-		LocalDate dueRepaymentPeriodDate = startDate;
-		switch (this.repaymentPeriodFrequencyType) {
-		case DAYS:
-			dueRepaymentPeriodDate = startDate.plusDays(this.repaymentEvery);
-			break;
-		case WEEKS:
-			dueRepaymentPeriodDate = startDate.plusWeeks(this.repaymentEvery);
-			break;
-		case MONTHS:
-			dueRepaymentPeriodDate = startDate.plusMonths(this.repaymentEvery);
-			break;
-		case YEARS:
-			dueRepaymentPeriodDate = startDate.plusYears(this.repaymentEvery);
-			break;
-		case INVALID:
-			break;
-		}
-		return dueRepaymentPeriodDate;
-	}
-
-	public PrincipalInterest calculateTotalInterestForPeriod(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final double interestCalculationGraceOnRepaymentPeriodFraction,
-			final int periodNumber, final MathContext mc,
-			final Money cumulatingInterestPaymentDueToGrace,
-			final Money outstandingBalance, final LocalDate periodStartDate,
-			final LocalDate periodEndDate) {
-
-		Money interestForInstallment = this.principal.zero();
-		Money interestBroughtForwardDueToGrace = cumulatingInterestPaymentDueToGrace
-				.copy();
-
-		switch (this.interestMethod) {
-		case FLAT:
-
-			switch (this.amortizationMethod) {
-			case EQUAL_INSTALLMENTS:
-				// average out outstanding interest over remaining
-				// instalments where interest is applicable
-				interestForInstallment = calculateTotalFlatInterestForInstallmentAveragingOutGracePeriods(
-						calculator, periodNumber, mc);
-				break;
-			case EQUAL_PRINCIPAL:
-				// interest follows time-value of money and is brought
-				// forward to next applicable interest payment period
-				final PrincipalInterest result = calculateTotalFlatInterestForPeriod(
-						calculator, periodNumber, mc,
-						interestBroughtForwardDueToGrace);
-				interestForInstallment = result.interest();
-				interestBroughtForwardDueToGrace = result
-						.interestPaymentDueToGrace();
-				break;
-			case INVALID:
-				break;
-			}
-			break;
-		case DECLINING_BALANCE:
-
-			final Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(
-					calculator, mc, outstandingBalance, periodStartDate,
-					periodEndDate);
-
-			final Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(
-					calculator,
-					interestCalculationGraceOnRepaymentPeriodFraction, mc,
-					outstandingBalance, periodNumber, periodStartDate,
-					periodEndDate);
-
-			interestForInstallment = interestForThisInstallmentAfterGrace;
-			if (interestForThisInstallmentAfterGrace.isGreaterThanZero()) {
-				interestForInstallment = interestBroughtForwardDueToGrace
-						.plus(interestForThisInstallmentAfterGrace);
-				interestBroughtForwardDueToGrace = interestBroughtForwardDueToGrace
-						.zero();
-			} else if (isInterestFreeGracePeriod(periodNumber)) {
-				interestForInstallment = interestForInstallment.zero();
-			} else if (isInterestFreeGracePeriodFromDate(interestCalculationGraceOnRepaymentPeriodFraction)) {
-				interestForInstallment = interestForThisInstallmentAfterGrace;
-			} else {
-				interestBroughtForwardDueToGrace = interestBroughtForwardDueToGrace
-						.plus(interestForThisInstallmentBeforeGrace);
-			}
-			break;
-		case INVALID:
-			break;
-		}
-
-		return new PrincipalInterest(null, interestForInstallment,
-				interestBroughtForwardDueToGrace);
-	}
-
-	private final boolean isLastRepaymentPeriod(final int numberOfRepayments,
-			final int periodNumber) {
-		return periodNumber == numberOfRepayments;
-	}
-
-	/**
-	 * general method to calculate totalInterestDue discounting any grace
-	 * settings
-	 */
-	private Money calculateTotalFlatInterestDueWithoutGrace(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final MathContext mc) {
-
-		Money totalInterestDue = this.principal.zero();
-
-		switch (this.interestMethod) {
-		case FLAT:
-			final BigDecimal interestRateForLoanTerm = calculateFlatInterestRateForLoanTerm(
-					calculator, mc);
-			totalInterestDue = this.principal.multiplyRetainScale(
-					interestRateForLoanTerm, mc.getRoundingMode());
-
-			break;
-		case DECLINING_BALANCE:
-			break;
-		case INVALID:
-			break;
-		}
-
-		if (this.totalInterestDue != null) {
-			totalInterestDue = this.totalInterestDue;
-		}
-
-		return totalInterestDue;
-	}
-
-	private BigDecimal calculateFlatInterestRateForLoanTerm(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final MathContext mc) {
-
-		final BigDecimal divisor = BigDecimal.valueOf(Double.valueOf("100.0"));
-
-		final long loanTermPeriodsInOneYear = calculatePeriodsInOneYear(calculator);
-		final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal
-				.valueOf(loanTermPeriodsInOneYear);
-
-		final BigDecimal loanTermFrequencyBigDecimal = calculatePeriodsInLoanTerm();
-
-		return this.annualNominalInterestRate
-				.divide(loanTermPeriodsInYearBigDecimal, mc)
-				.divide(divisor, mc).multiply(loanTermFrequencyBigDecimal);
-	}
-
-	private BigDecimal calculatePeriodsInLoanTerm() {
-
-		BigDecimal periodsInLoanTerm = BigDecimal
-				.valueOf(this.loanTermFrequency);
-		switch (this.interestCalculationPeriodMethod) {
-		case DAILY:
-			// number of days from 'ideal disbursement' to final date
-
-			LocalDate loanStartDate = getExpectedDisbursementDate();
-			if (getInterestChargedFromDate() != null
-					&& loanStartDate
-							.isBefore(getInterestChargedFromLocalDate())) {
-				loanStartDate = getInterestChargedFromLocalDate();
-			}
-
-			final int periodsInLoanTermInteger = Days.daysBetween(
-					loanStartDate, this.loanEndDate).getDays();
-			periodsInLoanTerm = BigDecimal.valueOf(periodsInLoanTermInteger);
-			break;
-		case INVALID:
-			break;
-		case SAME_AS_REPAYMENT_PERIOD:
-			if (this.allowPartialPeriodInterestCalcualtion) {
-				LocalDate startDate = getExpectedDisbursementDate();
-				if (getInterestChargedFromDate() != null) {
-					startDate = getInterestChargedFromLocalDate();
-				}
-				periodsInLoanTerm = calculatePeriodsBetweenDates(startDate,
-						this.loanEndDate);
-			}
-			break;
-		}
-
-		return periodsInLoanTerm;
-	}
-
-	public BigDecimal calculatePeriodsBetweenDates(final LocalDate startDate,
-			final LocalDate endDate) {
-		BigDecimal numberOfPeriods = BigDecimal.ZERO;
-		switch (this.repaymentPeriodFrequencyType) {
-		case DAYS:
-			int numberOfDays = Days.daysBetween(startDate, endDate).getDays();
-			numberOfPeriods = BigDecimal.valueOf((double) numberOfDays);
-			break;
-		case WEEKS:
-			int numberOfWeeks = Weeks.weeksBetween(startDate, endDate)
-					.getWeeks();
-			int daysLeftAfterWeeks = Days.daysBetween(
-					startDate.plusWeeks(numberOfWeeks), endDate).getDays();
-			numberOfPeriods = numberOfPeriods.add(
-					BigDecimal.valueOf(numberOfWeeks)).add(
-					BigDecimal.valueOf((double) daysLeftAfterWeeks / 7));
-			break;
-		case MONTHS:
-			int numberOfMonths = Months.monthsBetween(startDate, endDate)
-					.getMonths();
-			LocalDate startDateAfterConsideringMonths = startDate
-					.plusMonths(numberOfMonths);
-			LocalDate endDateAfterConsideringMonths = startDate
-					.plusMonths(numberOfMonths + 1);
-			int daysLeftAfterMonths = Days.daysBetween(
-					startDateAfterConsideringMonths, endDate).getDays();
-			int daysInPeriodAfterMonths = Days.daysBetween(
-					startDateAfterConsideringMonths,
-					endDateAfterConsideringMonths).getDays();
-			numberOfPeriods = numberOfPeriods.add(
-					BigDecimal.valueOf(numberOfMonths)).add(
-					BigDecimal.valueOf((double) daysLeftAfterMonths
-							/ daysInPeriodAfterMonths));
-			break;
-		case YEARS:
-			int numberOfYears = Years.yearsBetween(startDate, endDate)
-					.getYears();
-			LocalDate startDateAfterConsideringYears = startDate
-					.plusYears(numberOfYears);
-			LocalDate endDateAfterConsideringYears = startDate
-					.plusYears(numberOfYears + 1);
-			int daysLeftAfterYears = Days.daysBetween(
-					startDateAfterConsideringYears, endDate).getDays();
-			int daysInPeriodAfterYears = Days.daysBetween(
-					startDateAfterConsideringYears,
-					endDateAfterConsideringYears).getDays();
-			numberOfPeriods = numberOfPeriods.add(
-					BigDecimal.valueOf(numberOfYears)).add(
-					BigDecimal.valueOf((double) daysLeftAfterYears
-							/ daysInPeriodAfterYears));
-			break;
-		default:
-			break;
-		}
-		return numberOfPeriods;
-	}
-
-	public void updateLoanEndDate(final LocalDate loanEndDate) {
-		this.loanEndDate = loanEndDate;
-	}
-
-	private Money calculateTotalInterestPerInstallmentWithoutGrace(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final MathContext mc) {
-
-		final Money totalInterestForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(
-				calculator, mc);
-
-		return totalInterestForLoanTerm.dividedBy(
-				Long.valueOf(this.actualNumberOfRepayments),
-				mc.getRoundingMode());
-	}
-
-	private Money calculateTotalPrincipalPerPeriodWithoutGrace(
-			final MathContext mc, final int periodNumber) {
-		final int totalRepaymentsWithCapitalPayment = calculateNumberOfRepaymentsWithPrincipalPayment();
-		Money principalPerPeriod = this.principal.dividedBy(
-				totalRepaymentsWithCapitalPayment, mc.getRoundingMode()).plus(
-				this.adjustPrincipalForFlatLoans);
-		if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
-			principalPerPeriod = principalPerPeriod.zero();
-		}
-		if (!isPrincipalGraceApplicableForThisPeriod(periodNumber)
-				&& currentPeriodFixedPrincipalAmount != null) {
-			this.adjustPrincipalForFlatLoans = this.adjustPrincipalForFlatLoans
-					.plus(principalPerPeriod.minus(
-							currentPeriodFixedPrincipalAmount).dividedBy(
-							this.actualNumberOfRepayments - periodNumber,
-							mc.getRoundingMode()));
-			principalPerPeriod = this.principal.zero().plus(
-					currentPeriodFixedPrincipalAmount);
-
-		}
-		return principalPerPeriod;
-	}
-
-	private PrincipalInterest calculateTotalFlatInterestForPeriod(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final int periodNumber, final MathContext mc,
-			final Money cumulatingInterestPaymentDueToGrace) {
-
-		Money interestBroughtForwardDueToGrace = cumulatingInterestPaymentDueToGrace
-				.copy();
-
-		Money interestForInstallment = calculateTotalInterestPerInstallmentWithoutGrace(
-				calculator, mc);
-		if (isInterestPaymentGraceApplicableForThisPeriod(periodNumber)) {
-			interestBroughtForwardDueToGrace = interestBroughtForwardDueToGrace
-					.plus(interestForInstallment);
-			interestForInstallment = interestForInstallment.zero();
-		} else if (isInterestFreeGracePeriod(periodNumber)) {
-			interestForInstallment = interestForInstallment.zero();
-		} else if (isFirstPeriodAfterInterestPaymentGracePeriod(periodNumber)) {
-			interestForInstallment = cumulatingInterestPaymentDueToGrace
-					.plus(interestForInstallment);
-			interestBroughtForwardDueToGrace = interestBroughtForwardDueToGrace
-					.zero();
-		}
-
-		return new PrincipalInterest(null, interestForInstallment,
-				interestBroughtForwardDueToGrace);
-	}
-
-	/*
-	 * calculates the interest that should be due for a given scheduled loan
-	 * repayment period. It takes into account GRACE periods and calculates how
-	 * much interest is due per period by averaging the number of periods where
-	 * interest is due and should be paid against the total known interest that
-	 * is due without grace.
-	 */
-	private Money calculateTotalFlatInterestForInstallmentAveragingOutGracePeriods(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final int periodNumber, final MathContext mc) {
-
-		Money interestForInstallment = calculateTotalInterestPerInstallmentWithoutGrace(
-				calculator, mc);
-		if (isInterestPaymentGraceApplicableForThisPeriod(periodNumber)) {
-			interestForInstallment = interestForInstallment.zero();
-		} else if (isInterestFreeGracePeriod(periodNumber)) {
-			interestForInstallment = interestForInstallment.zero();
-		} else {
-
-			final Money totalInterestForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(
-					calculator, mc);
-
-			final Money interestPerGracePeriod = calculateTotalInterestPerInstallmentWithoutGrace(
-					calculator, mc);
-
-			final Money totalInterestFree = interestPerGracePeriod
-					.multipliedBy(getInterestChargingGrace());
-			final Money realTotalInterestForLoan = totalInterestForLoanTerm
-					.minus(totalInterestFree);
-
-			final Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.actualNumberOfRepayments);
-
-			interestForInstallment = realTotalInterestForLoan.dividedBy(
-					BigDecimal.valueOf(interestPaymentDuePeriods),
-					mc.getRoundingMode());
-		}
-
-		return interestForInstallment;
-	}
-
-	private BigDecimal periodicInterestRate(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final MathContext mc, final DaysInMonthType daysInMonthType,
-			final DaysInYearType daysInYearType, LocalDate periodStartDate,
-			LocalDate periodEndDate) {
-
-		final long loanTermPeriodsInOneYear = calculatePeriodsInOneYear(calculator);
-
-		final BigDecimal divisor = BigDecimal.valueOf(Double.valueOf("100.0"));
-		final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal
-				.valueOf(loanTermPeriodsInOneYear);
-
-		BigDecimal periodicInterestRate = BigDecimal.ZERO;
-		BigDecimal loanTermFrequencyBigDecimal = calculateLoanTermFrequency(
-				periodStartDate, periodEndDate);
-		switch (this.interestCalculationPeriodMethod) {
-		case INVALID:
-			break;
-		case DAILY:
-			// For daily work out number of days in the period
-			BigDecimal numberOfDaysInPeriod = BigDecimal.valueOf(Days
-					.daysBetween(periodStartDate, periodEndDate).getDays());
-
-			final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate
-					.divide(loanTermPeriodsInYearBigDecimal, mc).divide(
-							divisor, mc);
-
-			switch (this.repaymentPeriodFrequencyType) {
-			case INVALID:
-				break;
-			case DAYS:
-				periodicInterestRate = oneDayOfYearInterestRate.multiply(
-						numberOfDaysInPeriod, mc);
-				break;
-			case WEEKS:
-				periodicInterestRate = oneDayOfYearInterestRate.multiply(
-						numberOfDaysInPeriod, mc);
-				break;
-			case MONTHS:
-				if (daysInMonthType.isDaysInMonth_30()) {
-					numberOfDaysInPeriod = loanTermFrequencyBigDecimal
-							.multiply(BigDecimal.valueOf(30), mc);
-				}
-				periodicInterestRate = oneDayOfYearInterestRate.multiply(
-						numberOfDaysInPeriod, mc);
-				break;
-			case YEARS:
-				switch (daysInYearType) {
-				case DAYS_360:
-					numberOfDaysInPeriod = loanTermFrequencyBigDecimal
-							.multiply(BigDecimal.valueOf(360), mc);
-					break;
-				case DAYS_364:
-					numberOfDaysInPeriod = loanTermFrequencyBigDecimal
-							.multiply(BigDecimal.valueOf(364), mc);
-					break;
-				case DAYS_365:
-					numberOfDaysInPeriod = loanTermFrequencyBigDecimal
-							.multiply(BigDecimal.valueOf(365), mc);
-					break;
-				default:
-					break;
-				}
-				periodicInterestRate = oneDayOfYearInterestRate.multiply(
-						numberOfDaysInPeriod, mc);
-				break;
-			}
-			break;
-		case SAME_AS_REPAYMENT_PERIOD:
-			periodicInterestRate = this.annualNominalInterestRate
-					.divide(loanTermPeriodsInYearBigDecimal, mc)
-					.divide(divisor, mc).multiply(loanTermFrequencyBigDecimal);
-			break;
-		}
-
-		return periodicInterestRate;
-	}
-
-	private BigDecimal calculateLoanTermFrequency(
-			final LocalDate periodStartDate, final LocalDate periodEndDate) {
-		BigDecimal loanTermFrequencyBigDecimal = BigDecimal
-				.valueOf(this.repaymentEvery);
-		if (this.interestCalculationPeriodMethod.isDaily()
-				|| this.allowPartialPeriodInterestCalcualtion) {
-			loanTermFrequencyBigDecimal = calculatePeriodsBetweenDates(
-					periodStartDate, periodEndDate);
-		}
-		return loanTermFrequencyBigDecimal;
-	}
-
-	public BigDecimal interestRateFor(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final MathContext mc, final Money outstandingBalance,
-			final LocalDate fromDate, final LocalDate toDate) {
-
-		long loanTermPeriodsInOneYear = calculator.calculate(
-				PeriodFrequencyType.DAYS).longValue();
-		int repaymentEvery = Days.daysBetween(fromDate, toDate).getDays();
-		if (isFallingInRepaymentPeriod(fromDate, toDate)) {
-			loanTermPeriodsInOneYear = calculatePeriodsInOneYear(calculator);
-			repaymentEvery = getPeriodsBetween(fromDate, toDate);
-		}
-
-		final BigDecimal divisor = BigDecimal.valueOf(Double.valueOf("100.0"));
-		final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal
-				.valueOf(loanTermPeriodsInOneYear);
-		final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate
-				.divide(loanTermPeriodsInYearBigDecimal, mc)
-				.divide(divisor, mc);
-		BigDecimal interestRate = oneDayOfYearInterestRate.multiply(
-				BigDecimal.valueOf(repaymentEvery), mc);
-		return outstandingBalance.getAmount().multiply(interestRate, mc);
-	}
-
-	private long calculatePeriodsInOneYear(
-			final PaymentPeriodsInOneYearCalculator calculator) {
-
-		// check if daysInYears is set if so change periodsInOneYear to days set
-		// in db
-		long periodsInOneYear;
-		boolean daysInYearToUse = (this.repaymentPeriodFrequencyType.getCode()
-				.equalsIgnoreCase("periodFrequencyType.days") && !this.daysInYearType
-				.getCode().equalsIgnoreCase("DaysInYearType.actual"));
-		if (daysInYearToUse) {
-			periodsInOneYear = this.daysInYearType.getValue().longValue();
-		} else {
-			periodsInOneYear = calculator.calculate(
-					this.repaymentPeriodFrequencyType).longValue();
-		}
-		switch (this.interestCalculationPeriodMethod) {
-		case DAILY:
-			periodsInOneYear = (!this.daysInYearType.getCode()
-					.equalsIgnoreCase("DaysInYearType.actual")) ? this.daysInYearType
-					.getValue().longValue() : calculator.calculate(
-					PeriodFrequencyType.DAYS).longValue();
-			break;
-		case INVALID:
-			break;
-		case SAME_AS_REPAYMENT_PERIOD:
-			break;
-		}
-
-		return periodsInOneYear;
-	}
-
-	private int calculateNumberOfRepaymentsWithPrincipalPayment() {
-		int numPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(
-				this.actualNumberOfRepayments,
-				this.getRecurringMoratoriumOnPrincipalPeriods(),
-				this.getPrincipalGrace(), 0);
-		return numPeriods;
-	}
-
-	private Integer calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(
-			final Integer totalNumberOfRepaymentPeriods) {
-		return totalNumberOfRepaymentPeriods
-				- Math.max(getInterestChargingGrace(),
-						getInterestPaymentGrace());
-	}
-
-	public boolean isPrincipalGraceApplicableForThisPeriod(
-			final int periodNumber) {
-		if (this.getRecurringMoratoriumOnPrincipalPeriods() > 0) {
-			return ((periodNumber > 0 && periodNumber <= getPrincipalGrace()) || (periodNumber > 0 && (((periodNumber - getPrincipalGrace()) % (this
-					.getRecurringMoratoriumOnPrincipalPeriods() + 1)) != 1)));
-		} else {
-			return periodNumber > 0 && periodNumber <= getPrincipalGrace();
-		}
-	}
-
-	private boolean isInterestPaymentGraceApplicableForThisPeriod(
-			final int periodNumber) {
-		return periodNumber > 0 && periodNumber <= getInterestPaymentGrace();
-	}
-
-	private boolean isFirstPeriodAfterInterestPaymentGracePeriod(
-			final int periodNumber) {
-		return periodNumber > 0
-				&& periodNumber == getInterestPaymentGrace() + 1;
-	}
-
-	private boolean isInterestFreeGracePeriod(final int periodNumber) {
-		return periodNumber > 0 && periodNumber <= getInterestChargingGrace();
-	}
-
-	public Integer getPrincipalGrace() {
-		Integer graceOnPrincipalPayments = Integer.valueOf(0);
-		if (this.principalGrace != null) {
-			graceOnPrincipalPayments = this.principalGrace;
-		}
-		return graceOnPrincipalPayments;
-	}
-
-	public Integer getRecurringMoratoriumOnPrincipalPeriods() {
-		Integer recurringMoratoriumOnPrincipalPeriods = Integer.valueOf(0);
-		if (this.recurringMoratoriumOnPrincipalPeriods != null) {
-			recurringMoratoriumOnPrincipalPeriods = this.recurringMoratoriumOnPrincipalPeriods;
-		}
-		return recurringMoratoriumOnPrincipalPeriods;
-	}
-
-	public Integer getInterestPaymentGrace() {
-		Integer graceOnInterestPayments = Integer.valueOf(0);
-		if (this.interestPaymentGrace != null) {
-			graceOnInterestPayments = this.interestPaymentGrace;
-		}
-		return graceOnInterestPayments;
-	}
-
-	public Integer getInterestChargingGrace() {
-		Integer graceOnInterestCharged = Integer.valueOf(0);
-		if (this.interestChargingGrace != null) {
-			graceOnInterestCharged = this.interestChargingGrace;
-		}
-		return graceOnInterestCharged;
-	}
-
-	private double paymentPerPeriod(final BigDecimal periodicInterestRate,
-			final Money balance, final int periodsElapsed) {
-
-		if (getFixedEmiAmount() == null) {
-			final double futureValue = 0;
-			final double principalDouble = balance.getAmount()
-					.multiply(BigDecimal.valueOf(-1)).doubleValue();
-
-			final Integer periodsRemaining = calculateNumberOfRemainingPrincipalPaymentPeriods(
-					this.actualNumberOfRepayments,
-					this.getRecurringMoratoriumOnPrincipalPeriods(),
-					this.getPrincipalGrace(), periodsElapsed);
-
-			double installmentAmount = FinanicalFunctions.pmt(
-					periodicInterestRate.doubleValue(),
-					periodsRemaining.doubleValue(), principalDouble,
-					futureValue, false);
-
-			if (this.installmentAmountInMultiplesOf != null) {
-				installmentAmount = Money.roundToMultiplesOf(installmentAmount,
-						this.installmentAmountInMultiplesOf);
-			}
-			setFixedEmiAmount(BigDecimal.valueOf(installmentAmount));
-		}
-		return getFixedEmiAmount().doubleValue();
-	}
-
-	private Money calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final MathContext mc, final Money outstandingBalance,
-			LocalDate periodStartDate, LocalDate periodEndDate) {
-
-		Money interestDue = Money.zero(outstandingBalance.getCurrency());
-
-		final BigDecimal periodicInterestRate = periodicInterestRate(
-				calculator, mc, this.daysInMonthType, this.daysInYearType,
-				periodStartDate, periodEndDate);
-		interestDue = outstandingBalance.multiplyRetainScale(
-				periodicInterestRate, mc.getRoundingMode());
-
-		return interestDue;
-	}
-
-	private Money calculateDecliningInterestDueForInstallmentAfterApplyingGrace(
-			final PaymentPeriodsInOneYearCalculator calculator,
-			final double interestCalculationGraceOnRepaymentPeriodFraction,
-			final MathContext mc, final Money outstandingBalance,
-			final int periodNumber, LocalDate periodStartDate,
-			LocalDate periodEndDate) {
-
-		Money interest = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(
-				calculator, mc, outstandingBalance, periodStartDate,
-				periodEndDate);
-
-		if (isInterestPaymentGraceApplicableForThisPeriod(periodNumber)) {
-			interest = interest.zero();
-		}
-
-		Double fraction = interestCalculationGraceOnRepaymentPeriodFraction;
-
-		if (isInterestFreeGracePeriod(periodNumber)) {
-			interest = interest.zero();
-		} else if (isInterestFreeGracePeriodFromDate(interestCalculationGraceOnRepaymentPeriodFraction)) {
-
-			if (interestCalculationGraceOnRepaymentPeriodFraction >= Integer
-					.valueOf(1).doubleValue()) {
-				interest = interest.zero();
-				fraction = fraction - Integer.valueOf(1).doubleValue();
-
-			} else if (interestCalculationGraceOnRepaymentPeriodFraction > Double
-					.valueOf("0.25")
-					&& interestCalculationGraceOnRepaymentPeriodFraction < Integer
-							.valueOf(1).doubleValue()) {
-
-				final Money graceOnInterestForRepaymentPeriod = interest
-						.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction);
-				interest = interest.minus(graceOnInterestForRepaymentPeriod);
-				fraction = Double.valueOf("0");
-			}
-		}
-
-		return interest;
-	}
-
-	private boolean isInterestFreeGracePeriodFromDate(
-			final double interestCalculationGraceOnRepaymentPeriodFraction) {
-		return this.interestChargedFromDate != null
-				&& interestCalculationGraceOnRepaymentPeriodFraction > Double
-						.valueOf("0.0");
-	}
-
-	private Money calculateEqualPrincipalDueForInstallment(
-			final MathContext mc, final int periodNumber) {
-		Money principal = this.principal;
-		if (this.fixedPrincipalAmount == null) {
-			final Integer numberOfPrincipalPaymentPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(
-					this.actualNumberOfRepayments,
-					this.getRecurringMoratoriumOnPrincipalPeriods(),
-					this.getPrincipalGrace(), periodNumber);
-			principal = this.principal.dividedBy(
-					numberOfPrincipalPaymentPeriods, mc.getRoundingMode());
-			this.fixedPrincipalAmount = principal.getAmount();
-		}
-		principal = Money.of(getCurrency(), getFixedPrincipalAmount());
-
-		if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
-			principal = principal.zero();
-		}
-		return principal;
-	}
-
-	public void updateFixedPrincipalAmount(final MathContext mc,
-			final int periodNumber, final Money outstandingAmount) {
-		final Integer numberOfPrincipalPaymentPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(
-				this.actualNumberOfRepayments,
-				this.getRecurringMoratoriumOnPrincipalPeriods(),
-				this.getPrincipalGrace(), periodNumber - 1);
-		Money principal = outstandingAmount.dividedBy(
-				numberOfPrincipalPaymentPeriods, mc.getRoundingMode());
-		this.fixedPrincipalAmount = principal.getAmount();
-	}
-
-	private static Integer calculateNumberOfRemainingPrincipalPaymentPeriods(
-			final Integer totalNumberOfRepaymentPeriods,
-			final int recurringMoratoriumOnPrincipalPeriods,
-			final int PrincipalGrace, int periodsElapsed) {
-		if (PrincipalGrace > periodsElapsed) {
-			periodsElapsed = PrincipalGrace;
-		}
-		Integer periodsRemaining = totalNumberOfRepaymentPeriods
-				- periodsElapsed;
-		if (recurringMoratoriumOnPrincipalPeriods > 0) {
-			double periodsRemainingDouble = ((double) periodsRemaining / ((double) (recurringMoratoriumOnPrincipalPeriods + 1)));
-			periodsRemaining = (int) Math.ceil(periodsRemainingDouble);
-		}
-		return periodsRemaining;
-	}
-
-	public void setFixedPrincipalAmount(BigDecimal fixedPrincipalAmount) {
-		this.fixedPrincipalAmount = fixedPrincipalAmount;
-	}
-
-	private Money calculatePrincipalDueForInstallment(final int periodNumber,
-			final Money totalDuePerInstallment, final Money periodInterest) {
-
-		Money principal = totalDuePerInstallment.minus(periodInterest);
-		if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
-			principal = principal.zero();
-		}
-		return principal;
-	}
-
-	private Money calculateTotalDueForEqualInstallmentRepaymentPeriod(
-			final BigDecimal periodicInterestRate, final Money balance,
-			final int periodsElapsed) {
-
-		final double paymentPerRepaymentPeriod = paymentPerPeriod(
-				periodicInterestRate, balance, periodsElapsed);
-
-		return Money.of(balance.getCurrency(),
-				BigDecimal.valueOf(paymentPerRepaymentPeriod));
-	}
-
-	public LoanProductRelatedDetail toLoanProductRelatedDetail() {
-		final MonetaryCurrency currency = new MonetaryCurrency(
-				this.currency.getCode(), this.currency.getDecimalPlaces(),
-				this.currency.getCurrencyInMultiplesOf());
-
-		return LoanProductRelatedDetail.createFrom(currency,
-				this.principal.getAmount(), this.interestRatePerPeriod,
-				this.interestRatePeriodFrequencyType,
-				this.annualNominalInterestRate, this.interestMethod,
-				this.interestCalculationPeriodMethod,
-				this.allowPartialPeriodInterestCalcualtion,
-				this.repaymentEvery, this.repaymentPeriodFrequencyType,
-				this.numberOfRepayments, this.principalGrace,
-				this.recurringMoratoriumOnPrincipalPeriods,
-				this.interestPaymentGrace, this.interestChargingGrace,
-				this.amortizationMethod, this.inArrearsTolerance.getAmount(),
-				this.graceOnArrearsAgeing, this.daysInMonthType.getValue(),
-				this.daysInYearType.getValue(),
-				this.interestRecalculationEnabled);
-	}
-
-	public Integer getLoanTermFrequency() {
-		return this.loanTermFrequency;
-	}
-
-	public PeriodFrequencyType getLoanTermPeriodFrequencyType() {
-		return this.loanTermPeriodFrequencyType;
-	}
-
-	public Integer getRepaymentEvery() {
-		return this.repaymentEvery;
-	}
-
-	public PeriodFrequencyType getRepaymentPeriodFrequencyType() {
-		return this.repaymentPeriodFrequencyType;
-	}
-
-	public Date getRepaymentStartFromDate() {
-		Date dateValue = null;
-		if (this.repaymentsStartingFromDate != null) {
-			dateValue = this.repaymentsStartingFromDate.toDate();
-		}
-		return dateValue;
-	}
-
-	public Date getInterestChargedFromDate() {
-		Date dateValue = null;
-		if (this.interestChargedFromDate != null) {
-			dateValue = this.interestChargedFromDate.toDate();
-		}
-		return dateValue;
-	}
-
-	public void setPrincipal(Money principal) {
-		this.principal = principal;
-	}
-
-	public LocalDate getInterestChargedFromLocalDate() {
-		return this.interestChargedFromDate;
-	}
-
-	public InterestMethod getInterestMethod() {
-		return this.interestMethod;
-	}
-
-	public AmortizationMethod getAmortizationMethod() {
-		return this.amortizationMethod;
-	}
-
-	public MonetaryCurrency getCurrency() {
-		return this.principal.getCurrency();
-	}
-
-	public Integer getNumberOfRepayments() {
-		return this.numberOfRepayments;
-	}
-
-	public LocalDate getExpectedDisbursementDate() {
-		return this.expectedDisbursementDate;
-	}
-
-	public LocalDate getRepaymentsStartingFromLocalDate() {
-		return this.repaymentsStartingFromDate;
-	}
-
-	public LocalDate getCalculatedRepaymentsStartingFromLocalDate() {
-		return this.calculatedRepaymentsStartingFromDate;
-	}
-
-	public Money getPrincipal() {
-		return this.principal;
-	}
-
-	public Money getApprovedPrincipal() {
-		return this.approvedPrincipal;
-	}
-
-	public List<DisbursementData> getDisbursementDatas() {
-		return this.disbursementDatas;
-	}
-
-	public boolean isMultiDisburseLoan() {
-		return this.multiDisburseLoan;
-	}
-
-	public Money getMaxOutstandingBalance() {
-		return Money.of(getCurrency(), this.maxOutstandingBalance);
-	}
-
-	public BigDecimal getFixedEmiAmount() {
-		BigDecimal fixedEmiAmount = this.fixedEmiAmount;
-		if (getCurrentPeriodFixedEmiAmount() != null) {
-			fixedEmiAmount = getCurrentPeriodFixedEmiAmount();
-		}
-		return fixedEmiAmount;
-	}
-
-	public Integer getNthDay() {
-		return this.nthDay;
-	}
-
-	public DayOfWeekType getWeekDayType() {
-		return this.weekDayType;
-	}
-
-	public void setFixedEmiAmount(BigDecimal fixedEmiAmount) {
-		this.fixedEmiAmount = fixedEmiAmount;
-	}
-
-	public void resetFixedEmiAmount() {
-		this.fixedEmiAmount = this.actualFixedEmiAmount;
-	}
-
-	public LoanRescheduleStrategyMethod getLoanRescheduleStrategyMethod() {
-		return LoanRescheduleStrategyMethod.REDUCE_EMI_AMOUNT;
-	}
-
-	public boolean isInterestRecalculationEnabled() {
-		return this.interestRecalculationEnabled;
-	}
-
-	public LoanRescheduleStrategyMethod getRescheduleStrategyMethod() {
-		return this.rescheduleStrategyMethod;
-	}
-
-	public InterestRecalculationCompoundingMethod getInterestRecalculationCompoundingMethod() {
-		return this.interestRecalculationCompoundingMethod;
-	}
-
-	public CalendarInstance getRestCalendarInstance() {
-		return this.restCalendarInstance;
-	}
-
-	private boolean isFallingInRepaymentPeriod(LocalDate fromDate,
-			LocalDate toDate) {
-		boolean isSameAsRepaymentPeriod = false;
-		if (this.interestCalculationPeriodMethod.getValue().equals(
-				InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD
-						.getValue())) {
-			switch (this.repaymentPeriodFrequencyType) {
-			case WEEKS:
-				int days = Days.daysBetween(fromDate, toDate).getDays();
-				isSameAsRepaymentPeriod = (days % 7) == 0;
-				break;
-			case MONTHS:
-				boolean isFromDateOnEndDate = false;
-				if (fromDate.getDayOfMonth() > fromDate.plusDays(1)
-						.getDayOfMonth()) {
-					isFromDateOnEndDate = true;
-				}
-				boolean isToDateOnEndDate = false;
-				if (toDate.getDayOfMonth() > toDate.plusDays(1).getDayOfMonth()) {
-					isToDateOnEndDate = true;
-				}
-
-				if (isFromDateOnEndDate && isToDateOnEndDate) {
-					isSameAsRepaymentPeriod = true;
-				} else {
-
-					int months = getPeriodsBetween(fromDate, toDate);
-					fromDate = fromDate.plusMonths(months);
-					isSameAsRepaymentPeriod = fromDate.isEqual(toDate);
-				}
-
-				break;
-			default:
-				break;
-			}
-		}
-		return isSameAsRepaymentPeriod;
-	}
-
-	private Integer getPeriodsBetween(LocalDate fromDate, LocalDate toDate) {
-		Integer numberOfPeriods = 0;
-		PeriodType periodType = PeriodType.yearMonthDay();
-		Period difference = new Period(fromDate, toDate, periodType);
-		switch (this.repaymentPeriodFrequencyType) {
-		case DAYS:
-			numberOfPeriods = difference.getDays();
-			break;
-		case WEEKS:
-			periodType = PeriodType.weeks();
-			difference = new Period(fromDate, toDate, periodType);
-			numberOfPeriods = difference.getWeeks();
-			break;
-		case MONTHS:
-			numberOfPeriods = difference.getMonths();
-			break;
-		case YEARS:
-			numberOfPeriods = difference.getYears();
-			break;
-		default:
-			break;
-		}
-		return numberOfPeriods;
-	}
-
-	public RecalculationFrequencyType getRecalculationFrequencyType() {
-		return this.recalculationFrequencyType;
-	}
-
-	public void updateNumberOfRepayments(final Integer numberOfRepayments) {
-		this.numberOfRepayments = numberOfRepayments;
-		this.actualNumberOfRepayments = numberOfRepayments
-				+ getLoanTermVariations().adjustNumberOfRepayments();
-
-	}
-
-	public void updatePrincipalGrace(final Integer principalGrace) {
-		this.principalGrace = principalGrace;
-	}
-
-	public void updateInterestPaymentGrace(final Integer interestPaymentGrace) {
-		this.interestPaymentGrace = interestPaymentGrace;
-	}
-
-	public void updateInterestRatePerPeriod(BigDecimal interestRatePerPeriod) {
-		if (interestRatePerPeriod != null) {
-			this.interestRatePerPeriod = interestRatePerPeriod;
-		}
-	}
-
-	public void updateAnnualNominalInterestRate(
-			BigDecimal annualNominalInterestRate) {
-		if (annualNominalInterestRate != null) {
-			this.annualNominalInterestRate = annualNominalInterestRate;
-		}
-	}
-
-	public BigDecimal getAnnualNominalInterestRate() {
-		return this.annualNominalInterestRate;
-	}
-
-	public void updateInterestChargedFromDate(LocalDate interestChargedFromDate) {
-		if (interestChargedFromDate != null) {
-			this.interestChargedFromDate = interestChargedFromDate;
-		}
-	}
-
-	public void updateLoanTermFrequency(Integer loanTermFrequency) {
-		if (loanTermFrequency != null) {
-			this.loanTermFrequency = loanTermFrequency;
-		}
-	}
-
-	public void updateTotalInterestDue(Money totalInterestDue) {
-
-		if (totalInterestDue != null) {
-			this.totalInterestDue = totalInterestDue;
-		}
-	}
-
-	public ApplicationCurrency getApplicationCurrency() {
-		return this.currency;
-	}
-
-	public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
-		return this.interestCalculationPeriodMethod;
-	}
-
-	public LoanPreClosureInterestCalculationStrategy getPreClosureInterestCalculationStrategy() {
-		return this.preClosureInterestCalculationStrategy;
-	}
-
-	public CalendarInstance getCompoundingCalendarInstance() {
-		return this.compoundingCalendarInstance;
-	}
-
-	public RecalculationFrequencyType getCompoundingFrequencyType() {
-		return this.compoundingFrequencyType;
-	}
-
-	public BigDecimal getActualFixedEmiAmount() {
-		return this.actualFixedEmiAmount;
-	}
-
-	public Calendar getLoanCalendar() {
-		return loanCalendar;
-	}
-
-	public BigDecimal getFixedPrincipalAmount() {
-		BigDecimal fixedPrincipalAmount = this.fixedPrincipalAmount;
-		if (getCurrentPeriodFixedPrincipalAmount() != null) {
-			fixedPrincipalAmount = getCurrentPeriodFixedPrincipalAmount();
-		}
-		return fixedPrincipalAmount;
-	}
-
-	public LoanTermVariationsDataWrapper getLoanTermVariations() {
-		return this.variationsDataWrapper;
-	}
-
-	public BigDecimal getCurrentPeriodFixedEmiAmount() {
-		return this.currentPeriodFixedEmiAmount;
-	}
-
-	public void setCurrentPeriodFixedEmiAmount(
-			BigDecimal currentPeriodFixedEmiAmount) {
-		this.currentPeriodFixedEmiAmount = currentPeriodFixedEmiAmount;
-	}
-
-	public BigDecimal getCurrentPeriodFixedPrincipalAmount() {
-		return this.currentPeriodFixedPrincipalAmount;
-	}
-
-	public void setCurrentPeriodFixedPrincipalAmount(
-			BigDecimal currentPeriodFixedPrincipalAmount) {
-		this.currentPeriodFixedPrincipalAmount = currentPeriodFixedPrincipalAmount;
-	}
-
-	public Integer fetchNumberOfRepaymentsAfterExceptions() {
-		return this.actualNumberOfRepayments;
-	}
-
-	public LocalDate getSeedDate() {
-		return this.seedDate;
-	}
-
-	public CalendarHistoryDataWrapper getCalendarHistoryDataWrapper() {
-		return this.calendarHistoryDataWrapper;
-	}
-
-	public Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled() {
-		return this.isInterestChargedFromDateSameAsDisbursalDateEnabled;
-	}
-
-	public Integer getNumberOfdays() {
-		return numberOfDays;
-	}
-
-	public boolean isSkipRepaymentOnFirstDayofMonth() {
-		return isSkipRepaymentOnFirstDayOfMonth;
-	}
+    /**
+     * Legacy method of support 'grace' on the charging of interest on a loan.
+     * 
+     * <p>
+     * For the typical structured loan, its reasonable to use an integer to
+     * indicate the number of 'repayment frequency' periods the 'grace' should
+     * apply to but for slightly <b>irregular</b> loans where the period between
+     * disbursement and the date of the 'first repayment period' isnt doest
+     * match the 'repayment frequency' but can be less (15days instead of 1
+     * month) or more (6 weeks instead of 1 month) - The idea was to use a date
+     * to indicate from whence interest should be charged.
+     * </p>
+     */
+    private LocalDate interestChargedFromDate;
+    private final Money inArrearsTolerance;
+
+    private final Integer graceOnArrearsAgeing;
+
+    // added
+    private LocalDate loanEndDate;
 
+    private final List<DisbursementData> disbursementDatas;
+
+    private final boolean multiDisburseLoan;
+
+    private BigDecimal fixedEmiAmount;
+
+    private BigDecimal fixedPrincipalAmount;
+
+    private BigDecimal currentPeriodFixedEmiAmount;
+
+    private BigDecimal currentPeriodFixedPrincipalAmount;
+
+    private final BigDecimal actualFixedEmiAmount;
+
+    private final BigDecimal maxOutstandingBalance;
+
+    private Money totalInterestDue;
+
+    private final DaysInMonthType daysInMonthType;
+
+    private final DaysInYearType daysInYearType;
+
+    private final boolean interestRecalculationEnabled;
+
+    private final LoanRescheduleStrategyMethod rescheduleStrategyMethod;
+
+    private final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod;
+
+    private final CalendarInstance restCalendarInstance;
+
+    private final RecalculationFrequencyType recalculationFrequencyType;
+
+    private final CalendarInstance compoundingCalendarInstance;
+
+    private final RecalculationFrequencyType compoundingFrequencyType;
+    private final boolean allowCompoundingOnEod;
+
+    private final BigDecimal principalThresholdForLastInstalment;
+    private final Integer installmentAmountInMultiplesOf;
+
+    private final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy;
+
+    private Money approvedPrincipal = null;
+
+    private final LoanTermVariationsDataWrapper variationsDataWrapper;
+
+    private Money adjustPrincipalForFlatLoans;
+
+    private final LocalDate seedDate;
+
+    private final CalendarHistoryDataWrapper calendarHistoryDataWrapper;
+
+    private final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled;
+
+    private final Integer numberOfDays;
+
+    private final boolean isSkipRepaymentOnFirstDayOfMonth;
+
+    private final HolidayDetailDTO holidayDetailDTO;
+
+    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,
+            final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
+            final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate,
+            final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion,
+            final Money principalMoney, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
+            final LocalDate calculatedRepaymentsStartingFromDate, final Integer graceOnPrincipalPayment,
+            final Integer recurringMoratoriumOnPrincipalPeriods, final Integer graceOnInterestPayment,
+            final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final Money inArrearsTolerance,
+            final boolean multiDisburseLoan, final BigDecimal emiAmount, final List<DisbursementData> disbursementDatas,
+            final BigDecimal maxOutstandingBalance, final Integer graceOnArrearsAgeing, final DaysInMonthType daysInMonthType,
+            final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled,
+            final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
+            final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod,
+            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, final Integer numberOfdays,
+            boolean isSkipRepaymentOnFirstDayofMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod) {
+
+        final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
+        final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
+        return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
+                repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod,
+                interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
+                allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
+                calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged,
+                interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance,
+                graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
+                interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
+                compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
+                preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
+                isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfdays, isSkipRepaymentOnFirstDayofMonth, holidayDetailDTO,
+                allowCompoundingOnEod);
+
+    }
+
+    public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
+            final PeriodFrequencyType loanTermPeriodFrequencyType, NthDayType nthDay, DayOfWeekType dayOfWeek,
+            final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
+            final LocalDate calculatedRepaymentsStartingFromDate, final Money inArrearsTolerance,
+            final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount,
+            final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
+            final LocalDate interestChargedFromDate, final BigDecimal principalThresholdForLastInstalment,
+            final Integer installmentAmountInMultiplesOf, final RecalculationFrequencyType recalculationFrequencyType,
+            final CalendarInstance restCalendarInstance, final InterestRecalculationCompoundingMethod compoundingMethod,
+            final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
+            final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
+            final LoanRescheduleStrategyMethod rescheduleStrategyMethod, BigDecimal approvedAmount, BigDecimal annualNominalInterestRate,
+            List<LoanTermVariationsData> loanTermVariations, final Integer numberOfdays, final boolean isSkipRepaymentOnFirstDayofMonth,
+            final Calendar loanCalendar, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod) {
+        final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
+
+        return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
+                expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, inArrearsTolerance,
+                loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, interestChargedFromDate,
+                principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType, restCalendarInstance,
+                compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
+                rescheduleStrategyMethod, loanCalendar, approvedAmount, annualNominalInterestRate, loanTermVariations,
+                calendarHistoryDataWrapper, numberOfdays, isSkipRepaymentOnFirstDayofMonth, holidayDetailDTO, allowCompoundingOnEod);
+    }
+
+    public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
+            final PeriodFrequencyType loanTermPeriodFrequencyType, NthDayType nthDay, DayOfWeekType dayOfWeek,
+            final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
+            final LocalDate calculatedRepaymentsStartingFromDate, final Money inArrearsTolerance,
+            final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount,
+            final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
+            final LocalDate interestChargedFromDate, final BigDecimal principalThresholdForLastInstalment,
+            final Integer installmentAmountInMultiplesOf, final RecalculationFrequencyType recalculationFrequencyType,
+            final CalendarInstance restCalendarInstance, final InterestRecalculationCompoundingMethod compoundingMethod,
+            final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
+            final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
+            final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar, BigDecimal approvedAmount,
+            BigDecimal annualNominalInterestRate, final List<LoanTermVariationsData> loanTermVariations,
+            final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final Integer numberOfdays,
+            final boolean isSkipRepaymentOnFirstDayofMonth, final HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod) {
+
+        final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
+        final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
+        final PeriodFrequencyType repaymentPeriodFrequencyType = loanProductRelatedDetail.getRepaymentPeriodFrequencyType();
+        final AmortizationMethod amortizationMethod = loanProductRelatedDetail.getAmortizationMethod();
+        final InterestMethod interestMethod = loanProductRelatedDetail.getInterestMethod();
+        final BigDecimal interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod();
+        final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType();
+        final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
+                .getInterestCalculationPeriodMethod();
+        final boolean allowPartialPeriodInterestCalcualtion = loanProductRelatedDetail.isAllowPartialPeriodInterestCalcualtion();
+        final Money principalMoney = loanProductRelatedDetail.getPrincipal();
+
+        //
+        final Integer graceOnPrincipalPayment = loanProductRelatedDetail.graceOnPrincipalPayment();
+        final Integer recurringMoratoriumOnPrincipalPeriods = loanProductRelatedDetail.recurringMoratoriumOnPrincipalPeriods();
+        final Integer graceOnInterestPayment = loanProductRelatedDetail.graceOnInterestPayment();
+        final Integer graceOnInterestCharged = loanProductRelatedDetail.graceOnInterestCharged();
+
+        // Interest recalculation settings
+        final DaysInMonthType daysInMonthType = loanProductRelatedDetail.fetchDaysInMonthType();
+        final DaysInYearType daysInYearType = loanProductRelatedDetail.fetchDaysInYearType();
+        final boolean isInterestRecalculationEnabled = loanProductRelatedDetail.isInterestRecalculationEnabled();
+        final boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = false;
+        return new LoanApplicatio

<TRUNCATED>


[07/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 a525606..84c53b1 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
@@ -30,6 +30,7 @@ import java.util.StringTokenizer;
 import net.fortuna.ical4j.model.Date;
 import net.fortuna.ical4j.model.DateList;
 import net.fortuna.ical4j.model.DateTime;
+import net.fortuna.ical4j.model.NumberList;
 import net.fortuna.ical4j.model.Recur;
 import net.fortuna.ical4j.model.ValidationException;
 import net.fortuna.ical4j.model.WeekDay;
@@ -37,18 +38,23 @@ import net.fortuna.ical4j.model.WeekDayList;
 import net.fortuna.ical4j.model.parameter.Value;
 import net.fortuna.ical4j.model.property.RRule;
 
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
 import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
 import org.apache.fineract.portfolio.calendar.domain.Calendar;
 import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
 import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
+import org.apache.fineract.portfolio.common.domain.NthDayType;
 import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.joda.time.LocalDate;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 
+import com.google.gson.JsonElement;
+
 public class CalendarUtils {
 
     static {
@@ -260,10 +266,48 @@ public class CalendarUtils {
             }
 
         } else if (recur.getFrequency().equals(Recur.MONTHLY)) {
-            if (recur.getInterval() == 1) {
+            NumberList nthDays = recur.getSetPosList();
+            Integer nthDay = null;
+            if (!nthDays.isEmpty())
+                nthDay = (Integer) nthDays.get(0);
+            NumberList monthDays = recur.getMonthDayList();
+            Integer monthDay = null;
+            if (!monthDays.isEmpty())
+                monthDay = (Integer) monthDays.get(0);
+            WeekDayList weekdays = recur.getDayList();
+            WeekDay weekDay = null;
+            if (!weekdays.isEmpty()) 
+                weekDay = (WeekDay) weekdays.get(0);
+            if (nthDay != null && weekDay != null) {
+                NthDayType nthDayType = NthDayType.fromInt(nthDay);
+                NthDayNameEnum nthDayName = NthDayNameEnum.from(nthDayType.toString());
+                DayNameEnum weekdayType = DayNameEnum.from(weekDay.getDay());
+                if (recur.getInterval() == 1 || recur.getInterval() == -1) {
+                    humanReadable = "Monthly on " + nthDayName.getCode().toLowerCase() + " " + weekdayType.getCode().toLowerCase();
+                } else {
+                    humanReadable = "Every " + recur.getInterval() + " months on " + nthDayName.getCode().toLowerCase() + " "
+                            + weekdayType.getCode().toLowerCase();
+                }
+            } else if (monthDay != null) {
+                if (monthDay == -1) {
+                    if (recur.getInterval() == 1 || recur.getInterval() == -1) {
+                        humanReadable = "Monthly on last day";
+                    } else {
+                        humanReadable = "Every " + recur.getInterval() + " months on last day";
+                    }
+                } else {
+                    if (recur.getInterval() == 1 || recur.getInterval() == -1) {
+                        humanReadable = "Monthly on day " + monthDay;
+                    } else {
+                        humanReadable = "Every " + recur.getInterval() + " months on day " + monthDay;
+                    }
+                }
+            } else {
+                if (recur.getInterval() == 1 || recur.getInterval() == -1) {
                 humanReadable = "Monthly on day " + startDate.getDayOfMonth();
             } else {
                 humanReadable = "Every " + recur.getInterval() + " months on day " + startDate.getDayOfMonth();
+                }
             }
         } else if (recur.getFrequency().equals(Recur.YEARLY)) {
             if (recur.getInterval() == 1) {
@@ -347,6 +391,28 @@ public class CalendarUtils {
             return DayNameEnum.MO;// Default it to Monday
         }
     }
+    public static enum NthDayNameEnum {
+        ONE(1, "First"), TWO(2, "Second"), THREE(3, "Third"), FOUR(4, "Fourth"), FIVE(5, "Fifth"), LAST(-1, "Last"), INVALID(0, "Invalid");
+        private final String code;
+        private final Integer value;
+
+        private NthDayNameEnum(final Integer value, final String code) {
+            this.value = value;
+            this.code = code;
+        }
+        public String getCode() {
+            return this.code;
+        }
+        public int getValue() {
+            return this.value;
+        }
+        public static NthDayNameEnum from(final String name) {
+            for (final NthDayNameEnum nthDayName : NthDayNameEnum.values()) {
+                if (nthDayName.toString().equals(name)) { return nthDayName; }
+            }
+            return NthDayNameEnum.INVALID;
+        }
+    }
 
     public static PeriodFrequencyType getMeetingPeriodFrequencyType(final String recurringRule) {
         final Recur recur = CalendarUtils.getICalRecur(recurringRule);
@@ -399,6 +465,18 @@ public class CalendarUtils {
         WeekDay weekDay = (WeekDay) weekDays.get(0);
         return CalendarWeekDaysType.fromString(weekDay.getDay());
     }
+    public static NthDayType getRepeatsOnNthDayOfMonth(final String recurringRule) {
+        final Recur recur = CalendarUtils.getICalRecur(recurringRule);
+        NumberList monthDays = null;
+        if(recur.getDayList().isEmpty())
+        	monthDays = recur.getMonthDayList();
+        else
+        	monthDays = recur.getSetPosList();
+        if (monthDays.isEmpty()) return NthDayType.INVALID;
+        if (!recur.getMonthDayList().isEmpty() && recur.getSetPosList().isEmpty()) return NthDayType.ONDAY;
+        Integer monthDay = (Integer) monthDays.get(0);
+        return NthDayType.fromInt(monthDay);
+    }
 
     public static LocalDate getFirstRepaymentMeetingDate(final Calendar calendar, final LocalDate disbursementDate,
             final Integer loanRepaymentInterval, final String frequency, boolean isSkipRepaymentOnFirstDayOfMonth,
@@ -589,4 +667,37 @@ public class CalendarUtils {
 
         return scheduleDate;
     }
+    public static void validateNthDayOfMonthFrequency(DataValidatorBuilder baseDataValidator, final String repeatsOnNthDayOfMonthParamName,
+            final String repeatsOnDayParamName, final JsonElement element, final FromJsonHelper fromApiJsonHelper) {
+        final Integer repeatsOnNthDayOfMonth = fromApiJsonHelper.extractIntegerSansLocaleNamed(repeatsOnNthDayOfMonthParamName, element);
+        baseDataValidator.reset().parameter(repeatsOnNthDayOfMonthParamName).value(repeatsOnNthDayOfMonth).ignoreIfNull()
+                .isOneOfTheseValues(NthDayType.ONE.getValue(), NthDayType.TWO.getValue(), NthDayType.THREE.getValue(),
+                        NthDayType.FOUR.getValue(), NthDayType.LAST.getValue(), NthDayType.ONDAY.getValue());
+        final Integer repeatsOnDay = fromApiJsonHelper.extractIntegerSansLocaleNamed(repeatsOnDayParamName, element);
+        baseDataValidator.reset().parameter(repeatsOnDayParamName).value(repeatsOnDay).ignoreIfNull()
+                .inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
+        NthDayType nthDayType = null;
+        if (repeatsOnNthDayOfMonth != null) {
+            nthDayType = NthDayType.fromInt(repeatsOnNthDayOfMonth);
+        }
+        if (nthDayType != null && nthDayType != NthDayType.INVALID) {
+            if (nthDayType == NthDayType.ONE || nthDayType == NthDayType.TWO || nthDayType == NthDayType.THREE
+                    || nthDayType == NthDayType.FOUR) {
+                baseDataValidator.reset().parameter(repeatsOnDayParamName).value(repeatsOnDay).cantBeBlankWhenParameterProvidedIs(
+                        repeatsOnNthDayOfMonthParamName, NthDayNameEnum.from(nthDayType.toString()).getCode().toLowerCase());
+            }
+        }
+    }
+    public static Integer getMonthOnDay(String recurringRule) {
+        final Recur recur = CalendarUtils.getICalRecur(recurringRule);
+        NumberList monthDayList = null;
+        Integer monthOnDay = null;
+        if (getMeetingPeriodFrequencyType(recur).isMonthly()) {
+            monthDayList = recur.getMonthDayList();
+            if (!monthDayList.isEmpty()) {
+                monthOnDay = (Integer) monthDayList.get(0);
+            }
+        }
+        return monthOnDay;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarWritePlatformServiceJpaRepositoryImpl.java
index c987bd7..be01e2b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarWritePlatformServiceJpaRepositoryImpl.java
@@ -33,7 +33,6 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
-import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
 import org.apache.fineract.portfolio.calendar.domain.Calendar;
 import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
@@ -291,8 +290,10 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
             if (reschedulebasedOnMeetingDates == null){
             presentMeetingDate = command.localDateValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue());
             }
-            final Date endDate = presentMeetingDate.minusDays(1).toDate();
-            calendarHistory.updateEndDate(endDate);
+            if (null != newMeetingDate) {
+                final Date endDate = presentMeetingDate.minusDays(1).toDate();
+                calendarHistory.updateEndDate(endDate);
+            }
             this.calendarHistoryRepository.save(calendarHistory);
             Set<CalendarHistory> history = calendarForUpdate.getCalendarHistory();
             history.add(calendarHistory);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/NthDayType.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/NthDayType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/NthDayType.java
index d32b218..7abb445 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/NthDayType.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/common/domain/NthDayType.java
@@ -25,6 +25,8 @@ public enum NthDayType {
 	THREE(3,"nthDayType.three"),
 	FOUR(4,"nthDayType.four"),
 	FIVE(5,"nthDayType.five"),
+	LAST(-1,"nthDayType.last"),
+	ONDAY(-2,"nthDayType.onday"),
 	INVALID(0,"nthDayType.invalid");
 	
 	private final Integer value;
@@ -62,6 +64,12 @@ public enum NthDayType {
                 case 5:
                     repaymentFrequencyNthDayType = NthDayType.FIVE;
                 break;
+                case -1:
+                    repaymentFrequencyNthDayType = NthDayType.LAST;
+                break;
+                case -2:
+                    repaymentFrequencyNthDayType = NthDayType.ONDAY;
+                break;
                 default:
                 break;
             }
@@ -69,4 +77,13 @@ public enum NthDayType {
         return repaymentFrequencyNthDayType;
     }
    
+    public boolean isInvalid() {
+        return this.value.equals(NthDayType.INVALID.value);
+    }
+    public boolean isLastDay() {
+        return this.value.equals(NthDayType.LAST.value);
+    }
+    public boolean isOnDay() {
+        return this.value.equals(NthDayType.ONDAY.value);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 c44b8e4..fc503b7 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
@@ -52,6 +52,7 @@ 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.calendar.service.CalendarUtils;
 import org.apache.fineract.portfolio.client.data.ClientData;
 import org.apache.fineract.portfolio.client.domain.ClientEnumerations;
 import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
@@ -271,10 +272,12 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
             final LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
             final String recurrence = rs.getString("recurrence");
             final LocalTime meetingTime = JdbcSupport.getLocalTime(rs,"meetingTime");
+            Integer monthOnDay = CalendarUtils.getMonthOnDay(recurrence);
 
             CalendarData calendarData = CalendarData.instance(calendarId, calendarInstanceId, entityId, entityType, title, description,
                     location, startDate, endDate, null, null, false, recurrence, null, null, null, null, null, null, null, null, null,
-                    null, null, null, null,meetingTime);
+                    null, null, null, null, null, meetingTime, monthOnDay);
+
             return CenterData.instance(id, accountNo, name, externalId, status, activationDate, officeId, null, staffId, staffName, hierarchy, null,
                     calendarData);
         }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
index 61ea803..41d6c0b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
@@ -40,12 +40,49 @@ public interface LoanApiConstants {
     public static final String rejectedOnDateParameterName = "rejectedOnDate";
     public static final String withdrawnOnDateParameterName = "withdrawnOnDate";
 
-    // Interest recalculation related
-    public static final String isInterestRecalculationEnabledParameterName = "isInterestRecalculationEnabled";
+    public static final String transactionProcessingStrategyIdParameterName = "transactionProcessingStrategyId";
+    public static final String loanPurposeIdParameterName = "loanPurposeId";
+    public static final String loanOfficerIdParameterName = "loanOfficerId";
+    public static final String fundIdParameterName = "fundId";
+    public static final String externalIdParameterName = "externalId";
+    public static final String accountNoParameterName = "accountNo";
+    public static final String productIdParameterName = "productId";
+    public static final String calendarIdParameterName = "calendarId";
+    public static final String loanTypeParameterName = "loanType";
+    public static final String groupIdParameterName = "groupId";
+    public static final String clientIdParameterName = "clientId";
+    public static final String idParameterName = "id";
+    public static final String graceOnInterestChargedParameterName = "graceOnInterestCharged";
+    public static final String graceOnInterestPaymentParameterName = "graceOnInterestPayment";
+    public static final String graceOnPrincipalPaymentParameterName = "graceOnPrincipalPayment";
+    public static final String repaymentsStartingFromDateParameterName = "repaymentsStartingFromDate";
+    public static final String interestRateFrequencyTypeParameterName = "interestRateFrequencyType";
+    public static final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
+    public static final String interestTypeParameterName = "interestType";
+    public static final String amortizationTypeParameterName = "amortizationType";
+    public static final String repaymentFrequencyTypeParameterName = "repaymentFrequencyType";
+    public static final String loanTermFrequencyTypeParameterName = "loanTermFrequencyType";
+    public static final String loanTermFrequencyParameterName = "loanTermFrequency";
+    public static final String numberOfRepaymentsParameterName = "numberOfRepayments";
+    public static final String repaymentEveryParameterName = "repaymentEvery";
+    public static final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
+    public static final String inArrearsToleranceParameterName = "inArrearsTolerance";
+    public static final String interestChargedFromDateParameterName = "interestChargedFromDate";
+    public static final String submittedOnDateParameterName = "submittedOnDate";
+    public static final String submittedOnNoteParameterName = "interestChargedFromDate";
+    public static final String collateralParameterName = "collateral";
+    public static final String syncDisbursementWithMeetingParameterName = "syncDisbursementWithMeeting";
+    public static final String linkAccountIdParameterName = "linkAccountId";
+    public static final String createStandingInstructionAtDisbursementParameterName = "createStandingInstructionAtDisbursement";
     public static final String daysInYearTypeParameterName = "daysInYearType";
     public static final String daysInMonthTypeParameterName = "daysInMonthType";
+
+    // Interest recalculation related
+    public static final String isInterestRecalculationEnabledParameterName = "isInterestRecalculationEnabled";
     public static final String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod";
     public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
+    public static final String repaymentFrequencyNthDayTypeParameterName = "repaymentFrequencyNthDayType";
+    public static final String repaymentFrequencyDayOfWeekTypeParameterName = "repaymentFrequencyDayOfWeekType";
 
     // Floating interest rate related
     public static final String interestRateDifferentialParameterName = "interestRateDifferential";

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index 929a5ae..5e71e03 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -372,6 +372,17 @@ public class LoansApiResource {
             loanBasicDetails = LoanAccountData.withInterestRecalculationCalendarData(loanBasicDetails, calendarData,
                     compoundingCalendarData);
         }
+        if (loanBasicDetails.isMonthlyRepaymentFrequencyType()) {
+        	Collection<CalendarData> loanCalendarDatas = this.calendarReadPlatformService
+                    .retrieveCalendarsByEntity(loanId,
+                            CalendarEntityType.LOANS.getValue(), null);
+            CalendarData calendarData = null;
+            if (!CollectionUtils.isEmpty(loanCalendarDatas)) {
+                calendarData = loanCalendarDatas.iterator().next();
+            }
+            if(calendarData != null)
+            	loanBasicDetails = LoanAccountData.withLoanCalendarData(loanBasicDetails, calendarData);
+        }
 
         Collection<InterestRatePeriodData> interestRatesPeriods = this.loanReadPlatformService.retrieveLoanInterestRatePeriodData(loanId);
 
@@ -484,6 +495,8 @@ public class LoansApiResource {
         LoanProductData product = null;
         Collection<EnumOptionData> loanTermFrequencyTypeOptions = null;
         Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
+        Collection<EnumOptionData> repaymentFrequencyNthDayTypeOptions = null;
+        Collection<EnumOptionData> repaymentFrequencyDayOfWeekTypeOptions = null;
         Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = null;
         Collection<EnumOptionData> interestRateFrequencyTypeOptions = null;
         Collection<EnumOptionData> amortizationTypeOptions = null;
@@ -506,6 +519,8 @@ public class LoansApiResource {
             loanBasicDetails.setProduct(product);
             loanTermFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveLoanTermFrequencyTypeOptions();
             repaymentFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions();
+            repaymentFrequencyNthDayTypeOptions = this.dropdownReadPlatformService.retrieveRepaymentFrequencyOptionsForNthDayOfMonth();
+            repaymentFrequencyDayOfWeekTypeOptions = this.dropdownReadPlatformService.retrieveRepaymentFrequencyOptionsForDaysOfWeek();
             interestRateFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions();
 
             amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
@@ -559,9 +574,10 @@ public class LoansApiResource {
 
         final LoanAccountData loanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments,
                 charges, collateral, guarantors, meeting, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
-                null, null, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
-                interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
-                loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
+                repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, 
+                interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, 
+                fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions, loanCollateralOptions, 
+                calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
                 overdueCharges, paidInAdvanceTemplate, interestRatesPeriods);
 
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
index cc7fc87..5975ec3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
@@ -34,6 +34,7 @@ import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
 import org.apache.fineract.portfolio.calendar.data.CalendarData;
 import org.apache.fineract.portfolio.charge.data.ChargeData;
 import org.apache.fineract.portfolio.collateral.data.CollateralData;
+import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
 import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
 import org.apache.fineract.portfolio.fund.data.FundData;
 import org.apache.fineract.portfolio.group.data.GroupGeneralData;
@@ -1143,6 +1144,33 @@ public class LoanAccountData {
                 acc.isVariableInstallmentsAllowed, acc.minimumGap, acc.maximumGap);
     }
 
+    public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
+        return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
+                acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
+                acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
+                acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
+                acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
+                acc.repaymentFrequencyType, calendarData.getRepeatsOnNthDayOfMonth(), calendarData.getRepeatsOnDay(),
+                acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
+                acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
+                acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
+                acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
+                acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, acc.graceOnInterestCharged,
+                acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule,
+                acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, acc.productOptions,
+                acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions,
+                acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions,
+                acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions,
+                acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions,
+                acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter,
+                acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails,
+                acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
+                acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
+                acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
+                acc.originalSchedule, acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods,
+                acc.isVariableInstallmentsAllowed, acc.minimumGap, acc.maximumGap);
+    }
+
     public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
 
         return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
@@ -1518,4 +1546,8 @@ public class LoanAccountData {
         return BigDecimal.ZERO;
     }
 
+    public boolean isMonthlyRepaymentFrequencyType() {
+        return (this.repaymentFrequencyType.getId().intValue() == PeriodFrequencyType.MONTHS.getValue());
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanInterestRecalculationData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanInterestRecalculationData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanInterestRecalculationData.java
index 4b432e6..3cc4541 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanInterestRecalculationData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanInterestRecalculationData.java
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.loanaccount.data;
 
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
 import org.apache.fineract.portfolio.calendar.data.CalendarData;
-import org.joda.time.LocalDate;
 
 public class LoanInterestRecalculationData {
 
@@ -32,19 +31,29 @@ public class LoanInterestRecalculationData {
     private final CalendarData calendarData;
     private final EnumOptionData recalculationRestFrequencyType;
     private final Integer recalculationRestFrequencyInterval;
-    private final LocalDate recalculationRestFrequencyDate;
+    /* private final LocalDate recalculationRestFrequencyDate; */
+    private final EnumOptionData recalculationRestFrequencyNthDay;
+    private final EnumOptionData recalculationRestFrequencyWeekday;
+    private final Integer recalculationRestFrequencyOnDay;
     private final EnumOptionData recalculationCompoundingFrequencyType;
     private final Integer recalculationCompoundingFrequencyInterval;
-    private final LocalDate recalculationCompoundingFrequencyDate;
+    /* private final LocalDate recalculationCompoundingFrequencyDate; */
+    private final EnumOptionData recalculationCompoundingFrequencyNthDay;
+    private final EnumOptionData recalculationCompoundingFrequencyWeekday;
+    private final Integer recalculationCompoundingFrequencyOnDay;
+    private final Boolean isCompoundingToBePostedAsTransaction;
     @SuppressWarnings("unused")
     private final CalendarData compoundingCalendarData;
+    private final Boolean allowCompoundingOnEod;
 
     public LoanInterestRecalculationData(final Long id, final Long loanId, final EnumOptionData interestRecalculationCompoundingType,
             final EnumOptionData rescheduleStrategyType, final CalendarData calendarData,
             final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval,
-            final LocalDate recalculationRestFrequencyDate, final CalendarData compoundingCalendarData,
+            final EnumOptionData recalculationRestFrequencyNthDay, final EnumOptionData recalculationRestFrequencyWeekday,
+            final Integer recalculationRestFrequencyOnDay, final CalendarData compoundingCalendarData,
             final EnumOptionData recalculationCompoundingFrequencyType, final Integer recalculationCompoundingFrequencyInterval,
-            final LocalDate recalculationCompoundingFrequencyDate) {
+            final EnumOptionData recalculationCompoundingFrequencyNthDay, final EnumOptionData recalculationCompoundingFrequencyWeekday,
+            final Integer recalculationCompoundingFrequencyOnDay, final Boolean isCompoundingToBePostedAsTransaction, final Boolean allowCompoundingOnEod) {
         this.id = id;
         this.loanId = loanId;
         this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
@@ -52,11 +61,17 @@ public class LoanInterestRecalculationData {
         this.calendarData = calendarData;
         this.recalculationRestFrequencyType = recalculationRestFrequencyType;
         this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
-        this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
+        this.recalculationRestFrequencyNthDay = recalculationRestFrequencyNthDay;
+        this.recalculationRestFrequencyWeekday = recalculationRestFrequencyWeekday;
+        this.recalculationRestFrequencyOnDay = recalculationRestFrequencyOnDay;
         this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
         this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
-        this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
+        this.recalculationCompoundingFrequencyNthDay = recalculationCompoundingFrequencyNthDay;
+        this.recalculationCompoundingFrequencyWeekday = recalculationCompoundingFrequencyWeekday;
+        this.recalculationCompoundingFrequencyOnDay = recalculationCompoundingFrequencyOnDay;
         this.compoundingCalendarData = compoundingCalendarData;
+        this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
+        this.allowCompoundingOnEod = allowCompoundingOnEod;
     }
 
     public static LoanInterestRecalculationData withCalendarData(final LoanInterestRecalculationData recalculationData,
@@ -64,9 +79,12 @@ public class LoanInterestRecalculationData {
         return new LoanInterestRecalculationData(recalculationData.id, recalculationData.loanId,
                 recalculationData.interestRecalculationCompoundingType, recalculationData.rescheduleStrategyType, calendarData,
                 recalculationData.recalculationRestFrequencyType, recalculationData.recalculationRestFrequencyInterval,
-                recalculationData.recalculationRestFrequencyDate, compoundingCalendarData,
+                recalculationData.recalculationRestFrequencyNthDay, recalculationData.recalculationRestFrequencyWeekday,
+                recalculationData.recalculationRestFrequencyOnDay, compoundingCalendarData,
                 recalculationData.recalculationCompoundingFrequencyType, recalculationData.recalculationCompoundingFrequencyInterval,
-                recalculationData.recalculationCompoundingFrequencyDate);
+                recalculationData.recalculationCompoundingFrequencyNthDay, recalculationData.recalculationCompoundingFrequencyWeekday,
+                recalculationData.recalculationCompoundingFrequencyOnDay, recalculationData.isCompoundingToBePostedAsTransaction, 
+                recalculationData.allowCompoundingOnEod);
     }
 
     public Long getId() {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 13fd9ce..822b575 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
@@ -24,6 +24,7 @@ import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -76,6 +77,7 @@ import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
 import org.apache.fineract.portfolio.calendar.domain.Calendar;
 import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
 import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
+import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
 import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 import org.apache.fineract.portfolio.charge.domain.Charge;
 import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
@@ -115,7 +117,6 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplica
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
-import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
 import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
 import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
 import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
@@ -192,12 +193,6 @@ public class Loan extends AbstractPersistable<Long> {
     @Embedded
     private LoanProductRelatedDetail loanRepaymentScheduleDetail;
 
-    @Column(name = "repayment_frequency_nth_day_enum", nullable = true)
-    private Integer repaymentFrequencyNthDayType;
-
-    @Column(name = "repayment_frequency_day_of_week_enum", nullable = true)
-    private Integer repaymentFrequencyDayOfWeekType;
-
     @Column(name = "term_frequency", nullable = false)
     private Integer termFrequency;
 
@@ -858,7 +853,7 @@ public class Loan extends AbstractPersistable<Long> {
         if (loanCharge.isOverdueInstallmentCharge()) { return loanCharge.getAmountPercentageAppliedTo(); }
         switch (loanCharge.getChargeCalculation()) {
             case PERCENT_OF_AMOUNT:
-                    amount = getDerivedAmountForCharge(loanCharge);
+                amount = getDerivedAmountForCharge(loanCharge);
             break;
             case PERCENT_OF_AMOUNT_AND_INTEREST:
                 final BigDecimal totalInterestCharged = getTotalInterest();
@@ -1135,7 +1130,8 @@ public class Loan extends AbstractPersistable<Long> {
                         scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
                         scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
                         scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
-                        scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent());
+                        scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent(),
+                        scheduledLoanInstallment.getLoanCompoundingDetails());
                 addRepaymentScheduleInstallment(installment);
             }
         }
@@ -1194,6 +1190,13 @@ public class Loan extends AbstractPersistable<Long> {
             }
             installment.updateAccrualPortion(interest, fee, penality);
         }
+        LoanRepaymentScheduleInstallment lastInstallment = this.repaymentScheduleInstallments
+                .get(this.repaymentScheduleInstallments.size() - 1);
+        for (LoanTransaction loanTransaction : accruals) {
+            if (loanTransaction.getTransactionDate().isAfter(lastInstallment.getDueDate()) && !loanTransaction.isReversed()) {
+                loanTransaction.reverse();
+            }
+        }
     }
 
     private void updateAccrualsForNonPeriodicAccruals(final Collection<LoanTransaction> accruals, final AppUser currentUser) {
@@ -1265,12 +1268,6 @@ public class Loan extends AbstractPersistable<Long> {
 
         final String dateFormatAsInput = command.dateFormat();
         final String localeAsInput = command.locale();
-        final LocalDate recalculationRestFrequencyDate = command
-                .localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
-        final LocalDate recalculationCompoundingFrequencyDate = command
-                .localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
-        updateLoanInterestRecalculationSettings(recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate, command,
-                actualChanges);
 
         final String accountNoParamName = "accountNo";
         if (command.isChangeInStringParameterNamed(accountNoParamName, this.accountNumber)) {
@@ -1556,37 +1553,6 @@ public class Loan extends AbstractPersistable<Long> {
     /**
      * Update interest recalculation settings if product configuration changes
      */
-    public void updateLoanInterestRecalculationSettings(final LocalDate recalculationRestFrequencyDate,
-            final LocalDate recalculationCompoundingFrequencyDate, final JsonCommand command, final Map<String, Object> actualChanges) {
-
-        if (isInterestRecalculationEnabledForProduct()) {
-            Date restFrequencyDate = null;
-            if (recalculationRestFrequencyDate != null) {
-                restFrequencyDate = recalculationRestFrequencyDate.toDate();
-            }
-
-            Date compoundingFrequencyDate = null;
-            if (recalculationCompoundingFrequencyDate != null) {
-                compoundingFrequencyDate = recalculationCompoundingFrequencyDate.toDate();
-            }
-            if (this.loanInterestRecalculationDetails == null) {
-                actualChanges.put(LoanProductConstants.isInterestRecalculationEnabledParameterName, true);
-                this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
-                        .getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
-                        .getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
-                        .getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
-                        .getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
-                        .getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
-                        .getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
-                this.loanInterestRecalculationDetails.updateLoan(this);
-            } else {
-
-                this.loanInterestRecalculationDetails.update(command, actualChanges);
-            }
-        } else {
-            this.loanInterestRecalculationDetails = null;
-        }
-    }
 
     private void updateOverdueScheduleInstallment(final LoanCharge loanCharge) {
         if (loanCharge.isOverdueInstallmentCharge() && loanCharge.isActive()) {
@@ -1911,8 +1877,7 @@ public class Loan extends AbstractPersistable<Long> {
     public void loanApplicationSubmittal(final AppUser currentUser, final LoanScheduleModel loanSchedule,
             final LoanApplicationTerms loanApplicationTerms, final LoanLifecycleStateMachine lifecycleStateMachine,
             final LocalDate submittedOn, final String externalId, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays,
-            final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay, final LocalDate recalculationRestFrequencyDate,
-            final LocalDate recalculationCompoundingFrequencyDate) {
+            final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) {
 
         updateLoanSchedule(loanSchedule, currentUser);
 
@@ -1933,14 +1898,6 @@ public class Loan extends AbstractPersistable<Long> {
         this.expectedFirstRepaymentOnDate = loanApplicationTerms.getRepaymentStartFromDate();
         this.interestChargedFromDate = loanApplicationTerms.getInterestChargedFromDate();
 
-        if (loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.MONTHS) {
-            this.repaymentFrequencyNthDayType = loanApplicationTerms.getNthDay();
-            this.repaymentFrequencyDayOfWeekType = loanApplicationTerms.getWeekDayType().getValue();
-        } else {
-            this.repaymentFrequencyNthDayType = NthDayType.INVALID.getValue();
-            this.repaymentFrequencyDayOfWeekType = DayOfWeekType.INVALID.getValue();
-        }
-
         updateLoanScheduleDependentDerivedFields();
 
         if (submittedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
@@ -1984,22 +1941,9 @@ public class Loan extends AbstractPersistable<Long> {
          * enabled
          */
         if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
-            Date restFrequencyDate = null;
-            if (recalculationRestFrequencyDate != null) {
-                restFrequencyDate = recalculationRestFrequencyDate.toDate();
-            }
 
-            Date compoundingFrequencyDate = null;
-            if (recalculationCompoundingFrequencyDate != null) {
-                compoundingFrequencyDate = recalculationCompoundingFrequencyDate.toDate();
-            }
             this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
-                    .getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
-                    .getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
-                    .getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
-                    .getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
-                    .getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
-                    .getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
+                    .getProductInterestRecalculationDetails());
             this.loanInterestRecalculationDetails.updateLoan(this);
         }
 
@@ -2299,7 +2243,7 @@ public class Loan extends AbstractPersistable<Long> {
     }
 
     public ChangedTransactionDetail disburse(final AppUser currentUser, final JsonCommand command, final Map<String, Object> actualChanges,
-            final ScheduleGeneratorDTO scheduleGeneratorDTO,final PaymentDetail paymentDetail) {
+            final ScheduleGeneratorDTO scheduleGeneratorDTO, final PaymentDetail paymentDetail) {
 
         final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
                 LoanStatus.fromInt(this.loanStatus));
@@ -2330,7 +2274,7 @@ public class Loan extends AbstractPersistable<Long> {
         updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
         updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
         LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
-        handleDisbursementTransaction(actualDisbursementDate, createdDate, currentUser,paymentDetail);
+        handleDisbursementTransaction(actualDisbursementDate, createdDate, currentUser, paymentDetail);
         updateLoanSummaryDerivedFields();
         final Money interestApplied = Money.of(getCurrency(), this.summary.getTotalInterestCharged());
 
@@ -2380,8 +2324,13 @@ public class Loan extends AbstractPersistable<Long> {
             this.loanTermVariations.add(loanVariationTerms);
         }
 
-        if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged || rescheduledRepaymentDate != null) {
-            regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
+        if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged
+                || rescheduledRepaymentDate != null) {
+            if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
+                regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
+            } else {
+                regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
+            }
         }
     }
 
@@ -2592,7 +2541,7 @@ public class Loan extends AbstractPersistable<Long> {
         updateLoanSchedule(loanSchedule, currentUser);
         Set<LoanCharge> charges = this.charges();
         for (LoanCharge loanCharge : charges) {
-                recalculateLoanCharge(loanCharge, scheduleGeneratorDTO.getPenaltyWaitPeriod());
+            recalculateLoanCharge(loanCharge, scheduleGeneratorDTO.getPenaltyWaitPeriod());
         }
     }
 
@@ -2633,7 +2582,8 @@ public class Loan extends AbstractPersistable<Long> {
         return interestRate;
     }
 
-    private void handleDisbursementTransaction(final LocalDate disbursedOn, final LocalDateTime createdDate, final AppUser currentUser, final PaymentDetail paymentDetail) {
+    private void handleDisbursementTransaction(final LocalDate disbursedOn, final LocalDateTime createdDate, final AppUser currentUser,
+            final PaymentDetail paymentDetail) {
 
         // add repayment transaction to track incoming money from client to mfi
         // for (charges due at time of disbursement)
@@ -2651,14 +2601,14 @@ public class Loan extends AbstractPersistable<Long> {
          **/
 
         Money disbursentMoney = Money.zero(getCurrency());
-        final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, paymentDetail, disbursedOn,
-                null, createdDate, currentUser);
+        final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, paymentDetail,
+                disbursedOn, null, createdDate, currentUser);
         final Integer installmentNumber = null;
         for (final LoanCharge charge : charges()) {
             Date actualDisbursementDate = getActualDisbursementDate(charge);
-            if ((charge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue() 
-            		&& disbursedOn.equals(new LocalDate(actualDisbursementDate)) && actualDisbursementDate != null
-                    && !charge.isWaived() && !charge.isFullyPaid())
+            if ((charge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue()
+                    && disbursedOn.equals(new LocalDate(actualDisbursementDate)) && actualDisbursementDate != null && !charge.isWaived() && !charge
+                        .isFullyPaid())
                     || (charge.getCharge().getChargeTimeType() == ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()
                             && disbursedOn.equals(new LocalDate(actualDisbursementDate)) && actualDisbursementDate != null
                             && !charge.isWaived() && !charge.isFullyPaid())) {
@@ -3088,6 +3038,18 @@ public class Loan extends AbstractPersistable<Long> {
         return installment;
     }
 
+    private List<LoanTransaction> retreiveListOfIncomePostingTransactions() {
+        final List<LoanTransaction> incomePostTransactions = new ArrayList<>();
+        for (final LoanTransaction transaction : this.loanTransactions) {
+            if (transaction.isNotReversed() && transaction.isIncomePosting()) {
+                incomePostTransactions.add(transaction);
+            }
+        }
+        final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
+        Collections.sort(incomePostTransactions, transactionComparator);
+        return incomePostTransactions;
+    }
+
     private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() {
         final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
         for (final LoanTransaction transaction : this.loanTransactions) {
@@ -3104,8 +3066,8 @@ public class Loan extends AbstractPersistable<Long> {
         final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
         for (final LoanTransaction transaction : this.loanTransactions) {
             if (transaction.isNotReversed()
-                    && !(transaction.isDisbursement() || transaction.isAccrual() || transaction.isRepaymentAtDisbursement() || transaction
-                            .isNonMonetaryTransaction())) {
+                    && !(transaction.isDisbursement() || transaction.isAccrual() || transaction.isRepaymentAtDisbursement()
+                            || transaction.isNonMonetaryTransaction() || transaction.isIncomePosting())) {
                 repaymentsOrWaivers.add(transaction);
             }
         }
@@ -3169,6 +3131,71 @@ public class Loan extends AbstractPersistable<Long> {
                     LoanStatus.fromInt(this.loanStatus));
             this.loanStatus = statusEnum.getValue();
         }
+        processIncomeAccrualTransactionOnLoanClosure();
+    }
+
+    private void processIncomeAccrualTransactionOnLoanClosure() {
+        if (this.loanInterestRecalculationDetails != null && this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
+                && this.status().isClosedObligationsMet()) {
+            Date closedDate = this.getClosedOnDate();
+            LocalDate closedLocalDate = new LocalDate(closedDate);
+            reverseTransactionsOnOrAfter(retreiveListOfIncomePostingTransactions(), closedDate);
+            reverseTransactionsOnOrAfter(retreiveListOfAccrualTransactions(), closedDate);
+            HashMap<String, BigDecimal> cumulativeIncomeFromInstallments = new HashMap<>();
+            determineCumulativeIncomeFromInstallments(cumulativeIncomeFromInstallments);
+            HashMap<String, BigDecimal> cumulativeIncomeFromIncomePosting = new HashMap<>();
+            determineCumulativeIncomeDetails(retreiveListOfIncomePostingTransactions(), cumulativeIncomeFromIncomePosting);
+            BigDecimal interestToPost = cumulativeIncomeFromInstallments.get("interest").subtract(
+                    cumulativeIncomeFromIncomePosting.get("interest"));
+            BigDecimal feeToPost = cumulativeIncomeFromInstallments.get("fee").subtract(cumulativeIncomeFromIncomePosting.get("fee"));
+            BigDecimal penaltyToPost = cumulativeIncomeFromInstallments.get("penalty").subtract(
+                    cumulativeIncomeFromIncomePosting.get("penalty"));
+            BigDecimal amountToPost = interestToPost.add(feeToPost).add(penaltyToPost);
+            LoanTransaction finalIncomeTransaction = LoanTransaction.incomePosting(this, this.getOffice(), closedDate, amountToPost,
+                    interestToPost, feeToPost, penaltyToPost, null);
+            this.loanTransactions.add(finalIncomeTransaction);
+            if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
+                List<LoanTransaction> updatedAccrualTransactions = retreiveListOfAccrualTransactions();
+                LocalDate lastAccruedDate = this.getDisbursementDate();
+                if (updatedAccrualTransactions != null && updatedAccrualTransactions.size() > 0) {
+                    lastAccruedDate = updatedAccrualTransactions.get(updatedAccrualTransactions.size() - 1).getTransactionDate();
+                }
+                HashMap<String, Object> feeDetails = new HashMap<>();
+                determineFeeDetails(lastAccruedDate, closedLocalDate, feeDetails);
+                LoanTransaction finalAccrual = LoanTransaction.accrueTransaction(this, this.getOffice(), closedLocalDate, amountToPost,
+                        interestToPost, feeToPost, penaltyToPost, null);
+                updateLoanChargesPaidBy(finalAccrual, feeDetails, null);
+                this.loanTransactions.add(finalAccrual);
+            }
+        }
+    }
+
+    private void determineCumulativeIncomeFromInstallments(HashMap<String, BigDecimal> cumulativeIncomeFromInstallments) {
+        BigDecimal interest = BigDecimal.ZERO;
+        BigDecimal fee = BigDecimal.ZERO;
+        BigDecimal penalty = BigDecimal.ZERO;
+        for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
+            interest = interest.add(installment.getInterestCharged(getCurrency()).getAmount());
+            fee = fee.add(installment.getFeeChargesCharged(getCurrency()).getAmount());
+            penalty = penalty.add(installment.getPenaltyChargesCharged(getCurrency()).getAmount());
+        }
+        cumulativeIncomeFromInstallments.put("interest", interest);
+        cumulativeIncomeFromInstallments.put("fee", fee);
+        cumulativeIncomeFromInstallments.put("penalty", penalty);
+    }
+
+    private void determineCumulativeIncomeDetails(Collection<LoanTransaction> transactions, HashMap<String, BigDecimal> incomeDetailsMap) {
+        BigDecimal interest = BigDecimal.ZERO;
+        BigDecimal fee = BigDecimal.ZERO;
+        BigDecimal penalty = BigDecimal.ZERO;
+        for (LoanTransaction transaction : transactions) {
+            interest = interest.add(transaction.getInterestPortion(getCurrency()).getAmount());
+            fee = fee.add(transaction.getFeeChargesPortion(getCurrency()).getAmount());
+            penalty = penalty.add(transaction.getPenaltyChargesPortion(getCurrency()).getAmount());
+        }
+        incomeDetailsMap.put("interest", interest);
+        incomeDetailsMap.put("fee", fee);
+        incomeDetailsMap.put("penalty", penalty);
     }
 
     private void handleLoanOverpayment(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
@@ -4566,7 +4593,7 @@ public class Loan extends AbstractPersistable<Long> {
     private LocalDate getLastUserTransactionDate() {
         LocalDate currentTransactionDate = getDisbursementDate();
         for (final LoanTransaction previousTransaction : this.loanTransactions) {
-            if (!(previousTransaction.isReversed() || previousTransaction.isAccrual())) {
+            if (!(previousTransaction.isReversed() || previousTransaction.isAccrual() || previousTransaction.isIncomePosting())) {
                 if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
                     currentTransactionDate = previousTransaction.getTransactionDate();
                 }
@@ -4982,6 +5009,179 @@ public class Loan extends AbstractPersistable<Long> {
         }
 
         processPostDisbursementTransactions();
+        processIncomeTransactions(currentUser);
+    }
+
+    private void updateLoanChargesPaidBy(LoanTransaction accrual, HashMap<String, Object> feeDetails,
+            LoanRepaymentScheduleInstallment installment) {
+        @SuppressWarnings("unchecked")
+        List<LoanCharge> loanCharges = (List<LoanCharge>) feeDetails.get("loanCharges");
+        @SuppressWarnings("unchecked")
+        List<LoanInstallmentCharge> loanInstallmentCharges = (List<LoanInstallmentCharge>) feeDetails.get("loanInstallmentCharges");
+        if (loanCharges != null) {
+            for (LoanCharge loanCharge : loanCharges) {
+                Integer installmentNumber = null == installment ? null : installment.getInstallmentNumber();
+                final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(accrual, loanCharge, loanCharge.getAmount(getCurrency())
+                        .getAmount(), installmentNumber);
+                accrual.getLoanChargesPaid().add(loanChargePaidBy);
+            }
+        }
+        if (loanInstallmentCharges != null) {
+            for (LoanInstallmentCharge loanInstallmentCharge : loanInstallmentCharges) {
+                Integer installmentNumber = null == loanInstallmentCharge.getInstallment() ? null : loanInstallmentCharge.getInstallment()
+                        .getInstallmentNumber();
+                final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(accrual, loanInstallmentCharge.getLoancharge(),
+                        loanInstallmentCharge.getAmount(getCurrency()).getAmount(), installmentNumber);
+                accrual.getLoanChargesPaid().add(loanChargePaidBy);
+            }
+        }
+    }
+
+    public void processIncomeTransactions(AppUser currentUser) {
+        if (this.loanInterestRecalculationDetails != null && this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()) {
+            LocalDate lastCompoundingDate = this.getDisbursementDate();
+            List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = extractInterestRecalculationAdditionalDetails();
+            List<LoanTransaction> incomeTransactions = retreiveListOfIncomePostingTransactions();
+            List<LoanTransaction> accrualTransactions = retreiveListOfAccrualTransactions();
+            for (LoanInterestRecalcualtionAdditionalDetails compoundingDetail : compoundingDetails) {
+                if (!compoundingDetail.getEffectiveDate().isBefore(DateUtils.getLocalDateOfTenant())) {
+                    break;
+                }
+                LoanTransaction incomeTransaction = getTransactionForDate(incomeTransactions, compoundingDetail.getEffectiveDate());
+                LoanTransaction accrualTransaction = getTransactionForDate(accrualTransactions, compoundingDetail.getEffectiveDate());
+                addUpdateIncomeAndAccrualTransaction(compoundingDetail, lastCompoundingDate, currentUser, incomeTransaction,
+                        accrualTransaction);
+                lastCompoundingDate = compoundingDetail.getEffectiveDate();
+            }
+        }
+    }
+
+    private void reverseTransactionsOnOrAfter(List<LoanTransaction> transactions, Date date) {
+        LocalDate refDate = new LocalDate(date);
+        for (LoanTransaction loanTransaction : transactions) {
+            if (!loanTransaction.getTransactionDate().isBefore(refDate)) {
+                loanTransaction.reverse();
+            }
+        }
+    }
+
+    private void addUpdateIncomeAndAccrualTransaction(LoanInterestRecalcualtionAdditionalDetails compoundingDetail,
+            LocalDate lastCompoundingDate, AppUser currentUser, LoanTransaction existingIncomeTransaction,
+            LoanTransaction existingAccrualTransaction) {
+        BigDecimal interest = BigDecimal.ZERO;
+        BigDecimal fee = BigDecimal.ZERO;
+        BigDecimal penalties = BigDecimal.ZERO;
+        HashMap<String, Object> feeDetails = new HashMap<>();
+
+        if (this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().equals(
+                InterestRecalculationCompoundingMethod.INTEREST)) {
+            interest = compoundingDetail.getAmount();
+        } else if (this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().equals(
+                InterestRecalculationCompoundingMethod.FEE)) {
+            determineFeeDetails(lastCompoundingDate, compoundingDetail.getEffectiveDate(), feeDetails);
+            fee = (BigDecimal) feeDetails.get("fee");
+            penalties = (BigDecimal) feeDetails.get("penalties");
+        } else if (this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().equals(
+                InterestRecalculationCompoundingMethod.INTEREST_AND_FEE)) {
+            determineFeeDetails(lastCompoundingDate, compoundingDetail.getEffectiveDate(), feeDetails);
+            fee = (BigDecimal) feeDetails.get("fee");
+            penalties = (BigDecimal) feeDetails.get("penalties");
+            interest = compoundingDetail.getAmount().subtract(fee).subtract(penalties);
+        }
+
+        if (existingIncomeTransaction == null) {
+            LoanTransaction transaction = LoanTransaction.incomePosting(this, this.getOffice(), compoundingDetail.getEffectiveDate()
+                    .toDate(), compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
+            this.loanTransactions.add(transaction);
+        } else if (existingIncomeTransaction.getAmount(getCurrency()).getAmount().compareTo(compoundingDetail.getAmount()) != 0) {
+            existingIncomeTransaction.reverse();
+            LoanTransaction transaction = LoanTransaction.incomePosting(this, this.getOffice(), compoundingDetail.getEffectiveDate()
+                    .toDate(), compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
+            this.loanTransactions.add(transaction);
+        }
+
+        if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
+            if (existingAccrualTransaction == null) {
+                LoanTransaction accrual = LoanTransaction.accrueTransaction(this, this.getOffice(), compoundingDetail.getEffectiveDate(),
+                        compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
+                updateLoanChargesPaidBy(accrual, feeDetails, null);
+                this.loanTransactions.add(accrual);
+            } else if (existingAccrualTransaction.getAmount(getCurrency()).getAmount().compareTo(compoundingDetail.getAmount()) != 0) {
+                existingAccrualTransaction.reverse();
+                LoanTransaction accrual = LoanTransaction.accrueTransaction(this, this.getOffice(), compoundingDetail.getEffectiveDate(),
+                        compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
+                updateLoanChargesPaidBy(accrual, feeDetails, null);
+                this.loanTransactions.add(accrual);
+            }
+        }
+        updateLoanOutstandingBalaces();
+    }
+
+    private void determineFeeDetails(LocalDate fromDate, LocalDate toDate, HashMap<String, Object> feeDetails) {
+        BigDecimal fee = BigDecimal.ZERO;
+        BigDecimal penalties = BigDecimal.ZERO;
+
+        List<Integer> installments = new ArrayList<>();
+        for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
+            if (loanRepaymentScheduleInstallment.getDueDate().isAfter(fromDate)
+                    && !loanRepaymentScheduleInstallment.getDueDate().isAfter(toDate)) {
+                installments.add(loanRepaymentScheduleInstallment.getInstallmentNumber());
+            }
+        }
+
+        List<LoanCharge> loanCharges = new ArrayList<>();
+        List<LoanInstallmentCharge> loanInstallmentCharges = new ArrayList<>();
+        for (LoanCharge loanCharge : this.charges()) {
+            if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, toDate)) {
+                if (loanCharge.isPenaltyCharge() && !loanCharge.isInstalmentFee()) {
+                    penalties = penalties.add(loanCharge.amount());
+                    loanCharges.add(loanCharge);
+                } else if (!loanCharge.isInstalmentFee()) {
+                    fee = fee.add(loanCharge.amount());
+                    loanCharges.add(loanCharge);
+                }
+            } else if (loanCharge.isInstalmentFee()) {
+                for (LoanInstallmentCharge installmentCharge : loanCharge.installmentCharges()) {
+                    if (installments.contains(installmentCharge.getRepaymentInstallment().getInstallmentNumber())) {
+                        fee = fee.add(installmentCharge.getAmount());
+                        loanInstallmentCharges.add(installmentCharge);
+                    }
+                }
+            }
+        }
+
+        feeDetails.put("fee", fee);
+        feeDetails.put("penalties", penalties);
+        feeDetails.put("loanCharges", loanCharges);
+        feeDetails.put("loanInstallmentCharges", loanInstallmentCharges);
+    }
+
+    private LoanTransaction getTransactionForDate(List<LoanTransaction> transactions, LocalDate effectiveDate) {
+        for (LoanTransaction loanTransaction : transactions) {
+            if (loanTransaction.getTransactionDate().isEqual(effectiveDate)) { return loanTransaction; }
+        }
+        return null;
+    }
+
+    private List<LoanInterestRecalcualtionAdditionalDetails> extractInterestRecalculationAdditionalDetails() {
+        List<LoanInterestRecalcualtionAdditionalDetails> retDetails = new ArrayList<>();
+        if (null != this.repaymentScheduleInstallments && this.repaymentScheduleInstallments.size() > 0) {
+            Iterator<LoanRepaymentScheduleInstallment> installmentsItr = this.repaymentScheduleInstallments.iterator();
+            while (installmentsItr.hasNext()) {
+                LoanRepaymentScheduleInstallment installment = installmentsItr.next();
+                if (null != installment.getLoanCompoundingDetails()) {
+                    retDetails.addAll(installment.getLoanCompoundingDetails());
+                }
+            }
+        }
+        Collections.sort(retDetails, new Comparator<LoanInterestRecalcualtionAdditionalDetails>() {
+
+            @Override
+            public int compare(LoanInterestRecalcualtionAdditionalDetails first, LoanInterestRecalcualtionAdditionalDetails second) {
+                return first.getEffectiveDate().compareTo(second.getEffectiveDate());
+            }
+        });
+        return retDetails;
     }
 
     public void processPostDisbursementTransactions() {
@@ -5044,21 +5244,27 @@ public class Loan extends AbstractPersistable<Long> {
     public LoanApplicationTerms constructLoanApplicationTerms(final ScheduleGeneratorDTO scheduleGeneratorDTO) {
         final Integer loanTermFrequency = this.termFrequency;
         final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
-        final NthDayType nthDayType = NthDayType.fromInt(this.repaymentFrequencyNthDayType);
-        final DayOfWeekType dayOfWeekType = DayOfWeekType.fromInt(this.repaymentFrequencyDayOfWeekType);
+        NthDayType nthDayType = null;
+        DayOfWeekType dayOfWeekType = null;
         final List<DisbursementData> disbursementData = new ArrayList<>();
         for (LoanDisbursementDetails disbursementDetails : this.disbursementDetails) {
             disbursementData.add(disbursementDetails.toData());
         }
 
+        Calendar calendar = scheduleGeneratorDTO.getCalendar();
+        if (calendar != null) {
+            nthDayType = CalendarUtils.getRepeatsOnNthDayOfMonth(calendar.getRecurrence());
+            dayOfWeekType = DayOfWeekType.fromInt(CalendarUtils.getRepeatsOnDay(calendar.getRecurrence()).getValue());
+        }
+        HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
         CalendarInstance restCalendarInstance = null;
         CalendarInstance compoundingCalendarInstance = null;
         RecalculationFrequencyType recalculationFrequencyType = null;
         InterestRecalculationCompoundingMethod compoundingMethod = null;
         RecalculationFrequencyType compoundingFrequencyType = null;
         LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
-        Calendar calendar = null;
         CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
+        boolean allowCompoundingOnEod = false;
         if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
             restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
             compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
@@ -5066,6 +5272,8 @@ public class Loan extends AbstractPersistable<Long> {
             compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
             compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
             rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
+            allowCompoundingOnEod = this.loanInterestRecalculationDetails.allowCompoundingOnEod();
+            calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
         }
         calendar = scheduleGeneratorDTO.getCalendar();
         calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
@@ -5075,7 +5283,7 @@ public class Loan extends AbstractPersistable<Long> {
         List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
         annualNominalInterestRate = constructLoanTermVariations(floatingRateDTO, annualNominalInterestRate, loanTermVariations);
         LocalDate interestChargedFromDate = getInterestChargedFromDate();
-        if(interestChargedFromDate == null && scheduleGeneratorDTO.isInterestChargedFromDateAsDisbursementDateEnabled()){
+        if (interestChargedFromDate == null && scheduleGeneratorDTO.isInterestChargedFromDateAsDisbursementDateEnabled()) {
             interestChargedFromDate = getDisbursementDate();
         }
 
@@ -5087,7 +5295,7 @@ public class Loan extends AbstractPersistable<Long> {
                 this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
                 compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
                 rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper,
-		scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth());
+		scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), holidayDetailDTO, allowCompoundingOnEod);
         return loanApplicationTerms;
     }
 
@@ -5105,6 +5313,7 @@ public class Loan extends AbstractPersistable<Long> {
         Money penaltyCharges = Money.zero(loanCurrency());
         Money totalPrincipal = Money.zero(loanCurrency());
         Money totalInterest = Money.zero(loanCurrency());
+        final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
         for (final LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) {
             totalPrincipal = totalPrincipal.plus(scheduledRepayment.getPrincipalOutstanding(loanCurrency()));
             totalInterest = totalInterest.plus(scheduledRepayment.getInterestOutstanding(loanCurrency()));
@@ -5112,7 +5321,7 @@ public class Loan extends AbstractPersistable<Long> {
             penaltyCharges = penaltyCharges.plus(scheduledRepayment.getPenaltyChargesOutstanding(loanCurrency()));
         }
         return new LoanRepaymentScheduleInstallment(null, 0, LocalDate.now(), LocalDate.now(), totalPrincipal.getAmount(),
-                totalInterest.getAmount(), feeCharges.getAmount(), penaltyCharges.getAmount(), false);
+                totalInterest.getAmount(), feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
     }
 
     public List<LoanRepaymentScheduleInstallment> fetchRepaymentScheduleInstallments() {
@@ -5141,11 +5350,17 @@ public class Loan extends AbstractPersistable<Long> {
         Money outstanding = Money.zero(getCurrency());
         List<LoanTransaction> loanTransactions = retreiveListOfTransactionsExcludeAccruals();
         for (LoanTransaction loanTransaction : loanTransactions) {
-            if (loanTransaction.isDisbursement()) {
+            if (loanTransaction.isDisbursement() || loanTransaction.isIncomePosting()) {
                 outstanding = outstanding.plus(loanTransaction.getAmount(getCurrency()));
                 loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount());
             } else {
-                outstanding = outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency()));
+                if (this.loanInterestRecalculationDetails != null
+                        && this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
+                        && !loanTransaction.isRepaymentAtDisbursement()) {
+                    outstanding = outstanding.minus(loanTransaction.getAmount(getCurrency()));
+                } else {
+                    outstanding = outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency()));
+                }
                 loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount());
             }
         }
@@ -5252,7 +5467,8 @@ 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 boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) {
+            final FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays, 
+            final HolidayDetailDTO holidayDetailDTO) {
         LoanProduct loanProduct = loanProduct();
         // LoanProductRelatedDetail loanProductRelatedDetail =
         // getLoanRepaymentScheduleDetail();
@@ -5260,8 +5476,15 @@ public class Loan extends AbstractPersistable<Long> {
 
         final Integer loanTermFrequency = getTermFrequency();
         final PeriodFrequencyType loanTermPeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
-        final NthDayType nthDayType = NthDayType.fromInt(this.repaymentFrequencyNthDayType);
-        final DayOfWeekType dayOfWeekType = DayOfWeekType.fromInt(this.repaymentFrequencyDayOfWeekType);
+        NthDayType nthDayType = null;
+        DayOfWeekType dayOfWeekType = null;
+        if (loanCalendar != null) {
+            nthDayType = CalendarUtils.getRepeatsOnNthDayOfMonth(loanCalendar.getRecurrence());
+            CalendarWeekDaysType getRepeatsOnDay = CalendarUtils.getRepeatsOnDay(loanCalendar.getRecurrence());
+            Integer getRepeatsOnDayValue = null;
+            if (getRepeatsOnDay != null) getRepeatsOnDayValue = getRepeatsOnDay.getValue();
+            if (getRepeatsOnDayValue != null) dayOfWeekType = DayOfWeekType.fromInt(getRepeatsOnDayValue);
+        }
 
         final Integer numberOfRepayments = this.loanRepaymentScheduleDetail.getNumberOfRepayments();
         final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery();
@@ -5304,7 +5527,7 @@ public class Loan extends AbstractPersistable<Long> {
         final BigDecimal maxOutstandingBalance = getMaxOutstandingLoanBalance();
 
         final List<DisbursementData> disbursementData = getDisbursmentData();
-        
+
         CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
         if (loanCalendar != null) {
             Set<CalendarHistory> calendarHistory = loanCalendar.getCalendarHistory();
@@ -5315,11 +5538,13 @@ public class Loan extends AbstractPersistable<Long> {
         InterestRecalculationCompoundingMethod compoundingMethod = null;
         RecalculationFrequencyType compoundingFrequencyType = null;
         LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
+        boolean allowCompoundingOnEod = false;
         if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
             recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
             compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
             compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
             rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
+            allowCompoundingOnEod = this.loanInterestRecalculationDetails.allowCompoundingOnEod();
         }
 
         List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
@@ -5332,7 +5557,7 @@ public class Loan extends AbstractPersistable<Long> {
                 this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
                 compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
                 rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, 
-                calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst);
+                calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod);
     }
 
     /**
@@ -5376,22 +5601,6 @@ public class Loan extends AbstractPersistable<Long> {
         return isEnabled;
     }
 
-    public Integer getRepaymentFrequencyNthDayType() {
-        return this.repaymentFrequencyNthDayType;
-    }
-
-    public void setRepaymentFrequencyNthDayType(Integer repaymentFrequencyNthDayType) {
-        this.repaymentFrequencyNthDayType = repaymentFrequencyNthDayType;
-    }
-
-    public Integer getRepaymentFrequencyDayOfWeekType() {
-        return this.repaymentFrequencyDayOfWeekType;
-    }
-
-    public void setRepaymentFrequencyDayOfWeekType(Integer repaymentFrequencyDayOfWeekType) {
-        this.repaymentFrequencyDayOfWeekType = repaymentFrequencyDayOfWeekType;
-    }
-
     public String getAccountNumber() {
         return this.accountNumber;
     }
@@ -5597,8 +5806,10 @@ public class Loan extends AbstractPersistable<Long> {
         updateLoanToLastDisbursalState(actualDisbursementDate);
         for (Iterator<LoanTermVariations> iterator = this.loanTermVariations.iterator(); iterator.hasNext();) {
             LoanTermVariations loanTermVariations = iterator.next();
-            if (loanTermVariations.getTermType().isDueDateVariation() && loanTermVariations.fetchDateValue().isAfter(actualDisbursementDate) ||
-                    loanTermVariations.getTermType().isEMIAmountVariation() && loanTermVariations.getTermApplicableFrom().equals(actualDisbursementDate.toDate())
+            if (loanTermVariations.getTermType().isDueDateVariation()
+                    && loanTermVariations.fetchDateValue().isAfter(actualDisbursementDate)
+                    || loanTermVariations.getTermType().isEMIAmountVariation()
+                    && loanTermVariations.getTermApplicableFrom().equals(actualDisbursementDate.toDate())
                     || loanTermVariations.getTermApplicableFrom().after(actualDisbursementDate.toDate())) {
                 iterator.remove();
             }
@@ -5722,7 +5933,7 @@ public class Loan extends AbstractPersistable<Long> {
         }
         return nextRepaymentDate;
     }
-    
+
     public BigDecimal getDerivedAmountForCharge(LoanCharge loanCharge) {
         BigDecimal amount = BigDecimal.ZERO;
         if (isMultiDisburmentLoan() && (loanCharge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue())) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
index 5a2241b..f1f8c4e 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInstallmentCharge.java
@@ -288,4 +288,10 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
         return amountToDeductOnThisCharge;
     }
 
+	public LoanCharge getLoancharge() {
+		return this.loancharge;
+	}
+	public LoanRepaymentScheduleInstallment getInstallment() {
+		return this.installment;
+	}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalcualtionAdditionalDetails.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalcualtionAdditionalDetails.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalcualtionAdditionalDetails.java
new file mode 100644
index 0000000..f374760
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanInterestRecalcualtionAdditionalDetails.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.joda.time.LocalDate;
+import org.springframework.data.jpa.domain.AbstractPersistable;
+
+@Entity
+@Table(name = "m_loan_interest_recalculation_additional_details")
+public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersistable<Long> {
+
+    @Temporal(TemporalType.DATE)
+    @Column(name = "effective_date")
+    private Date effectiveDate;
+
+    @Column(name = "amount", scale = 6, precision = 19, nullable = false)
+    private BigDecimal amount;
+
+    protected LoanInterestRecalcualtionAdditionalDetails() {
+
+    }
+
+    public LoanInterestRecalcualtionAdditionalDetails(final LocalDate effectiveDate, final BigDecimal amount) {
+        if (effectiveDate != null) {
+            this.effectiveDate = effectiveDate.toDate();
+        }
+        this.amount = amount;
+    }
+
+    public LocalDate getEffectiveDate() {
+        return new LocalDate(this.effectiveDate);
+    }
+
+    public BigDecimal getAmount() {
+        return this.amount;
+    }
+}



[08/10] incubator-fineract git commit: FINERACT-60 : Interest compounding, nth day rest frequency and meeting calendar date changes

Posted by ra...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java
index a825bcb..4126f75 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java
@@ -111,7 +111,8 @@ public class LoanReschedulingWithinCenterTest {
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", recalculationRestFrequencyDate,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan, 
+                null, null);
 
         // APPLY FOR TRANCHE LOAN WITH INTEREST RECALCULATION
         final Integer loanId = applyForLoanApplicationForInterestRecalculation(clientId, groupId, calendarId, loanProductID, disbursalDate,
@@ -222,7 +223,8 @@ public class LoanReschedulingWithinCenterTest {
                 LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
                 LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
                 LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", recalculationRestFrequencyDate,
-                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan);
+                LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan, 
+                null, null);
 
         // CREATE TRANCHES
         List<HashMap> createTranches = new ArrayList<>();
@@ -279,14 +281,18 @@ public class LoanReschedulingWithinCenterTest {
             final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
             final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
             final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts,
-            final boolean isMultiTrancheLoan) {
+            final boolean isMultiTrancheLoan, final Integer recalculationRestFrequencyOnDayType, final Integer recalculationRestFrequencyDayOfWeekType) {
         final String recalculationCompoundingFrequencyType = null;
         final String recalculationCompoundingFrequencyInterval = null;
         final String recalculationCompoundingFrequencyDate = null;
+        final Integer recalculationCompoundingFrequencyOnDayType = null;
+        final Integer recalculationCompoundingFrequencyDayOfWeekType = null;
         return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
                 rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
                 recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
-                recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false, isMultiTrancheLoan);
+                recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false, isMultiTrancheLoan, 
+                recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType, recalculationRestFrequencyOnDayType, 
+                recalculationRestFrequencyDayOfWeekType);
     }
 
     private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
@@ -295,7 +301,10 @@ public class LoanReschedulingWithinCenterTest {
             final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
             final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
             final String preCloseInterestCalculationStrategy, final Account[] accounts, final String chargeId,
-            boolean isArrearsBasedOnOriginalSchedule, final boolean isMultiTrancheLoan) {
+            boolean isArrearsBasedOnOriginalSchedule, final boolean isMultiTrancheLoan, 
+            final Integer recalculationCompoundingFrequencyOnDayType,
+            final Integer recalculationCompoundingFrequencyDayOfWeekType, final Integer recalculationRestFrequencyOnDayType,
+            final Integer recalculationRestFrequencyDayOfWeekType) {
         System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
         LoanProductTestBuilder builder = new LoanProductTestBuilder()
                 .withPrincipal("10000.00")
@@ -311,9 +320,10 @@ public class LoanReschedulingWithinCenterTest {
                 .withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
                         preCloseInterestCalculationStrategy)
                 .withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
-                        recalculationRestFrequencyDate)
+                        recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType)
                 .withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
-                        recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
+                        recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType,
+                        recalculationCompoundingFrequencyDayOfWeekType);
         if (accounts != null) {
             builder = builder.withAccountingRulePeriodicAccrual(accounts);
         }
@@ -356,7 +366,6 @@ public class LoanReschedulingWithinCenterTest {
                 .withInterestCalculationPeriodTypeAsDays() //
                 .withExpectedDisbursementDate(disbursementDate) //
                 .withSubmittedOnDate(disbursementDate) //
-                .withRestFrequencyDate(restStartDate)//
                 .withwithRepaymentStrategy(repaymentStrategy) //
                 .withCharges(charges)//
                 .build(clientID.toString(), groupId.toString(), loanProductID.toString(), null);
@@ -389,4 +398,5 @@ public class LoanReschedulingWithinCenterTest {
         date.add(type, addvalue);
         return new ArrayList<>(Arrays.asList(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1, date.get(Calendar.DAY_OF_MONTH)));
     }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
index cfa9c39..50d9cc9 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
@@ -61,8 +61,6 @@ public class LoanApplicationTestBuilder {
     private List<HashMap> disbursementData = null;
     @SuppressWarnings("rawtypes")
     private List<HashMap> charges = new ArrayList<>();
-    private String recalculationRestFrequencyDate = null;
-    private String recalculationCompoundingFrequencyDate = null;
     private String repaymentsStartingFromDate = null;
 
     private String calendarId;
@@ -135,12 +133,6 @@ public class LoanApplicationTestBuilder {
             map.put("maxOutstandingLoanBalance", maxOutstandingLoanBalance);
 
         }
-        if (recalculationRestFrequencyDate != null) {
-            map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate);
-        }
-        if (recalculationCompoundingFrequencyDate != null) {
-            map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate);
-        }
 
         System.out.println("Loan Application request : " + map);
         return new Gson().toJson(map);
@@ -281,15 +273,7 @@ public class LoanApplicationTestBuilder {
         return this;
     }
 
-    public LoanApplicationTestBuilder withRestFrequencyDate(final String recalculationRestFrequencyDate) {
-        this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
-        return this;
-    }
 
-    public LoanApplicationTestBuilder withCompoundingFrequencyDate(final String recalculationCompoundingFrequencyDate) {
-        this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
-        return this;
-    }
 
     public LoanApplicationTestBuilder withFirstRepaymentDate(final String firstRepaymentDate) {
         this.repaymentsStartingFromDate = firstRepaymentDate;

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
index 3b4c767..5f90468 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
@@ -104,10 +104,8 @@ public class LoanProductTestBuilder {
     private String rescheduleStrategyMethod = "1";
     private String recalculationRestFrequencyType = "1";
     private String recalculationRestFrequencyInterval = "0";
-    private String recalculationRestFrequencyDate = null;
     private String recalculationCompoundingFrequencyType = null;
     private String recalculationCompoundingFrequencyInterval = null;
-    private String recalculationCompoundingFrequencyDate = null;
     private String minimumDaysBetweenDisbursalAndFirstRepayment = null;
     private Boolean holdGuaranteeFunds = null;
     private String mandatoryGuarantee = null;
@@ -122,6 +120,10 @@ public class LoanProductTestBuilder {
     private Boolean allowVariableInstallments = Boolean.FALSE;
     private Integer minimumGap;
     private Integer maximumGap;
+    private Integer recalculationCompoundingFrequencyOnDayType = null;
+    private Integer recalculationRestFrequencyOnDayType = null;
+    private Integer recalculationCompoundingFrequencyDayOfWeekType = null;
+    private Integer recalculationRestFrequencyDayOfWeekType = null;
 
     public String build(final String chargeId) {
         final HashMap<String, Object> map = new HashMap<>();
@@ -177,16 +179,18 @@ public class LoanProductTestBuilder {
             map.put("rescheduleStrategyMethod", this.rescheduleStrategyMethod);
             map.put("recalculationRestFrequencyType", recalculationRestFrequencyType);
             map.put("recalculationRestFrequencyInterval", recalculationRestFrequencyInterval);
-            map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate);
             if (!RECALCULATION_COMPOUNDING_METHOD_NONE.equals(this.interestRecalculationCompoundingMethod)) {
                 map.put("recalculationCompoundingFrequencyType", recalculationCompoundingFrequencyType);
                 map.put("recalculationCompoundingFrequencyInterval", recalculationCompoundingFrequencyInterval);
-                map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate);
             }
             map.put("preClosureInterestCalculationStrategy", preCloseInterestCalculationStrategy);
             if (isArrearsBasedOnOriginalSchedule != null) {
                 map.put("isArrearsBasedOnOriginalSchedule", isArrearsBasedOnOriginalSchedule);
             }
+            map.put("recalculationCompoundingFrequencyOnDayType", this.recalculationCompoundingFrequencyOnDayType);
+            map.put("recalculationCompoundingFrequencyDayOfWeekType", this.recalculationCompoundingFrequencyDayOfWeekType);
+            map.put("recalculationRestFrequencyOnDayType", this.recalculationRestFrequencyOnDayType);
+            map.put("recalculationRestFrequencyDayOfWeekType", this.recalculationRestFrequencyDayOfWeekType);
         }
         if (holdGuaranteeFunds != null) {
             map.put("holdGuaranteeFunds", this.holdGuaranteeFunds);
@@ -437,20 +441,24 @@ public class LoanProductTestBuilder {
     }
 
     public LoanProductTestBuilder withInterestRecalculationRestFrequencyDetails(final String recalculationRestFrequencyType,
-            final String recalculationRestFrequencyInterval, final String recalculationRestFrequencyDate) {
+            final String recalculationRestFrequencyInterval, final Integer recalculationRestFrequencyOnDayType,
+            final Integer recalculationRestFrequencyDayOfWeekType) {
         this.isInterestRecalculationEnabled = true;
         this.recalculationRestFrequencyType = recalculationRestFrequencyType;
         this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
-        this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
+        this.recalculationRestFrequencyOnDayType = recalculationRestFrequencyOnDayType;
+        this.recalculationRestFrequencyDayOfWeekType = recalculationRestFrequencyDayOfWeekType;
         return this;
     }
 
     public LoanProductTestBuilder withInterestRecalculationCompoundingFrequencyDetails(final String recalculationCompoundingFrequencyType,
-            final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate) {
+            final String recalculationCompoundingFrequencyInterval, final Integer recalculationCompoundingFrequencyOnDayType,
+            final Integer recalculationCompoundingFrequencyDayOfWeekType) {
         this.isInterestRecalculationEnabled = true;
         this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
         this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
-        this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
+        this.recalculationCompoundingFrequencyOnDayType = recalculationCompoundingFrequencyOnDayType;
+        this.recalculationCompoundingFrequencyDayOfWeekType = recalculationCompoundingFrequencyDayOfWeekType;
         return this;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java
index 3e499d1..447cb13 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java
@@ -173,6 +173,9 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
         return this.amount;
     }
 
+    public void setAmount(BigDecimal amount) {
+        this.amount = amount;
+    }
     public void setReversalJournalEntry(final JournalEntry reversalJournalEntry) {
         this.reversalJournalEntry = reversalJournalEntry;
     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryRepository.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryRepository.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryRepository.java
index ab61a70..120b03e 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryRepository.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntryRepository.java
@@ -18,6 +18,7 @@
  */
 package org.apache.fineract.accounting.journalentry.domain;
 
+import java.util.Date;
 import java.util.List;
 
 import org.springframework.data.jpa.repository.JpaRepository;
@@ -39,8 +40,13 @@ public interface JournalEntryRepository extends JpaRepository<JournalEntry, Long
     
     @Query("from JournalEntry journalEntry where journalEntry.entityId= :entityId and journalEntry.entityType = :entityType")    
     List<JournalEntry> findProvisioningJournalEntriesByEntityId(@Param("entityId") Long entityId, @Param("entityType") Integer entityType) ;
-    
+
     @Query("from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed is false and journalEntry.entityType = :entityType")
-    List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType) ;
-    
+    List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType);
+
+    @Query("from JournalEntry journalEntry where glAccount.id= :accountId and transactionId= :transactionId and transactionDate= :transactionDate"
+            + " and type= :journalEntryType and entityType=1 and entityId= :loanId and loanTransaction.id= :loanTransactionId")
+    JournalEntry findLOANJournalEntryWith(@Param("accountId") Long accountId, @Param("transactionId") String transactionId,
+            @Param("transactionDate") Date transactionDate, @Param("journalEntryType") Integer journalEntryType,
+            @Param("loanId") Long loanId, @Param("loanTransactionId") Long loanTransactionId);
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
index 3d64581..c7a0c23 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
@@ -781,6 +781,12 @@ public class AccountingProcessorHelper {
             final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
             final BigDecimal amount, final Boolean isReversal) {
         final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
+        createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, amount, isReversal, account);
+    }
+
+    public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final Long loanId,
+            final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal,
+            final GLAccount account) {
         if (isReversal) {
             createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
         } else {
@@ -1070,7 +1076,7 @@ public class AccountingProcessorHelper {
         this.glJournalEntryRepository.save(journalEntry);
     }
 
-    private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
+    public GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
         GLAccount glAccount = null;
         if (isOrganizationAccount(accountMappingTypeId)) {
             FinancialActivityAccount financialActivityAccount = this.financialActivityAccountRepository

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
index 8287b72..7408ac9 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java
@@ -21,12 +21,16 @@ package org.apache.fineract.accounting.journalentry.service;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.fineract.accounting.closure.domain.GLClosure;
 import org.apache.fineract.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
 import org.apache.fineract.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
 import org.apache.fineract.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY;
+import org.apache.fineract.accounting.glaccount.domain.GLAccount;
 import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
 import org.apache.fineract.accounting.journalentry.data.LoanDTO;
 import org.apache.fineract.accounting.journalentry.data.LoanTransactionDTO;
@@ -88,7 +92,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
                     .getTransactionType().isWaiveCharges())) {
                 createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, true, false);
             }
-            
+
             /** Logic for Refunds of Active Loans **/
             else if (loanTransactionDTO.getTransactionType().isRefundForActiveLoans()) {
                 createJournalEntriesForRefundForActiveLoan(loanDTO, loanTransactionDTO, office);
@@ -193,18 +197,27 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
 
         BigDecimal totalDebitAmount = new BigDecimal(0);
 
+        Map<GLAccount, BigDecimal> accountMap = new HashMap<>();
+
         // handle principal payment or writeOff (and reversals)
         if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
             totalDebitAmount = totalDebitAmount.add(principalAmount);
-            this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO,
-                    loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalAmount, isReversal);
+            GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                    ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), paymentTypeId);
+            accountMap.put(account, principalAmount);
         }
 
         // handle interest payment of writeOff (and reversals)
         if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
             totalDebitAmount = totalDebitAmount.add(interestAmount);
-            this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE,
-                    loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal);
+            GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                    ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
+            if (accountMap.containsKey(account)) {
+                BigDecimal amount = accountMap.get(account).add(interestAmount);
+                accountMap.put(account, amount);
+            } else {
+                accountMap.put(account, interestAmount);
+            }
         }
 
         // handle fees payment of writeOff (and reversals)
@@ -212,12 +225,23 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
             totalDebitAmount = totalDebitAmount.add(feesAmount);
 
             if (isIncomeFromFee) {
-                this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
-                        ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
-                        feesAmount, isReversal, loanTransactionDTO.getFeePayments());
+                GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), paymentTypeId);
+                if (accountMap.containsKey(account)) {
+                    BigDecimal amount = accountMap.get(account).add(feesAmount);
+                    accountMap.put(account, amount);
+                } else {
+                    accountMap.put(account, feesAmount);
+                }
             } else {
-                this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE,
-                        loanProductId, paymentTypeId, loanId, transactionId, transactionDate, feesAmount, isReversal);
+                GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), paymentTypeId);
+                if (accountMap.containsKey(account)) {
+                    BigDecimal amount = accountMap.get(account).add(feesAmount);
+                    accountMap.put(account, amount);
+                } else {
+                    accountMap.put(account, feesAmount);
+                }
             }
         }
 
@@ -225,19 +249,41 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
         if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             if (isIncomeFromFee) {
-                this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
-                        ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
-                        penaltiesAmount, isReversal, loanTransactionDTO.getPenaltyPayments());
+                GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), paymentTypeId);
+                if (accountMap.containsKey(account)) {
+                    BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
+                    accountMap.put(account, amount);
+                } else {
+                    accountMap.put(account, penaltiesAmount);
+                }
             } else {
-                this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE,
-                        loanProductId, paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal);
+                GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                        ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(), paymentTypeId);
+                if (accountMap.containsKey(account)) {
+                    BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
+                    accountMap.put(account, amount);
+                } else {
+                    accountMap.put(account, penaltiesAmount);
+                }
             }
         }
-        
+
         if (overPaymentAmount != null && !(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
             totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
-            this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT, loanProductId,
-                    paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, isReversal);
+            GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
+                    ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), paymentTypeId);
+            if (accountMap.containsKey(account)) {
+                BigDecimal amount = accountMap.get(account).add(overPaymentAmount);
+                accountMap.put(account, amount);
+            } else {
+                accountMap.put(account, overPaymentAmount);
+            }
+        }
+
+        for (Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
+            this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
+                    entry.getValue(), isReversal, entry.getKey());
         }
 
         /**
@@ -367,6 +413,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
                     paymentTypeId, loanId, transactionId, transactionDate, refundAmount, isReversal);
         }
     }
+
     private void createJournalEntriesForRefundForActiveLoan(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO, Office office) {
         // TODO Auto-generated method stub
         // loan properties
@@ -401,12 +448,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
 
         if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
             totalDebitAmount = totalDebitAmount.add(feesAmount);
-            
+
             List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
-            
-            for(ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getFeePayments()) {
-                chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(), 
-                        chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1)):chargePaymentDTO.getAmount() ));
+
+            for (ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getFeePayments()) {
+                chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(),
+                        chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1))
+                                : chargePaymentDTO.getAmount()));
             }
             this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
                     CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
@@ -416,12 +464,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
         if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
             totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
             List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
-            
-            for(ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getPenaltyPayments()) {
-                chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(), 
-                        chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1)):chargePaymentDTO.getAmount() ));
+
+            for (ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getPenaltyPayments()) {
+                chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(),
+                        chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1))
+                                : chargePaymentDTO.getAmount()));
             }
-            
+
             this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
                     CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
                     penaltiesAmount, !isReversal, chargePaymentDTOs);
@@ -434,8 +483,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
         }
 
         /*** create a single debit entry (or reversal) for the entire amount **/
-        this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), loanProductId,
-                paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
-     
+        this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(),
+                loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
+
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
index cec29fb..0580a4c 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java
@@ -39,8 +39,9 @@ public enum JobName {
     RECALCULATE_INTEREST_FOR_LOAN("Recalculate Interest For Loans"), //
     GENERATE_RD_SCEHDULE("Generate Mandatory Savings Schedule"), //
     GENERATE_LOANLOSS_PROVISIONING("Generate Loan Loss Provisioning"), //
-    POST_DIVIDENTS_FOR_SHARES("Post Dividends For Shares"),
-    UPDATE_SAVINGS_DORMANT_ACCOUNTS("Update Savings Dormant Accounts");
+    POST_DIVIDENTS_FOR_SHARES("Post Dividends For Shares"), //
+    UPDATE_SAVINGS_DORMANT_ACCOUNTS("Update Savings Dormant Accounts"), //
+    ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS("Add Accrual Transactions For Loans With Income Posted As Transactions");
 
     private final String name;
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/CalendarConstants.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/CalendarConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/CalendarConstants.java
index a15a71b..b96eee5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/CalendarConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/CalendarConstants.java
@@ -31,7 +31,8 @@ public class CalendarConstants {
                 "typeId"), REPEATING("repeating"), REMIND_BY_ID("remindById"), FIRST_REMINDER("firstReminder"), SECOND_REMINDER(
                 "secondReminder"), LOCALE("locale"), DATE_FORMAT("dateFormat"), FREQUENCY("frequency"), INTERVAL("interval"), REPEATS_ON_DAY(
                 "repeatsOnDay"), RESCHEDULE_BASED_ON_MEETING_DATES("reschedulebasedOnMeetingDates"), PRESENT_MEETING_DATE(
-                "presentMeetingDate"), NEW_MEETING_DATE("newMeetingDate"),MEETING_TIME("meetingtime"),Time_Format("timeFormat"), ;
+                "presentMeetingDate"), NEW_MEETING_DATE("newMeetingDate"),MEETING_TIME("meetingtime"),Time_Format("timeFormat"), REPEATS_ON_NTH_DAY_OF_MONTH("repeatsOnNthDayOfMonth"),
+                REPEATS_ON_LAST_WEEKDAY_OF_MONTH("repeatsOnLastWeekdayOfMonth"), REPEATS_ON_DAY_OF_MONTH("repeatsOnDayOfMonth");
 
         private final String value;
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/api/CalendarsApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/api/CalendarsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/api/CalendarsApiResource.java
index f2ac608..418c902 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/api/CalendarsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/api/CalendarsApiResource.java
@@ -230,8 +230,9 @@ public class CalendarsApiResource {
         final List<EnumOptionData> remindByOptions = this.dropdownReadPlatformService.retrieveCalendarRemindByOptions();
         final List<EnumOptionData> frequencyOptions = this.dropdownReadPlatformService.retrieveCalendarFrequencyTypeOptions();
         final List<EnumOptionData> repeatsOnDayOptions = this.dropdownReadPlatformService.retrieveCalendarWeekDaysTypeOptions();
+        final List<EnumOptionData> frequencyNthDayTypeOptions = this.dropdownReadPlatformService.retrieveCalendarFrequencyNthDayTypeOptions();
         return CalendarData.withTemplateOptions(calendarData, entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions,
-                repeatsOnDayOptions);
+                repeatsOnDayOptions, frequencyNthDayTypeOptions);
     }
 
     private CommandWrapper getResourceDetails(final CalendarEntityType type, final Long entityId) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 de89923..2c6513a 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
@@ -28,6 +28,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarType;
 import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
 import org.apache.fineract.portfolio.calendar.service.CalendarEnumerations;
 import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
+import org.apache.fineract.portfolio.common.domain.NthDayType;
 import org.joda.time.LocalDate;
 import org.joda.time.LocalTime;
 
@@ -53,6 +54,7 @@ public class CalendarData {
     private final EnumOptionData frequency;
     private final Integer interval;
     private final EnumOptionData repeatsOnDay;
+    private final EnumOptionData repeatsOnNthDayOfMonth;
     private final EnumOptionData remindBy;
     private final Integer firstReminder;
     private final Integer secondReminder;
@@ -67,20 +69,24 @@ public class CalendarData {
     private final String createdByUsername;
     private final Long lastUpdatedByUserId;
     private final String lastUpdatedByUsername;
+    private final Integer repeatsOnDayOfMonth;
+
     // template related
     final List<EnumOptionData> entityTypeOptions;
     final List<EnumOptionData> calendarTypeOptions;
     final List<EnumOptionData> remindByOptions;
     final List<EnumOptionData> frequencyOptions;
     final List<EnumOptionData> repeatsOnDayOptions;
+    final List<EnumOptionData> frequencyNthDayTypeOptions;
  
     public static CalendarData instance(final Long id, final Long calendarInstanceId, final Long entityId, final EnumOptionData entityType,
             final String title, final String description, final String location, final LocalDate startDate, final LocalDate endDate,
             final Integer duration, final EnumOptionData type, final boolean repeating, final String recurrence,
-            final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay, final EnumOptionData remindBy,
-            final Integer firstReminder, final Integer secondReminder, final String humanReadable, final LocalDate createdDate,
-            final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId,
-            final String lastUpdatedByUsername, final LocalTime meetingTime) {
+            final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay,
+            final EnumOptionData repeatsOnNthDayOfMonth, final EnumOptionData remindBy, final Integer firstReminder,
+            final Integer secondReminder, final String humanReadable, final LocalDate createdDate, final LocalDate lastUpdatedDate,
+            final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId, final String lastUpdatedByUsername,
+            final LocalTime meetingTime, final Integer repeatsOnDayOfMonth) {
 
         final Collection<LocalDate> recurringDates = null;
         final Collection<LocalDate> nextTenRecurringDates = null;
@@ -91,12 +97,14 @@ public class CalendarData {
         final List<EnumOptionData> remindByOptions = null;
         final List<EnumOptionData> frequencyOptions = null;
         final List<EnumOptionData> repeatsOnDayOptions = null;
+        final List<EnumOptionData> frequencyNthDayTypeOptions = null;
 
         return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration,
-                type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
-                nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
-                createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
-                frequencyOptions, repeatsOnDayOptions, meetingTime);
+                type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy, firstReminder,
+                secondReminder, recurringDates, nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate,
+                lastUpdatedDate, createdByUserId, createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, repeatsOnDayOfMonth,
+                entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions, repeatsOnDayOptions, meetingTime,
+                frequencyNthDayTypeOptions);
     }
 
     public static CalendarData withRecurringDates(final CalendarData calendarData, final Collection<LocalDate> recurringDates,
@@ -104,24 +112,24 @@ public class CalendarData {
         return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType,
                 calendarData.title, calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate,
                 calendarData.duration, calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency,
-                calendarData.interval, calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder,
+                calendarData.interval, calendarData.repeatsOnDay, calendarData.repeatsOnNthDayOfMonth, calendarData.remindBy, calendarData.firstReminder,
                 calendarData.secondReminder, recurringDates, nextTenRecurringDates, calendarData.humanReadable, recentEligibleMeetingDate,
                 calendarData.createdDate, calendarData.lastUpdatedDate, calendarData.createdByUserId, calendarData.createdByUsername,
-                calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername, calendarData.entityTypeOptions,
+                calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername, calendarData.repeatsOnDayOfMonth, calendarData.entityTypeOptions,
                 calendarData.calendarTypeOptions, calendarData.remindByOptions, calendarData.frequencyOptions,
-                calendarData.repeatsOnDayOptions,calendarData.meetingTime);
+                calendarData.repeatsOnDayOptions, calendarData.meetingTime, calendarData.frequencyNthDayTypeOptions);
     }
 
     public static CalendarData withRecentEligibleMeetingDate(final CalendarData calendarData, final LocalDate recentEligibleMeetingDate) {
         return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType,
                 calendarData.title, calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate,
                 calendarData.duration, calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency,
-                calendarData.interval, calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder,
+                calendarData.interval, calendarData.repeatsOnDay, calendarData.repeatsOnNthDayOfMonth, calendarData.remindBy, calendarData.firstReminder,
                 calendarData.secondReminder, calendarData.recurringDates, calendarData.nextTenRecurringDates, calendarData.humanReadable,
                 recentEligibleMeetingDate, calendarData.createdDate, calendarData.lastUpdatedDate, calendarData.createdByUserId,
                 calendarData.createdByUsername, calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername,
-                calendarData.entityTypeOptions, calendarData.calendarTypeOptions, calendarData.remindByOptions,
-                calendarData.frequencyOptions, calendarData.repeatsOnDayOptions,calendarData.meetingTime);
+                calendarData.repeatsOnDayOfMonth, calendarData.entityTypeOptions, calendarData.calendarTypeOptions, calendarData.remindByOptions,
+                calendarData.frequencyOptions, calendarData.repeatsOnDayOptions,calendarData.meetingTime, calendarData.frequencyNthDayTypeOptions);
     }
 
     public static CalendarData sensibleDefaultsForNewCalendarCreation() {
@@ -141,6 +149,7 @@ public class CalendarData {
         final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarFrequencyType.DAILY);
         final Integer interval = new Integer(1);
         final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarWeekDaysType.MO);
+        final EnumOptionData repeatsOnNthDayOfMonth = CalendarEnumerations.calendarFrequencyNthDayType(NthDayType.ONE);
         final EnumOptionData remindBy = CalendarEnumerations.calendarRemindBy(CalendarRemindBy.EMAIL);
         final Integer firstReminder = new Integer(0);
         final Integer secondReminder = new Integer(0);
@@ -154,6 +163,7 @@ public class CalendarData {
         final List<EnumOptionData> remindByOptions = null;
         final List<EnumOptionData> frequencyOptions = null;
         final List<EnumOptionData> repeatsOnDayOptions = null;
+        final List<EnumOptionData> frequencyNthDayTypeOptions = null;
 
         final LocalDate createdDate = null;
         final LocalDate lastUpdatedDate = null;
@@ -162,39 +172,44 @@ public class CalendarData {
         final Long lastUpdatedByUserId = null;
         final String lastUpdatedByUsername = null;
         final LocalTime meetingTime = null;
+        final Integer repeatsOnDayOfMonth = null;
 
         return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration,
-                type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
-                nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
-                createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
-                frequencyOptions, repeatsOnDayOptions, meetingTime);
+                type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy, firstReminder,
+                secondReminder, recurringDates, nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate,
+                lastUpdatedDate, createdByUserId, createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, repeatsOnDayOfMonth,
+                entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions, repeatsOnDayOptions, meetingTime,
+                frequencyNthDayTypeOptions);
     }
 
     public static CalendarData withTemplateOptions(final CalendarData calendarData, final List<EnumOptionData> entityTypeOptions,
             final List<EnumOptionData> calendarTypeOptions, final List<EnumOptionData> remindByOptions,
-            final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions) {
+            final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions,
+            final List<EnumOptionData> frequencyNthDayTypeOptions) {
 
         return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType,
                 calendarData.title, calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate,
                 calendarData.duration, calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency,
-                calendarData.interval, calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder,
-                calendarData.secondReminder, calendarData.recurringDates, calendarData.nextTenRecurringDates, calendarData.humanReadable,
-                calendarData.recentEligibleMeetingDate, calendarData.createdDate, calendarData.lastUpdatedDate,
+                calendarData.interval, calendarData.repeatsOnDay, calendarData.repeatsOnNthDayOfMonth, calendarData.remindBy,
+                calendarData.firstReminder, calendarData.secondReminder, calendarData.recurringDates, calendarData.nextTenRecurringDates,
+                calendarData.humanReadable, calendarData.recentEligibleMeetingDate, calendarData.createdDate, calendarData.lastUpdatedDate,
                 calendarData.createdByUserId, calendarData.createdByUsername, calendarData.lastUpdatedByUserId,
-                calendarData.lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions, repeatsOptions,
-                repeatsOnDayOptions,calendarData.meetingTime);
+                calendarData.lastUpdatedByUsername, calendarData.repeatsOnDayOfMonth, entityTypeOptions, calendarTypeOptions,
+                remindByOptions, repeatsOptions, repeatsOnDayOptions, calendarData.meetingTime, frequencyNthDayTypeOptions);
     }
 
     private CalendarData(final Long id, final Long calendarInstanceId, final Long entityId, final EnumOptionData entityType,
             final String title, final String description, final String location, final LocalDate startDate, final LocalDate endDate,
             final Integer duration, final EnumOptionData type, final boolean repeating, final String recurrence,
-            final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay, final EnumOptionData remindBy,
-            final Integer firstReminder, final Integer secondReminder, final Collection<LocalDate> recurringDates,
-            final Collection<LocalDate> nextTenRecurringDates, final String humanReadable, final LocalDate recentEligibleMeetingDate,
-            final LocalDate createdDate, final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername,
-            final Long lastUpdatedByUserId, final String lastUpdatedByUsername, final List<EnumOptionData> entityTypeOptions,
+            final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay,
+            final EnumOptionData repeatsOnNthDayOfMonth, final EnumOptionData remindBy, final Integer firstReminder,
+            final Integer secondReminder, final Collection<LocalDate> recurringDates, final Collection<LocalDate> nextTenRecurringDates,
+            final String humanReadable, final LocalDate recentEligibleMeetingDate, final LocalDate createdDate,
+            final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId,
+            final String lastUpdatedByUsername, final Integer repeatsOnDayOfMonth, final List<EnumOptionData> entityTypeOptions,
             final List<EnumOptionData> calendarTypeOptions, final List<EnumOptionData> remindByOptions,
-            final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions,final LocalTime meetingTime) {
+            final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions,final LocalTime meetingTime, 
+            final List<EnumOptionData> frequencyNthDayTypeOptions) {
         this.id = id;
         this.calendarInstanceId = calendarInstanceId;
         this.entityId = entityId;
@@ -211,6 +226,7 @@ public class CalendarData {
         this.frequency = frequency;
         this.interval = interval;
         this.repeatsOnDay = repeatsOnDay;
+        this.repeatsOnNthDayOfMonth = repeatsOnNthDayOfMonth;
         this.remindBy = remindBy;
         this.firstReminder = firstReminder;
         this.secondReminder = secondReminder;
@@ -224,12 +240,14 @@ public class CalendarData {
         this.createdByUsername = createdByUsername;
         this.lastUpdatedByUserId = lastUpdatedByUserId;
         this.lastUpdatedByUsername = lastUpdatedByUsername;
+        this.repeatsOnDayOfMonth = repeatsOnDayOfMonth;
         this.entityTypeOptions = entityTypeOptions;
         this.calendarTypeOptions = calendarTypeOptions;
         this.remindByOptions = remindByOptions;
         this.frequencyOptions = repeatsOptions;
         this.repeatsOnDayOptions = repeatsOnDayOptions;
         this.meetingTime = meetingTime;
+        this.frequencyNthDayTypeOptions = frequencyNthDayTypeOptions;
     }
 
     public Long getId() {
@@ -350,4 +368,10 @@ public class CalendarData {
     public EnumOptionData frequencyType(){
         return this.frequency;
     }
+	public EnumOptionData getRepeatsOnDay() {
+		return this.repeatsOnDay;
+	}
+	public EnumOptionData getRepeatsOnNthDayOfMonth() {
+		return this.repeatsOnNthDayOfMonth;
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 f44dfdd..f2fa718 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
@@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORT
 import org.apache.fineract.portfolio.calendar.exception.CalendarDateException;
 import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
 import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
+import org.apache.fineract.portfolio.common.domain.NthDayType;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.apache.poi.openxml4j.util.Nullable;
 import org.joda.time.LocalDate;
@@ -152,8 +153,9 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
     }
 
     public static Calendar createRepeatingCalendar(final String title, final LocalDate startDate, final Integer typeId,
-            final CalendarFrequencyType frequencyType, final Integer interval, final Integer repeatsOnDay) {
-        final String recurrence = constructRecurrence(frequencyType, interval, repeatsOnDay);
+            final CalendarFrequencyType frequencyType, final Integer interval, final Integer repeatsOnDay,
+            final Integer repeatsOnNthDayOfMonth) {
+        final String recurrence = constructRecurrence(frequencyType, interval, repeatsOnDay, repeatsOnNthDayOfMonth);
         return createRepeatingCalendar(title, startDate, typeId, recurrence);
     }
 
@@ -245,7 +247,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
 
             // TODO cover other recurrence also
 
-            this.recurrence = constructRecurrence(calendarFrequencyType, interval, repeatsOnDay);
+            this.recurrence = constructRecurrence(calendarFrequencyType, interval, repeatsOnDay, null);
 
         }
 
@@ -422,7 +424,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
 
     @SuppressWarnings("null")
     public Map<String, Object> updateRepeatingCalendar(final LocalDate calendarStartDate, final CalendarFrequencyType frequencyType,
-            final Integer interval, final Integer repeatsOnDay) {
+            final Integer interval, final Integer repeatsOnDay, final Integer repeatsOnNthDay) {
         final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
 
         if (calendarStartDate != null & this.startDate != null) {
@@ -432,7 +434,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
             }
         }
 
-        final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, repeatsOnDay);
+        final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, repeatsOnDay, repeatsOnNthDay);
         if (!StringUtils.isBlank(this.recurrence) && !newRecurrence.equalsIgnoreCase(this.recurrence)) {
             actualChanges.put("recurrence", newRecurrence);
             this.recurrence = newRecurrence;
@@ -568,13 +570,27 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
             if (frequencyType.isWeekly()) {
                 repeatsOnDay = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue());
             }
+            Integer repeatsOnNthDayOfMonth = null;
+            if (frequencyType.isMonthly()) {
+                repeatsOnNthDayOfMonth = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_NTH_DAY_OF_MONTH
+                        .getValue());
+                final NthDayType nthDay = NthDayType.fromInt(repeatsOnNthDayOfMonth);
+                repeatsOnDay = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_LAST_WEEKDAY_OF_MONTH
+                        .getValue());
+                if (nthDay.isOnDay()) {
+                    repeatsOnNthDayOfMonth = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY_OF_MONTH
+                            .getValue());
+                    repeatsOnDay = null;
+                }
+            }
 
-            return constructRecurrence(frequencyType, interval, repeatsOnDay);
+            return constructRecurrence(frequencyType, interval, repeatsOnDay, repeatsOnNthDayOfMonth);
         }
         return "";
     }
 
-    private static String constructRecurrence(final CalendarFrequencyType frequencyType, final Integer interval, final Integer repeatsOnDay) {
+    private static String constructRecurrence(final CalendarFrequencyType frequencyType, final Integer interval,
+            final Integer repeatsOnDay, final Integer repeatsOnNthDayOfMonth) {
         final StringBuilder recurrenceBuilder = new StringBuilder(200);
 
         recurrenceBuilder.append("FREQ=");
@@ -584,10 +600,31 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
             recurrenceBuilder.append(interval);
         }
         if (frequencyType.isWeekly()) {
-            final CalendarWeekDaysType weekDays = CalendarWeekDaysType.fromInt(repeatsOnDay);
-            if (!weekDays.isInvalid()) {
-                recurrenceBuilder.append(";BYDAY=");
-                recurrenceBuilder.append(weekDays.toString().toUpperCase());
+            if (repeatsOnDay != null) {
+                final CalendarWeekDaysType weekDays = CalendarWeekDaysType.fromInt(repeatsOnDay);
+                if (!weekDays.isInvalid()) {
+                    recurrenceBuilder.append(";BYDAY=");
+                    recurrenceBuilder.append(weekDays.toString().toUpperCase());
+                }
+            }
+        }
+        if (frequencyType.isMonthly()) {
+            if (repeatsOnNthDayOfMonth != null && (repeatsOnDay == null || repeatsOnDay == CalendarWeekDaysType.INVALID.getValue())) {
+                if (repeatsOnNthDayOfMonth >= -1 && repeatsOnNthDayOfMonth <= 28) {
+                    recurrenceBuilder.append(";BYMONTHDAY=");
+                    recurrenceBuilder.append(repeatsOnNthDayOfMonth);
+                }
+            } else if (repeatsOnNthDayOfMonth != null && repeatsOnDay != null && repeatsOnDay != CalendarWeekDaysType.INVALID.getValue()) {
+                final NthDayType nthDay = NthDayType.fromInt(repeatsOnNthDayOfMonth);
+                if (!nthDay.isInvalid()) {
+                    recurrenceBuilder.append(";BYSETPOS=");
+                    recurrenceBuilder.append(nthDay.getValue());
+                }
+                final CalendarWeekDaysType weekday = CalendarWeekDaysType.fromInt(repeatsOnDay);
+                if (!weekday.isInvalid()) {
+                    recurrenceBuilder.append(";BYDAY=");
+                    recurrenceBuilder.append(weekday.toString().toUpperCase());
+                }
             }
         }
         return recurrenceBuilder.toString();
@@ -611,18 +648,22 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
 
         final CalendarFrequencyType frequencyType = CalendarUtils.getFrequency(this.recurrence);
         final Integer interval = new Integer(CalendarUtils.getInterval(this.recurrence));
-        final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, startDate.getDayOfWeek());
+        final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, startDate.getDayOfWeek(), null);
 
         this.recurrence = newRecurrence;
         this.startDate = startDate.toDate();
         this.endDate = endDate.toDate();
     }
-    
-    public Set<CalendarHistory> getCalendarHistory(){
-    	return this.calendarHistory;
+
+    public Set<CalendarHistory> getCalendarHistory() {
+        return this.calendarHistory;
     }
-    
-    public void updateCalendarHistory(final Set<CalendarHistory> calendarHistory){
-    	this.calendarHistory = calendarHistory;
+
+    public void updateCalendarHistory(final Set<CalendarHistory> calendarHistory) {
+        this.calendarHistory = calendarHistory;
+    }
+
+    public void setRecurrence(String recurrence) {
+        this.recurrence = recurrence;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstance.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstance.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstance.java
index 6c40b04..6ae6c60 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstance.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstance.java
@@ -31,7 +31,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
 @Table(name = "m_calendar_instance")
 public class CalendarInstance extends AbstractPersistable<Long> {
 
-    @ManyToOne(cascade = CascadeType.ALL)
+    @ManyToOne(cascade = CascadeType.PERSIST)
     @JoinColumn(name = "calendar_id", nullable = false)
     private Calendar calendar;
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java
index c956afa..fcdd2e2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/serialization/CalendarCommandFromApiJsonDeserializer.java
@@ -37,6 +37,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
 import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
 import org.apache.fineract.portfolio.calendar.domain.CalendarRemindBy;
 import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
+import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
 import org.joda.time.LocalDate;
 import org.joda.time.LocalDateTime;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -173,6 +174,10 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
                             CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element);
                     baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue()).value(repeatsOnDay)
                             .notBlank().inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
+                } else if (CalendarFrequencyType.fromInt(frequency).isMonthly()) {
+                    CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
+                            CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_NTH_DAY_OF_MONTH.getValue(),
+                            CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_LAST_WEEKDAY_OF_MONTH.getValue(), element, this.fromApiJsonHelper);
                 }
             }
         }
@@ -305,11 +310,17 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
                             .integerGreaterThanZero();
                 }
 
+                if (CalendarFrequencyType.fromInt(frequency).isWeekly()) {
                 if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element)) {
                     final Integer repeatsOnDay = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
                             CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element);
                     baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue()).value(repeatsOnDay)
                             .notBlank().inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
+                    }
+                } else if (CalendarFrequencyType.fromInt(frequency).isMonthly()) {
+                    CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
+                            CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_NTH_DAY_OF_MONTH.getValue(),
+                            CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_LAST_WEEKDAY_OF_MONTH.getValue(), element, this.fromApiJsonHelper);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformService.java
index 1c95c77..c670643 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformService.java
@@ -33,5 +33,6 @@ public interface CalendarDropdownReadPlatformService {
     List<EnumOptionData> retrieveCalendarFrequencyTypeOptions();
 
     List<EnumOptionData> retrieveCalendarWeekDaysTypeOptions();
+    List<EnumOptionData> retrieveCalendarFrequencyNthDayTypeOptions();
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformServiceImpl.java
index 713a38c..7881180 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarDropdownReadPlatformServiceImpl.java
@@ -55,4 +55,8 @@ public class CalendarDropdownReadPlatformServiceImpl implements CalendarDropdown
     public List<EnumOptionData> retrieveCalendarWeekDaysTypeOptions() {
         return CalendarEnumerations.calendarWeekDaysType(CalendarWeekDaysType.values());
     }
+    @Override
+    public List<EnumOptionData> retrieveCalendarFrequencyNthDayTypeOptions() {
+        return CalendarEnumerations.calendarFrequencyNthDayType();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarEnumerations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarEnumerations.java
index e96dba6..15c74ec 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarEnumerations.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/service/CalendarEnumerations.java
@@ -19,6 +19,7 @@
 package org.apache.fineract.portfolio.calendar.service;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
@@ -27,6 +28,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
 import org.apache.fineract.portfolio.calendar.domain.CalendarRemindBy;
 import org.apache.fineract.portfolio.calendar.domain.CalendarType;
 import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
+import org.apache.fineract.portfolio.common.domain.NthDayType;
 
 public class CalendarEnumerations {
 
@@ -86,8 +88,11 @@ public class CalendarEnumerations {
     }
 
     public static EnumOptionData calendarFrequencyType(final CalendarFrequencyType calendarFrequencyType) {
-        final EnumOptionData optionData = new EnumOptionData(calendarFrequencyType.getValue().longValue(), calendarFrequencyType.getCode(),
+        EnumOptionData optionData = null;
+        if (!calendarFrequencyType.isInvalid()) {
+            optionData = new EnumOptionData(calendarFrequencyType.getValue().longValue(), calendarFrequencyType.getCode(),
                 calendarFrequencyType.toString());
+        }
         return optionData;
     }
 
@@ -106,8 +111,11 @@ public class CalendarEnumerations {
     }
 
     public static EnumOptionData calendarWeekDaysType(final CalendarWeekDaysType calendarWeekDaysType) {
-        final EnumOptionData optionData = new EnumOptionData(calendarWeekDaysType.getValue().longValue(), calendarWeekDaysType.getCode(),
+        EnumOptionData optionData = null;
+        if (!calendarWeekDaysType.isInvalid()) {
+            optionData = new EnumOptionData(calendarWeekDaysType.getValue().longValue(), calendarWeekDaysType.getCode(),
                 calendarWeekDaysType.toString());
+        }
         return optionData;
     }
 
@@ -120,4 +128,19 @@ public class CalendarEnumerations {
         }
         return optionDatas;
     }
+    public static EnumOptionData calendarFrequencyNthDayType(final int id) {
+        return calendarFrequencyNthDayType(NthDayType.fromInt(id));
+    }
+    public static EnumOptionData calendarFrequencyNthDayType(final NthDayType calendarFrequencyNthDayType) {
+        final EnumOptionData optionData = new EnumOptionData(calendarFrequencyNthDayType.getValue().longValue(), calendarFrequencyNthDayType.getCode(),
+                calendarFrequencyNthDayType.toString());
+        return optionData;
+    }
+    public static List<EnumOptionData> calendarFrequencyNthDayType() {
+        final List<EnumOptionData> optionDatas = Arrays.asList(calendarFrequencyNthDayType(NthDayType.ONE),
+        		calendarFrequencyNthDayType(NthDayType.TWO), calendarFrequencyNthDayType(NthDayType.THREE),
+        		calendarFrequencyNthDayType(NthDayType.FOUR), calendarFrequencyNthDayType(NthDayType.LAST), 
+        		calendarFrequencyNthDayType(NthDayType.ONDAY));
+        return optionDatas;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/763cf18b/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 3b5c37c..c9e7068 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
@@ -89,6 +89,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
             final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarUtils.getFrequency(recurrence));
             final Integer interval = new Integer(CalendarUtils.getInterval(recurrence));
             final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarUtils.getRepeatsOnDay(recurrence));
+            final EnumOptionData repeatsOnNthDayOfMonth = CalendarEnumerations.calendarFrequencyNthDayType(CalendarUtils.getRepeatsOnNthDayOfMonth(recurrence));
             final Integer remindById = rs.getInt("remindById");
             EnumOptionData remindBy = null;
             if (remindById != null && remindById != 0) {
@@ -100,7 +101,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
             if (startDate != null && recurrence != null) {
                 humanReadable = CalendarUtils.getRRuleReadable(startDate, recurrence);
             }
-
+            Integer monthOnDay = CalendarUtils.getMonthOnDay(recurrence);
             final LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
             final LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate");
             final Long createdByUserId = rs.getLong("creatingUserId");
@@ -110,9 +111,9 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
             final LocalTime meetingTime = JdbcSupport.getLocalTime(rs,"meetingTime");
 
             return CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
-                    duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
+                    duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy, firstReminder, secondReminder,
                     humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
-                    lastUpdatedByUserName,meetingTime);
+                    lastUpdatedByUserName,meetingTime, monthOnDay);
         }
     }
 
@@ -479,6 +480,8 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
             final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarUtils.getFrequency(recurrence));
             final Integer interval = new Integer(CalendarUtils.getInterval(recurrence));
             final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarUtils.getRepeatsOnDay(recurrence));
+            final EnumOptionData repeatsOnNthDayOfMonth = CalendarEnumerations.calendarFrequencyNthDayType(CalendarUtils
+                    .getRepeatsOnNthDayOfMonth(recurrence));
             final Integer remindById = rs.getInt("remindById");
             EnumOptionData remindBy = null;
             if (remindById != null && remindById != 0) {
@@ -498,11 +501,12 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
             final Long lastUpdatedByUserId = null;
             final String lastUpdatedByUserName = null;
             final LocalTime meetingTime = null;
+            Integer monthOnDay = CalendarUtils.getMonthOnDay(recurrence);
 
             return CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
-                    duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
-                    humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
-                    lastUpdatedByUserName, meetingTime);
+                    duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy,
+                    firstReminder, secondReminder, humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName,
+                    lastUpdatedByUserId, lastUpdatedByUserName, meetingTime, monthOnDay);
         }
     }