http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
index c1f91ea..0746522 100644
--- 
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
@@ -21,7 +21,9 @@ package 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
 import java.math.BigDecimal;
 import java.math.MathContext;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
@@ -192,6 +194,25 @@ public final class LoanApplicationTerms {
     private final boolean isSkipRepaymentOnFirstDayOfMonth;
 
     private final HolidayDetailDTO holidayDetailDTO;
+    
+    private final Set<Integer> periodNumbersApplicableForPrincipalGrace = new 
HashSet<>();
+    
+    private final Set<Integer> periodNumbersApplicableForInterestGrace = new 
HashSet<>();
+    
+    
+    // used for FLAT loans when interest rate changed 
+    private Integer excludePeriodsForCalculation = 0;
+    private Money totalPrincipalAccountedForInterestCalcualtion;
+    
+    
+    //used for FLAT loans generation on modifying terms 
+    private Money totalPrincipalAccounted;
+    private Money totalInterestAccounted;
+    private int periodsCompleted = 0;
+    private int extraPeriods = 0;
+    
+    
+    
 
     public static LoanApplicationTerms assembleFrom(final ApplicationCurrency 
currency, final Integer loanTermFrequency,
             final PeriodFrequencyType loanTermPeriodFrequencyType, final 
Integer numberOfRepayments, final Integer repaymentEvery,
@@ -482,6 +503,12 @@ public final class LoanApplicationTerms {
         this.isInterestChargedFromDateSameAsDisbursalDateEnabled = 
isInterestChargedFromDateSameAsDisbursalDateEnabled;
         this.holidayDetailDTO = holidayDetailDTO;
         this.allowCompoundingOnEod = allowCompoundingOnEod;
+        Integer periodNumber = 1;
+        updatePeriodNumberApplicableForPrincipalOrInterestGrace(periodNumber);
+        updateRecurringMoratoriumOnPrincipalPeriods(periodNumber);
+        this.totalPrincipalAccountedForInterestCalcualtion = principal.zero();
+        this.totalInterestAccounted = principal.zero();
+        this.totalPrincipalAccounted = principal.zero();
     }
 
     public Money adjustPrincipalIfLastRepaymentPeriod(final Money 
principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -706,7 +733,8 @@ public final class LoanApplicationTerms {
         switch (this.interestMethod) {
             case FLAT:
                 final BigDecimal interestRateForLoanTerm = 
calculateFlatInterestRateForLoanTerm(calculator, mc);
-                totalInterestDue = 
this.principal.multiplyRetainScale(interestRateForLoanTerm, 
mc.getRoundingMode());
+                totalInterestDue = 
this.principal.minus(totalPrincipalAccountedForInterestCalcualtion).multiplyRetainScale(interestRateForLoanTerm,
+                        mc.getRoundingMode());
 
             break;
             case DECLINING_BALANCE:
@@ -715,10 +743,6 @@ public final class LoanApplicationTerms {
             break;
         }
 
-        if (this.totalInterestDue != null) {
-            totalInterestDue = this.totalInterestDue;
-        }
-
         return totalInterestDue;
     }
 
@@ -844,13 +868,19 @@ public final class LoanApplicationTerms {
     private Money calculateTotalInterestPerInstallmentWithoutGrace(final 
PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) {
 
         final Money totalInterestForLoanTerm = 
calculateTotalFlatInterestDueWithoutGrace(calculator, mc);
-
-        return 
totalInterestForLoanTerm.dividedBy(Long.valueOf(this.actualNumberOfRepayments), 
mc.getRoundingMode());
+        Money interestPerInstallment = 
totalInterestForLoanTerm.dividedBy(Long.valueOf(this.actualNumberOfRepayments) 
- defaultToZeroIfNull(this.excludePeriodsForCalculation), mc.getRoundingMode());
+        if (this.excludePeriodsForCalculation < this.periodsCompleted) {
+            Money interestLeft = 
this.totalInterestDue.minus(this.totalInterestAccounted);
+            interestPerInstallment = 
interestLeft.dividedBy(Long.valueOf(this.actualNumberOfRepayments)
+                    - defaultToZeroIfNull(this.periodsCompleted), 
mc.getRoundingMode());
+        }
+        
+        return interestPerInstallment;
     }
 
     private Money calculateTotalPrincipalPerPeriodWithoutGrace(final 
MathContext mc, final int periodNumber) {
         final int totalRepaymentsWithCapitalPayment = 
calculateNumberOfRepaymentsWithPrincipalPayment();
-        Money principalPerPeriod = 
this.principal.dividedBy(totalRepaymentsWithCapitalPayment, 
mc.getRoundingMode()).plus(
+        Money principalPerPeriod = 
this.principal.minus(totalPrincipalAccounted).dividedBy(totalRepaymentsWithCapitalPayment,
 mc.getRoundingMode()).plus(
                 this.adjustPrincipalForFlatLoans);
         if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
             principalPerPeriod = principalPerPeriod.zero();
@@ -906,11 +936,30 @@ public final class LoanApplicationTerms {
 
             final Money totalInterestFree = 
interestPerGracePeriod.multipliedBy(getInterestChargingGrace());
             final Money realTotalInterestForLoan = 
totalInterestForLoanTerm.minus(totalInterestFree);
-
-            final Integer interestPaymentDuePeriods = 
calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.actualNumberOfRepayments);
-
+            
+            
+            
+            Integer interestPaymentDuePeriods = 
calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments,
+                    this.excludePeriodsForCalculation);
             interestForInstallment = realTotalInterestForLoan
                     .dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods), 
mc.getRoundingMode());
+            if (this.excludePeriodsForCalculation < this.periodsCompleted) {
+                Money interestLeft = 
this.totalInterestDue.minus(this.totalInterestAccounted);
+                Integer interestDuePeriods = 
calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments,
+                        this.periodsCompleted);
+                interestForInstallment = 
interestLeft.dividedBy(Long.valueOf(interestDuePeriods), mc.getRoundingMode());
+            }
+            if(!this.periodNumbersApplicableForInterestGrace.isEmpty()){
+                int periodsElapsed = 
calculateLastInterestGracePeriod(periodNumber);
+                if (periodsElapsed > this.excludePeriodsForCalculation && 
periodsElapsed > this.periodsCompleted) {
+                    Money interestLeft = 
this.totalInterestDue.minus(this.totalInterestAccounted);
+                    Integer interestDuePeriods = 
calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments,
+                            periodsElapsed);
+                    interestForInstallment = 
interestLeft.dividedBy(Long.valueOf(interestDuePeriods), mc.getRoundingMode());
+                }
+            }
+            
+
         }
 
         return interestForInstallment;
@@ -1032,24 +1081,46 @@ public final class LoanApplicationTerms {
 
     private int calculateNumberOfRepaymentsWithPrincipalPayment() {
         int numPeriods = 
calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments,
-                this.getRecurringMoratoriumOnPrincipalPeriods(), 
this.getPrincipalGrace(), 0);
+                this.periodsCompleted);
+//        numPeriods = numPeriods - this.periodsCompleted;
         return numPeriods;
     }
-
-    private Integer 
calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(final Integer 
totalNumberOfRepaymentPeriods) {
-        return totalNumberOfRepaymentPeriods - 
Math.max(getInterestChargingGrace(), getInterestPaymentGrace());
+    
+    private Integer calculateNumberOfRemainingInterestPaymentPeriods(final 
Integer totalNumberOfRepaymentPeriods, int periodsElapsed) {
+        int principalFeePeriods = 0;
+        for (Integer intNumber : this.periodNumbersApplicableForInterestGrace) 
{
+            if (intNumber > periodsElapsed) {
+                principalFeePeriods++;
+            }
+        }
+        Integer periodsRemaining = totalNumberOfRepaymentPeriods - 
periodsElapsed - principalFeePeriods;
+        return periodsRemaining;
+    }
+    
+    private Integer calculateLastInterestGracePeriod(int periodNumber){
+        int lastGracePeriod = 0;
+        for (Integer grace : this.periodNumbersApplicableForInterestGrace) {
+            if(grace < periodNumber && lastGracePeriod < grace){
+                lastGracePeriod = grace;
+            }
+        }
+        return lastGracePeriod;
     }
 
     public boolean isPrincipalGraceApplicableForThisPeriod(final int 
periodNumber) {
-        if (this.getRecurringMoratoriumOnPrincipalPeriods() > 0) {
-            return ((periodNumber > 0 && periodNumber <= getPrincipalGrace()) 
|| (periodNumber > 0 && (((periodNumber - getPrincipalGrace()) % (this
-                    .getRecurringMoratoriumOnPrincipalPeriods() + 1)) != 1)));
+        boolean isPrincipalGraceApplicableForThisPeriod = false;
+        if 
(this.periodNumbersApplicableForPrincipalGrace.contains(periodNumber)) {
+            isPrincipalGraceApplicableForThisPeriod = true;
         }
-        return periodNumber > 0 && periodNumber <= getPrincipalGrace();
+        return isPrincipalGraceApplicableForThisPeriod;
     }
 
-    private boolean isInterestPaymentGraceApplicableForThisPeriod(final int 
periodNumber) {
-        return periodNumber > 0 && periodNumber <= getInterestPaymentGrace();
+    public boolean isInterestPaymentGraceApplicableForThisPeriod(final int 
periodNumber) {
+        boolean isInterestPaymentGraceApplicableForThisPeriod = false;
+        if 
(this.periodNumbersApplicableForInterestGrace.contains(periodNumber)) {
+            isInterestPaymentGraceApplicableForThisPeriod = true;
+        }
+        return isInterestPaymentGraceApplicableForThisPeriod;
     }
 
     private boolean isFirstPeriodAfterInterestPaymentGracePeriod(final int 
periodNumber) {
@@ -1099,7 +1170,7 @@ public final class LoanApplicationTerms {
             final double principalDouble = 
balance.getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue();
 
             final Integer periodsRemaining = 
calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments,
-                    this.getRecurringMoratoriumOnPrincipalPeriods(), 
this.getPrincipalGrace(), periodsElapsed);
+                    periodsElapsed);
 
             double installmentAmount = 
FinanicalFunctions.pmt(periodicInterestRate.doubleValue(), 
periodsRemaining.doubleValue(),
                     principalDouble, futureValue, false);
@@ -1165,7 +1236,7 @@ public final class LoanApplicationTerms {
         Money principal = this.principal;
         if (this.fixedPrincipalAmount == null) {
             final Integer numberOfPrincipalPaymentPeriods = 
calculateNumberOfRemainingPrincipalPaymentPeriods(
-                    this.actualNumberOfRepayments, 
this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), 
periodNumber);
+                    this.actualNumberOfRepayments, periodNumber);
             principal = 
this.principal.dividedBy(numberOfPrincipalPaymentPeriods, mc.getRoundingMode());
             this.fixedPrincipalAmount = principal.getAmount();
         }
@@ -1179,21 +1250,19 @@ public final class LoanApplicationTerms {
 
     public void updateFixedPrincipalAmount(final MathContext mc, final int 
periodNumber, final Money outstandingAmount) {
         final Integer numberOfPrincipalPaymentPeriods = 
calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments,
-                this.getRecurringMoratoriumOnPrincipalPeriods(), 
this.getPrincipalGrace(), periodNumber - 1);
+                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);
+    private Integer calculateNumberOfRemainingPrincipalPaymentPeriods(final 
Integer totalNumberOfRepaymentPeriods, int periodsElapsed) {
+        int principalFeePeriods = 0;
+        for (Integer intNumber : 
this.periodNumbersApplicableForPrincipalGrace) {
+            if (intNumber > periodsElapsed) {
+                principalFeePeriods++;
+            }
         }
+        Integer periodsRemaining = totalNumberOfRepaymentPeriods - 
periodsElapsed - principalFeePeriods;
         return periodsRemaining;
     }
 
@@ -1469,10 +1538,7 @@ public final class LoanApplicationTerms {
     }
 
     public void updateTotalInterestDue(Money totalInterestDue) {
-
-        if (totalInterestDue != null) {
-            this.totalInterestDue = totalInterestDue;
-        }
+        this.totalInterestDue = totalInterestDue;
     }
 
     public ApplicationCurrency getApplicationCurrency() {
@@ -1576,4 +1642,81 @@ public final class LoanApplicationTerms {
         }
         return disbursedAmount;
     }
+    
+    public void updatePeriodNumberApplicableForPrincipalOrInterestGrace(final 
Integer periodsApplicationForGrace) {
+        int applicablePeriodNumber = periodsApplicationForGrace;
+        int graceOnPrincipal = defaultToZeroIfNull(this.principalGrace);
+        int graceOnInterest = defaultToZeroIfNull(this.interestPaymentGrace);
+
+        while (graceOnPrincipal > 0 || graceOnInterest > 0) {
+            if (graceOnPrincipal > 0) {
+                
this.periodNumbersApplicableForPrincipalGrace.add(applicablePeriodNumber);
+            }
+            if (graceOnInterest > 0) {
+                
this.periodNumbersApplicableForInterestGrace.add(applicablePeriodNumber);
+            }
+            applicablePeriodNumber++;
+            graceOnPrincipal--;
+            graceOnInterest--;
+        }
+    }
+    
+    /**
+     * set the value to zero if the provided value is null
+     * 
+     * @return integer value equal/greater than 0
+     **/
+    private Integer defaultToZeroIfNull(Integer value) {
+
+        return (value != null) ? value : 0;
+    }
+    
+    public void updateExcludePeriodsForCalculation(Integer 
excludePeriodsForCalculation){
+        this.excludePeriodsForCalculation = excludePeriodsForCalculation;
+        this.extraPeriods = 0;
+    }
+    
+    public Integer getActualNoOfRepaymnets() {
+        return this.actualNumberOfRepayments;
+    }
+    
+    public Money getTotalInterestDue() {
+        return this.totalInterestDue;
+    }
+    
+    private void updateRecurringMoratoriumOnPrincipalPeriods(Integer 
periodNumber) {
+        Boolean isPrincipalGraceApplicableForThisPeriod = false;
+        Integer numberOfRepayments = this.actualNumberOfRepayments;
+        if (this.getRecurringMoratoriumOnPrincipalPeriods() > 0) {
+            while (numberOfRepayments > 0) {
+                isPrincipalGraceApplicableForThisPeriod = ((periodNumber > 0 
&& periodNumber <= getPrincipalGrace()) || (periodNumber > 0 && (((periodNumber 
- getPrincipalGrace()) % (this
+                        .getRecurringMoratoriumOnPrincipalPeriods() + 1)) != 
1)));
+                if (isPrincipalGraceApplicableForThisPeriod) {
+                    
this.periodNumbersApplicableForPrincipalGrace.add(periodNumber);
+                }
+                numberOfRepayments--;
+                periodNumber++;
+            }
+        }
+
+    }
+
+    
+    public void setTotalPrincipalAccounted(Money totalPrincipalAccounted) {
+        this.totalPrincipalAccountedForInterestCalcualtion = 
totalPrincipalAccounted;
+    }
+    
+    
+    //Used for FLAT loans to calculate principal and interest per installment  
+    public void updateAccountedTillPeriod(int periodNumber,  Money 
totalPrincipalAccounted,Money totalInterestAccounted, int extendPeriods){
+        this.periodsCompleted = periodNumber;
+        this.totalPrincipalAccounted = totalPrincipalAccounted;
+        this.totalInterestAccounted = totalInterestAccounted;
+        this.extraPeriods = this.extraPeriods + extendPeriods;
+    }
+    
+    public void updateTotalInterestAccounted(Money totalInterestAccounted){
+        this.totalInterestAccounted = totalInterestAccounted;
+    }
+    
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
index ae67451..9583ac4 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
@@ -19,22 +19,15 @@
 package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
 
 import java.math.MathContext;
-import java.util.List;
 import java.util.Set;
 
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
 import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
-import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
-import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
 import org.joda.time.LocalDate;
 
 public interface LoanScheduleGenerator {
@@ -42,18 +35,12 @@ public interface LoanScheduleGenerator {
     LoanScheduleModel generate(MathContext mc, LoanApplicationTerms 
loanApplicationTerms, Set<LoanCharge> loanCharges,
             final HolidayDetailDTO holidayDetailDTO);
 
-    LoanScheduleDTO rescheduleNextInstallments(MathContext mc, 
LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges,
-            final HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> 
transactions,
-            LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor,
-            List<LoanRepaymentScheduleInstallment> 
repaymentScheduleInstallments, LocalDate rescheduleFrom);
+    LoanScheduleDTO rescheduleNextInstallments(MathContext mc, 
LoanApplicationTerms loanApplicationTerms, Loan loan,
+            final HolidayDetailDTO holidayDetailDTO, 
LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor,
+            LocalDate rescheduleFrom);
 
     LoanRepaymentScheduleInstallment 
calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
-            LoanApplicationTerms loanApplicationTerms, MathContext mc, 
Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO,
-            List<LoanTransaction> loanTransactions, 
LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor,
-            List<LoanRepaymentScheduleInstallment> 
repaymentScheduleInstallments);
+            LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan 
loan, HolidayDetailDTO holidayDetailDTO,
+            LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor);
 
-    LoanRescheduleModel reschedule(final MathContext mathContext, final 
LoanRescheduleRequest loanRescheduleRequest,
-            final ApplicationCurrency applicationCurrency, final 
HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance,
-            CalendarInstance compoundingCalendarInstance, final Calendar 
loanCalendar, FloatingRateDTO floatingRateDTO,
-            final boolean isSkipRepaymentonmonthFirst, final Integer 
numberofdays);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/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 ac4a368..9565ff3 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
@@ -86,7 +86,6 @@ import 
org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException;
 import 
org.apache.fineract.portfolio.loanaccount.exception.MinDaysBetweenDisbursalAndFirstRepaymentViolationException;
@@ -621,9 +620,8 @@ public class LoanScheduleAssembler {
     }
 
     public LoanScheduleModel assembleForInterestRecalculation(final 
LoanApplicationTerms loanApplicationTerms, final Long officeId,
-            List<LoanTransaction> transactions, final Set<LoanCharge> 
loanCharges,
-            final LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor,
-            final List<LoanRepaymentScheduleInstallment> 
repaymentScheduleInstallments, final LocalDate rescheduleFrom) {
+            Loan loan, final LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor,
+            final LocalDate rescheduleFrom) {
         final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
         final MathContext mc = new MathContext(8, roundingMode);
         final boolean isHolidayEnabled = 
this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
@@ -634,15 +632,13 @@ public class LoanScheduleAssembler {
 
         final LoanScheduleGenerator loanScheduleGenerator = 
this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
         HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, 
holidays, workingDays);
-        return loanScheduleGenerator.rescheduleNextInstallments(mc, 
loanApplicationTerms, loanCharges, detailDTO, transactions,
-                loanRepaymentScheduleTransactionProcessor, 
repaymentScheduleInstallments, rescheduleFrom).getLoanScheduleModel();
+        return loanScheduleGenerator.rescheduleNextInstallments(mc, 
loanApplicationTerms, loan, detailDTO,
+                loanRepaymentScheduleTransactionProcessor, 
rescheduleFrom).getLoanScheduleModel();
     }
 
     public LoanRepaymentScheduleInstallment 
calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
-            LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> 
loanCharges, final Long officeId,
-            List<LoanTransaction> loanTransactions,
-            final LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor,
-            final List<LoanRepaymentScheduleInstallment> 
repaymentScheduleInstallments) {
+            LoanApplicationTerms loanApplicationTerms, Loan loan, final Long 
officeId,
+            final LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor) {
         final LoanScheduleGenerator loanScheduleGenerator = 
this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
         final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
         final MathContext mc = new MathContext(8, roundingMode);
@@ -653,8 +649,8 @@ public class LoanScheduleAssembler {
         final WorkingDays workingDays = this.workingDaysRepository.findOne();
         HolidayDetailDTO holidayDetailDTO = new 
HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
 
-        return loanScheduleGenerator.calculatePrepaymentAmount(currency, 
onDate, loanApplicationTerms, mc, loanCharges, holidayDetailDTO,
-                loanTransactions, loanRepaymentScheduleTransactionProcessor, 
repaymentScheduleInstallments);
+        return loanScheduleGenerator.calculatePrepaymentAmount(currency, 
onDate, loanApplicationTerms, mc, loan, holidayDetailDTO,
+                loanRepaymentScheduleTransactionProcessor);
 
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
index 41e8313..a8ea977 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
@@ -171,9 +171,8 @@ public class LoanScheduleCalculationPlatformServiceImpl 
implements LoanScheduleC
         }
         LoanApplicationTerms loanApplicationTerms = 
constructLoanApplicationTerms(loan);
         LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = 
this.loanScheduleAssembler.calculatePrepaymentAmount(currency,
-                today, loanApplicationTerms, loan.charges(), 
loan.getOfficeId(),
-                
loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals(), 
loanRepaymentScheduleTransactionProcessor,
-                loan.getRepaymentScheduleInstallments());
+                today, loanApplicationTerms, loan, loan.getOfficeId(),
+                loanRepaymentScheduleTransactionProcessor);
         Money totalAmount = 
totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
                 
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
         Money interestDue = Money.zero(currency);
@@ -194,8 +193,7 @@ public class LoanScheduleCalculationPlatformServiceImpl 
implements LoanScheduleC
         }
 
         LoanScheduleModel model = 
this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms,
 loan.getOfficeId(),
-                modifiedTransactions, loan.charges(), 
loanRepaymentScheduleTransactionProcessor, 
loan.getRepaymentScheduleInstallments(),
-                loan.fetchInterestRecalculateFromDate());
+                loan, loanRepaymentScheduleTransactionProcessor, 
loan.fetchInterestRecalculateFromDate());
         LoanScheduleData scheduleDate = model.toData();
         Collection<LoanSchedulePeriodData> periodDatas = 
scheduleDate.getPeriods();
         for (LoanSchedulePeriodData periodData : periodDatas) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
index 2094a05..591e21b 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
@@ -42,9 +42,9 @@ import 
org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSeria
 import 
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
 import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestData;
-import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanReschedulePreviewPlatformService;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestReadPlatformService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -108,14 +108,14 @@ public class RescheduleLoansApiResource {
         final ApiRequestJsonSerializationSettings settings = 
this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
 
         if (compareIgnoreCase(command, "previewLoanReschedule")) {
-            final LoanRescheduleModel loanRescheduleModel = 
this.loanReschedulePreviewPlatformService.previewLoanReschedule(scheduleId);
+            final LoanScheduleModel loanRescheduleModel = 
this.loanReschedulePreviewPlatformService.previewLoanReschedule(scheduleId);
 
             return this.loanRescheduleToApiJsonSerializer.serialize(settings, 
loanRescheduleModel.toData(), new HashSet<String>());
         }
 
         final LoanRescheduleRequestData loanRescheduleRequestData = 
this.loanRescheduleRequestReadPlatformService
                 .readLoanRescheduleRequest(scheduleId);
-
+        
         return 
this.loanRescheduleRequestToApiJsonSerializer.serialize(settings, 
loanRescheduleRequestData);
     }
 
@@ -170,4 +170,20 @@ public class RescheduleLoansApiResource {
     private boolean compareIgnoreCase(String firstString, String secondString) 
{
         return StringUtils.isNotBlank(firstString) && 
firstString.trim().equalsIgnoreCase(secondString);
     }
+    
+    /*@GET
+    @Path("{scheduleId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String retrieveTemplate(@Context final UriInfo uriInfo) {
+
+        
this.platformSecurityContext.authenticatedUser().validateHasReadPermission(RescheduleLoansApiConstants.ENTITY_NAME);
+        final ApiRequestJsonSerializationSettings settings = 
this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+
+        LoanRescheduleRequestData loanRescheduleReasons = null;
+        loanRescheduleReasons = this.loanRescheduleRequestReadPlatformService
+                
.retrieveAllRescheduleReasons(RescheduleLoansApiConstants.LOAN_RESCHEDULE_REASON);
+
+        return 
this.loanRescheduleRequestToApiJsonSerializer.serialize(settings, 
loanRescheduleReasons);
+    }*/
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
index b74388c..2a6dfbd 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
@@ -18,10 +18,10 @@
  */
 package org.apache.fineract.portfolio.loanaccount.rescheduleloan.data;
 
-import java.math.BigDecimal;
 import java.util.Collection;
 
 import org.apache.fineract.infrastructure.codes.data.CodeValueData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.joda.time.LocalDate;
 
 /**
@@ -36,59 +36,55 @@ public class LoanRescheduleRequestData {
     private final String loanAccountNumber;
     private final LoanRescheduleRequestStatusEnumData statusEnum;
     private final Integer rescheduleFromInstallment;
-    private final Integer graceOnPrincipal;
-    private final Integer graceOnInterest;
     private final LocalDate rescheduleFromDate;
-    private final Integer extraTerms;
-    private final BigDecimal interestRate;
     private final Boolean recalculateInterest;
     private final CodeValueData rescheduleReasonCodeValue;
     private final LoanRescheduleRequestTimelineData timeline;
     private final String rescheduleReasonComment;
-    private final LocalDate adjustedDueDate;
+    @SuppressWarnings("unused")
     private final Collection<CodeValueData> rescheduleReasons;
+    @SuppressWarnings("unused")
+    private final Collection<LoanTermVariationsData> loanTermVariationsData;
     
     /**
      * LoanRescheduleRequestData constructor
+     * @param loanTermVariationsData TODO
      **/
     private LoanRescheduleRequestData(Long id, Long loanId, 
LoanRescheduleRequestStatusEnumData statusEnum,
-            Integer rescheduleFromInstallment, Integer graceOnPrincipal, 
Integer graceOnInterest, LocalDate rescheduleFromDate,
-            LocalDate adjustedDueDate, Integer extraTerms, BigDecimal 
interestRate, CodeValueData rescheduleReasonCodeValue,
+            Integer rescheduleFromInstallment, LocalDate rescheduleFromDate, 
CodeValueData rescheduleReasonCodeValue,
             String rescheduleReasonComment, LoanRescheduleRequestTimelineData 
timeline, final String clientName,
-            final String loanAccountNumber, final Long clientId, final Boolean 
recalculateInterest, Collection<CodeValueData> rescheduleReasons) {
+            final String loanAccountNumber, final Long clientId, final Boolean 
recalculateInterest,
+            Collection<CodeValueData> rescheduleReasons, final 
Collection<LoanTermVariationsData> loanTermVariationsData) {
 
         this.id = id;
         this.loanId = loanId;
         this.statusEnum = statusEnum;
         this.rescheduleFromInstallment = rescheduleFromInstallment;
-        this.graceOnPrincipal = graceOnPrincipal;
-        this.graceOnInterest = graceOnInterest;
         this.rescheduleFromDate = rescheduleFromDate;
-        this.extraTerms = extraTerms;
-        this.interestRate = interestRate;
         this.rescheduleReasonCodeValue = rescheduleReasonCodeValue;
         this.rescheduleReasonComment = rescheduleReasonComment;
-        this.adjustedDueDate = adjustedDueDate;
         this.timeline = timeline;
         this.clientName = clientName;
         this.loanAccountNumber = loanAccountNumber;
         this.clientId = clientId;
         this.recalculateInterest = recalculateInterest;
         this.rescheduleReasons = rescheduleReasons ;
+        this.loanTermVariationsData = loanTermVariationsData;
     }
 
     /**
+     * @param loanTermVariationsData TODO
      * @return an instance of the LoanRescheduleRequestData class
      **/
     public static LoanRescheduleRequestData instance(Long id, Long loanId, 
LoanRescheduleRequestStatusEnumData statusEnum,
-            Integer rescheduleFromInstallment, Integer graceOnPrincipal, 
Integer graceOnInterest, LocalDate rescheduleFromDate,
-            LocalDate adjustedDueDate, Integer extraTerms, BigDecimal 
interestRate, CodeValueData rescheduleReasonCodeValue,
+            Integer rescheduleFromInstallment, LocalDate rescheduleFromDate, 
CodeValueData rescheduleReasonCodeValue,
             String rescheduleReasonComment, LoanRescheduleRequestTimelineData 
timeline, final String clientName,
-            final String loanAccountNumber, final Long clientId, final Boolean 
recalculateInterest, Collection<CodeValueData> rescheduleReasons) {
+            final String loanAccountNumber, final Long clientId, final Boolean 
recalculateInterest,
+            Collection<CodeValueData> rescheduleReasons, final 
Collection<LoanTermVariationsData> loanTermVariationsData) {
 
-        return new LoanRescheduleRequestData(id, loanId, statusEnum, 
rescheduleFromInstallment, graceOnPrincipal, graceOnInterest,
-                rescheduleFromDate, adjustedDueDate, extraTerms, interestRate, 
rescheduleReasonCodeValue, rescheduleReasonComment,
-                timeline, clientName, loanAccountNumber, clientId, 
recalculateInterest, rescheduleReasons);
+        return new LoanRescheduleRequestData(id, loanId, statusEnum, 
rescheduleFromInstallment, rescheduleFromDate,
+                rescheduleReasonCodeValue, rescheduleReasonComment, timeline, 
clientName, loanAccountNumber, clientId, recalculateInterest,
+                rescheduleReasons, loanTermVariationsData);
     }
 
     /**
@@ -120,20 +116,6 @@ public class LoanRescheduleRequestData {
     }
 
     /**
-     * @return the graceOnPrincipal
-     */
-    public Integer getGraceOnPrincipal() {
-        return graceOnPrincipal;
-    }
-
-    /**
-     * @return the graceOnInterest
-     */
-    public Integer getGraceOnInterest() {
-        return graceOnInterest;
-    }
-
-    /**
      * @return the reschedule from date
      */
     public LocalDate getRescheduleFromDate() {
@@ -141,20 +123,6 @@ public class LoanRescheduleRequestData {
     }
 
     /**
-     * @return the extraTerms
-     */
-    public Integer getExtraTerms() {
-        return extraTerms;
-    }
-
-    /**
-     * @return the interestRate
-     */
-    public BigDecimal getInterestRate() {
-        return interestRate;
-    }
-
-    /**
      * @return the rescheduleReasonCodeValueId
      */
     public CodeValueData getRescheduleReasonCodeValueId() {
@@ -176,13 +144,6 @@ public class LoanRescheduleRequestData {
     }
 
     /**
-     * @return the adjustedDueDate
-     */
-    public LocalDate getAdjustedDueDate() {
-        return adjustedDueDate;
-    }
-
-    /**
      * @return the clientName
      */
     public String getClientName() {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
index 5254187..67e0f80 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
@@ -32,10 +32,8 @@ import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
-import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestReadPlatformService;
 import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -47,13 +45,10 @@ import com.google.gson.reflect.TypeToken;
 public class LoanRescheduleRequestDataValidator {
 
     private final FromJsonHelper fromJsonHelper;
-    private final LoanRescheduleRequestReadPlatformService 
loanRescheduleRequestReadPlatformService;
 
     @Autowired
-    public LoanRescheduleRequestDataValidator(FromJsonHelper fromJsonHelper,
-            LoanRescheduleRequestReadPlatformService 
loanRescheduleRequestReadPlatformService) {
+    public LoanRescheduleRequestDataValidator(FromJsonHelper fromJsonHelper) {
         this.fromJsonHelper = fromJsonHelper;
-        this.loanRescheduleRequestReadPlatformService = 
loanRescheduleRequestReadPlatformService;
     }
 
     /**
@@ -159,21 +154,8 @@ public class LoanRescheduleRequestDataValidator {
                         
.failWithCode("repayment.schedule.installment.obligation.met", "Repayment 
schedule installment obligation met");
             }
 
-            if (installment != null && installment.isPartlyPaid()) {
-                
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)
-                        
.failWithCode("repayment.schedule.installment.partly.paid", "Repayment schedule 
installment is partly paid");
-            }
         }
 
-        if (loanId != null) {
-            List<LoanRescheduleRequestData> loanRescheduleRequestData = 
this.loanRescheduleRequestReadPlatformService
-                    .readLoanRescheduleRequests(loanId, 
LoanStatus.APPROVED.getValue());
-
-            if (loanRescheduleRequestData.size() > 0) {
-                
dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled",
-                        "The loan can only be rescheduled once.");
-            }
-        }
         if(loan.isMultiDisburmentLoan()) {
             
dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(RescheduleLoansApiConstants.resheduleForMultiDisbursementNotSupportedErrorCode,
                     "Loan rescheduling is not supported for multidisbursement 
loans");
@@ -232,7 +214,6 @@ public class LoanRescheduleRequestDataValidator {
         final Loan loan = loanRescheduleRequest.getLoan();
 
         if (loan != null) {
-            Long loanId = loan.getId();
 
             if (!loan.status().isActive()) {
                 
dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.is.not.active",
 "Loan is not active");
@@ -251,16 +232,6 @@ public class LoanRescheduleRequestDataValidator {
                             "loan.repayment.schedule.installment." + 
"obligation.met", "Repayment schedule installment obligation met");
                 }
             }
-
-            if (loanId != null) {
-                List<LoanRescheduleRequestData> loanRescheduleRequestData = 
this.loanRescheduleRequestReadPlatformService
-                        .readLoanRescheduleRequests(loanId, 
LoanStatus.APPROVED.getValue());
-
-                if (loanRescheduleRequestData.size() > 0) {
-                    
dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled",
-                            "The loan can only be rescheduled once.");
-                }
-            }
         }
 
         if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
deleted file mode 100644
index bcb7bc4..0000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * 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.rescheduleloan.domain;
-
-import java.math.MathContext;
-
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
-import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator;
-import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator;
-import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
-
-public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
-
-    @Override
-    public LoanRescheduleModel reschedule(final MathContext mathContext, final 
InterestMethod interestMethod,
-            final LoanRescheduleRequest loanRescheduleRequest, final 
ApplicationCurrency applicationCurrency,
-            final HolidayDetailDTO holidayDetailDTO, final CalendarInstance 
restCalendarInstance,
-            final CalendarInstance compoundingCalendarInstance, final Calendar 
loanCalendar, final FloatingRateDTO floatingRateDTO,
-            final boolean isSkipRepaymentonmonthFirst, final Integer 
numberofdays) {
-
-        LoanRescheduleModel loanRescheduleModel = null;
-
-        switch (interestMethod) {
-            case DECLINING_BALANCE:
-                loanRescheduleModel = new 
DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, 
loanRescheduleRequest,
-                        applicationCurrency, holidayDetailDTO, 
restCalendarInstance, compoundingCalendarInstance, loanCalendar,
-                        floatingRateDTO, isSkipRepaymentonmonthFirst, 
numberofdays);
-            break;
-
-            case FLAT:
-                loanRescheduleModel = new 
FlatInterestLoanScheduleGenerator().reschedule(mathContext, 
loanRescheduleRequest,
-                        applicationCurrency, holidayDetailDTO, 
restCalendarInstance, compoundingCalendarInstance, loanCalendar,
-                        floatingRateDTO, isSkipRepaymentonmonthFirst, 
numberofdays);
-            break;
-
-            case INVALID:
-            break;
-        }
-
-        return loanRescheduleModel;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
index 8893054..8a0a844 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
@@ -18,20 +18,27 @@
  */
 package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
 
-import java.math.BigDecimal;
 import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
 
 import org.apache.fineract.infrastructure.codes.domain.CodeValue;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.joda.time.LocalDate;
 import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -40,116 +47,97 @@ import 
org.springframework.data.jpa.domain.AbstractPersistable;
 @Table(name = "m_loan_reschedule_request")
 public class LoanRescheduleRequest extends AbstractPersistable<Long> {
        
-       @ManyToOne
+    @ManyToOne
     @JoinColumn(name = "loan_id", nullable = false)
     private Loan loan;
        
-       @Column(name = "status_enum", nullable = false)
-       private Integer statusEnum;
-       
-       @Column(name = "reschedule_from_installment")
-       private Integer rescheduleFromInstallment;
-       
-       @Column(name = "grace_on_principal")
-       private Integer graceOnPrincipal;
-       
-       @Column(name = "grace_on_interest")
-       private Integer graceOnInterest;
-       
-       @Temporal(TemporalType.DATE)
+    @Column(name = "status_enum", nullable = false)
+    private Integer statusEnum;
+
+    @Column(name = "reschedule_from_installment")
+    private Integer rescheduleFromInstallment;
+
+    @Temporal(TemporalType.DATE)
     @Column(name = "reschedule_from_date")
-       private Date rescheduleFromDate;
-       
-       @Temporal(TemporalType.DATE)
-    @Column(name = "adjusted_due_date")
-       private Date adjustedDueDate;
-       
-       @Column(name = "extra_terms")
-       private Integer extraTerms;
-       
-       @Column(name = "recalculate_interest")
-       private Boolean recalculateInterest;
-       
-       @Column(name = "interest_rate", scale = 6, precision = 19)
-       private BigDecimal interestRate;
-       
-       @ManyToOne
+    private Date rescheduleFromDate;
+
+    @Column(name = "recalculate_interest")
+    private Boolean recalculateInterest;
+
+    @ManyToOne
     @JoinColumn(name = "reschedule_reason_cv_id")
-       private CodeValue rescheduleReasonCodeValue;
-       
-       @Column(name = "reschedule_reason_comment")
-       private String rescheduleReasonComment;
-       
-       @Temporal(TemporalType.DATE)
+    private CodeValue rescheduleReasonCodeValue;
+
+    @Column(name = "reschedule_reason_comment")
+    private String rescheduleReasonComment;
+
+    @Temporal(TemporalType.DATE)
     @Column(name = "submitted_on_date")
-       private Date submittedOnDate;
-       
-       @ManyToOne
+    private Date submittedOnDate;
+
+    @ManyToOne
     @JoinColumn(name = "submitted_by_user_id")
-       private AppUser submittedByUser;
-       
-       @Temporal(TemporalType.DATE)
+    private AppUser submittedByUser;
+
+    @Temporal(TemporalType.DATE)
     @Column(name = "approved_on_date")
-       private Date approvedOnDate;
+    private Date approvedOnDate;
        
-       @ManyToOne
+    @ManyToOne
     @JoinColumn(name = "approved_by_user_id")
-       private AppUser approvedByUser;
+    private AppUser approvedByUser;
        
-       @Temporal(TemporalType.DATE)
+    @Temporal(TemporalType.DATE)
     @Column(name = "rejected_on_date")
-       private Date rejectedOnDate;
+    private Date rejectedOnDate;
        
-       @ManyToOne
+    @ManyToOne
     @JoinColumn(name = "rejected_by_user_id")
-       private AppUser rejectedByUser;
-       
-       /** 
-        * LoanRescheduleRequest constructor
-        **/
-       protected LoanRescheduleRequest() {}
-       
-       /** 
-        * LoanRescheduleRequest constructor
-        **/
-       private LoanRescheduleRequest(final Loan loan, final Integer 
statusEnum, final Integer rescheduleFromInstallment, 
-                       final Integer graceOnPrincipal, final Integer 
graceOnInterest, final Date rescheduleFromDate, final Date adjustedDueDate,
-                       final Integer extraTerms, final Boolean 
recalculateInterest, final BigDecimal interestRate, final CodeValue 
rescheduleReasonCodeValue, 
-                       final String rescheduleReasonComment, final Date 
submittedOnDate, final AppUser submittedByUser, 
-                       final Date approvedOnDate, final AppUser 
approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) {
-               this.loan = loan;
-               this.statusEnum = statusEnum;
-               this.rescheduleFromInstallment = rescheduleFromInstallment;
-               this.graceOnPrincipal = graceOnPrincipal;
-               this.graceOnInterest = graceOnInterest;
-               this.rescheduleFromDate = rescheduleFromDate;
-               this.extraTerms = extraTerms;
-               this.interestRate = interestRate;
-               this.rescheduleReasonCodeValue = rescheduleReasonCodeValue;
-               this.rescheduleReasonComment = rescheduleReasonComment;
-               this.submittedOnDate = submittedOnDate;
-               this.submittedByUser = submittedByUser;
-               this.approvedOnDate = approvedOnDate;
-               this.approvedByUser = approvedByUser;
-               this.rejectedOnDate = rejectedOnDate;
-               this.rejectedByUser = rejectedByUser; 
-               this.adjustedDueDate = adjustedDueDate;
-               this.recalculateInterest = recalculateInterest;
-       }
-       
-       /** 
-        * @return a new instance of the LoanRescheduleRequest class
-        **/
-       public static LoanRescheduleRequest instance(final Loan loan, final 
Integer statusEnum, final Integer rescheduleFromInstallment, 
-                       final Integer graceOnPrincipal, final Integer 
graceOnInterest, final Date rescheduleFromDate, final Date adjustedDueDate,
-                       final Integer extraTerms, final Boolean 
recalculateInterest, final BigDecimal interestRate, final CodeValue 
rescheduleReasonCodeValue, 
-                       final String rescheduleReasonComment, final Date 
submittedOnDate, final AppUser submittedByUser, 
-                       final Date approvedOnDate, final AppUser 
approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) {
-               
-               return new LoanRescheduleRequest(loan, statusEnum, 
rescheduleFromInstallment, graceOnPrincipal, graceOnInterest, 
-                               rescheduleFromDate, adjustedDueDate, 
extraTerms, recalculateInterest, interestRate, rescheduleReasonCodeValue, 
rescheduleReasonComment, submittedOnDate,
-                               submittedByUser, approvedOnDate, 
approvedByUser, rejectedOnDate, rejectedByUser);
-       }
+    private AppUser rejectedByUser;
+
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, 
fetch=FetchType.EAGER)
+    @JoinColumn(name = "loan_reschedule_request_id", nullable = false)
+    private Set<LoanRescheduleRequestToTermVariationMapping> 
loanRescheduleRequestToTermVariationMappings = new HashSet<>();
+       
+    /**
+     * LoanRescheduleRequest constructor
+     **/
+    protected LoanRescheduleRequest() {}
+
+    /**
+     * LoanRescheduleRequest constructor
+     **/
+    private LoanRescheduleRequest(final Loan loan, final Integer statusEnum, 
final Integer rescheduleFromInstallment,
+            final Date rescheduleFromDate, final Boolean recalculateInterest, 
final CodeValue rescheduleReasonCodeValue,
+            final String rescheduleReasonComment, final Date submittedOnDate, 
final AppUser submittedByUser, final Date approvedOnDate,
+            final AppUser approvedByUser, final Date rejectedOnDate, AppUser 
rejectedByUser) {
+        this.loan = loan;
+        this.statusEnum = statusEnum;
+        this.rescheduleFromInstallment = rescheduleFromInstallment;
+        this.rescheduleFromDate = rescheduleFromDate;
+        this.rescheduleReasonCodeValue = rescheduleReasonCodeValue;
+        this.rescheduleReasonComment = rescheduleReasonComment;
+        this.submittedOnDate = submittedOnDate;
+        this.submittedByUser = submittedByUser;
+        this.approvedOnDate = approvedOnDate;
+        this.approvedByUser = approvedByUser;
+        this.rejectedOnDate = rejectedOnDate;
+        this.rejectedByUser = rejectedByUser;
+        this.recalculateInterest = recalculateInterest;
+    }
+       
+    /**
+     * @return a new instance of the LoanRescheduleRequest class
+     **/
+    public static LoanRescheduleRequest instance(final Loan loan, final 
Integer statusEnum, final Integer rescheduleFromInstallment,
+            final Date rescheduleFromDate, final Boolean recalculateInterest, 
final CodeValue rescheduleReasonCodeValue,
+            final String rescheduleReasonComment, final Date submittedOnDate, 
final AppUser submittedByUser, final Date approvedOnDate,
+            final AppUser approvedByUser, final Date rejectedOnDate, AppUser 
rejectedByUser) {
+
+        return new LoanRescheduleRequest(loan, statusEnum, 
rescheduleFromInstallment, rescheduleFromDate, recalculateInterest,
+                rescheduleReasonCodeValue, rescheduleReasonComment, 
submittedOnDate, submittedByUser, approvedOnDate, approvedByUser,
+                rejectedOnDate, rejectedByUser);
+    }
        
        /** 
         * @return the reschedule request loan object 
@@ -173,20 +161,6 @@ public class LoanRescheduleRequest extends 
AbstractPersistable<Long> {
        }
        
        /** 
-        * @return the grace on principal 
-        **/
-       public Integer getGraceOnPrincipal() {
-               return this.graceOnPrincipal;
-       }
-       
-       /** 
-        * @return the grace on interest 
-        **/
-       public Integer getGraceOnInterest() {
-               return this.graceOnInterest;
-       }
-       
-       /** 
         * @return due date of the rescheduling start point 
         **/
        public LocalDate getRescheduleFromDate() {
@@ -201,34 +175,6 @@ public class LoanRescheduleRequest extends 
AbstractPersistable<Long> {
        }
        
        /** 
-        * @return due date of the first rescheduled installment
-        **/
-       public LocalDate getAdjustedDueDate() {
-               
-               LocalDate localDate = null;
-               
-               if(this.adjustedDueDate != null) {
-                       localDate = new LocalDate(this.adjustedDueDate);
-               }
-               
-               return localDate;
-       }
-       
-       /** 
-        * @return extra terms to be added after the last loan installment 
-        **/
-       public Integer getExtraTerms() {
-               return this.extraTerms;
-       }
-       
-       /** 
-        * @return the new interest rate to be applied to unpaid installments 
-        **/
-       public BigDecimal getInterestRate() {
-               return this.interestRate;
-       }
-       
-       /** 
         * @return the reschedule reason code value object 
         **/
        public CodeValue getRescheduleReasonCodeValue() {
@@ -348,4 +294,24 @@ public class LoanRescheduleRequest extends 
AbstractPersistable<Long> {
                        this.statusEnum = LoanStatus.REJECTED.getValue();
                }
        }
+       
+    public void updateLoanRescheduleRequestToTermVariationMappings(final 
List<LoanRescheduleRequestToTermVariationMapping> mapping) {
+        this.loanRescheduleRequestToTermVariationMappings.addAll(mapping);
+    }
+    
+    public Set<LoanRescheduleRequestToTermVariationMapping> 
getLoanRescheduleRequestToTermVariationMappings() {
+        return this.loanRescheduleRequestToTermVariationMappings;
+    }
+
+       public LoanTermVariations getDueDateTermVariationIfExists() {
+               if(this.loanRescheduleRequestToTermVariationMappings != null
+                               && 
this.loanRescheduleRequestToTermVariationMappings.size() > 0){
+                       for (LoanRescheduleRequestToTermVariationMapping 
mapping : this.loanRescheduleRequestToTermVariationMappings) {
+                               
if(mapping.getLoanTermVariations().getTermType().isDueDateVariation()){
+                                       return mapping.getLoanTermVariations();
+                               }
+                       }
+               }
+               return null;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
deleted file mode 100644
index f2e8bc7..0000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * 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.rescheduleloan.domain;
-
-import java.math.MathContext;
-
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
-import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
-
-public interface LoanReschedulerFactory {
-
-    public LoanRescheduleModel reschedule(final MathContext mathContext, final 
InterestMethod interestMethod,
-            final LoanRescheduleRequest loanRescheduleRequest, final 
ApplicationCurrency applicationCurrency,
-            final HolidayDetailDTO holidayDetailDTO, CalendarInstance 
restCalendarInstance, CalendarInstance compoundingCalendarInstance,
-            final Calendar loanCalendar, FloatingRateDTO floatingRateDTO, 
final boolean isSkipRepaymentonmonthFirst,
-            final Integer numberofdays);
-}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
index b300b4d..f91649e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
@@ -18,9 +18,9 @@
  */
 package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service;
 
-import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
 
 public interface LoanReschedulePreviewPlatformService {
        
-       public LoanRescheduleModel previewLoanReschedule(Long requestId);
+       public LoanScheduleModel previewLoanReschedule(Long requestId);
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
index 64040af..f6a918d 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
@@ -18,41 +18,33 @@
  */
 package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service;
 
-import java.math.BigDecimal;
 import java.math.MathContext;
 import java.math.RoundingMode;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
-import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
-import org.apache.fineract.organisation.holiday.domain.Holiday;
-import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
-import org.apache.fineract.organisation.holiday.domain.HolidayStatusType;
-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.organisation.workingdays.domain.WorkingDays;
-import 
org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import 
org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
-import 
org.apache.fineract.portfolio.floatingrates.exception.FloatingRateNotFoundException;
-import 
org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
+import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
-import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
-import 
org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
-import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
-import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
+import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
 import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
 import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
-import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
-import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
+import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -60,103 +52,94 @@ import org.springframework.stereotype.Service;
 public class LoanReschedulePreviewPlatformServiceImpl implements 
LoanReschedulePreviewPlatformService {
 
     private final LoanRescheduleRequestRepository 
loanRescheduleRequestRepository;
-    private final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository;
-    private final ConfigurationDomainService configurationDomainService;
-    private final HolidayRepository holidayRepository;
-    private final WorkingDaysRepositoryWrapper workingDaysRepository;
-    private final LoanScheduleHistoryWritePlatformService 
loanScheduleHistoryWritePlatformService;
-    private final CalendarInstanceRepository calendarInstanceRepository;
-    private final FloatingRatesReadPlatformService 
floatingRatesReadPlatformService;
     private final LoanUtilService loanUtilService;
+    private final LoanRepaymentScheduleTransactionProcessorFactory 
loanRepaymentScheduleTransactionProcessorFactory;
+    private final LoanScheduleGeneratorFactory loanScheduleFactory;
+    private final LoanSummaryWrapper loanSummaryWrapper;
+    private final DefaultScheduledDateGenerator scheduledDateGenerator = new 
DefaultScheduledDateGenerator();
 
     @Autowired
     public LoanReschedulePreviewPlatformServiceImpl(final 
LoanRescheduleRequestRepository loanRescheduleRequestRepository,
-            final ApplicationCurrencyRepositoryWrapper 
applicationCurrencyRepository,
-            final ConfigurationDomainService configurationDomainService, final 
HolidayRepository holidayRepository,
-            final WorkingDaysRepositoryWrapper workingDaysRepository,
-            final LoanScheduleHistoryWritePlatformService 
loanScheduleHistoryWritePlatformService,
-            final CalendarInstanceRepository calendarInstanceRepository,
-            final FloatingRatesReadPlatformService 
floatingRatesReadPlatformService, final LoanUtilService loanUtilService) {
+            final LoanUtilService loanUtilService,
+            final LoanRepaymentScheduleTransactionProcessorFactory 
loanRepaymentScheduleTransactionProcessorFactory,
+            final LoanScheduleGeneratorFactory loanScheduleFactory, final 
LoanSummaryWrapper loanSummaryWrapper) {
         this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
-        this.applicationCurrencyRepository = applicationCurrencyRepository;
-        this.configurationDomainService = configurationDomainService;
-        this.holidayRepository = holidayRepository;
-        this.workingDaysRepository = workingDaysRepository;
-        this.loanScheduleHistoryWritePlatformService = 
loanScheduleHistoryWritePlatformService;
-        this.calendarInstanceRepository = calendarInstanceRepository;
-        this.floatingRatesReadPlatformService = 
floatingRatesReadPlatformService;
         this.loanUtilService = loanUtilService;
+        this.loanRepaymentScheduleTransactionProcessorFactory = 
loanRepaymentScheduleTransactionProcessorFactory;
+        this.loanScheduleFactory = loanScheduleFactory;
+        this.loanSummaryWrapper = loanSummaryWrapper;
     }
 
     @Override
-    public LoanRescheduleModel previewLoanReschedule(Long requestId) {
+    public LoanScheduleModel previewLoanReschedule(Long requestId) {
         final LoanRescheduleRequest loanRescheduleRequest = 
this.loanRescheduleRequestRepository.findOne(requestId);
 
         if (loanRescheduleRequest == null) { throw new 
LoanRescheduleRequestNotFoundException(requestId); }
 
         Loan loan = loanRescheduleRequest.getLoan();
 
-        final boolean isHolidayEnabled = 
this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
-        final List<Holiday> holidays = 
this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
-                .getDisbursementDate().toDate(), 
HolidayStatusType.ACTIVE.getValue());
-        final WorkingDays workingDays = this.workingDaysRepository.findOne();
-        final LoanProductMinimumRepaymentScheduleRelatedDetail 
loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
-        final MonetaryCurrency currency = 
loanProductRelatedDetail.getCurrency();
-        final ApplicationCurrency applicationCurrency = 
this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
-
-        final InterestMethod interestMethod = 
loan.getLoanRepaymentScheduleDetail().getInterestMethod();
-        final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
-        final MathContext mathContext = new MathContext(8, roundingMode);
-        List<LoanRepaymentScheduleHistory> oldPeriods = 
this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive(
-                loan.getRepaymentScheduleInstallments(), loan, 
loanRescheduleRequest);
-        HolidayDetailDTO holidayDetailDTO = new 
HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
-        CalendarInstance restCalendarInstance = null;
-        CalendarInstance compoundingCalendarInstance = null;
-        if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
-            restCalendarInstance = 
calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
-                    
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
-            compoundingCalendarInstance = 
calendarInstanceRepository.findCalendarInstaneByEntityId(
-                    loan.loanInterestRecalculationDetailId(), 
CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
+        ScheduleGeneratorDTO scheduleGeneratorDTO = 
this.loanUtilService.buildScheduleGeneratorDTO(loan,
+                loanRescheduleRequest.getRescheduleFromDate());
+        LocalDate rescheduleFromDate = null;
+        List<LoanTermVariationsData> removeLoanTermVariationsData = new 
ArrayList<>();
+        final LoanApplicationTerms loanApplicationTerms = 
loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
+        LoanTermVariations dueDateVariationInCurrentRequest = 
loanRescheduleRequest.getDueDateTermVariationIfExists();
+        if(dueDateVariationInCurrentRequest != null){
+            for (LoanTermVariationsData loanTermVariation : 
loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
+                if 
(loanTermVariation.getDateValue().equals(dueDateVariationInCurrentRequest.fetchTermApplicaDate()))
 {
+                    rescheduleFromDate = 
loanTermVariation.getTermApplicableFrom();
+                    removeLoanTermVariationsData.add(loanTermVariation);
+                }
+            }
         }
-        final CalendarInstance loanCalendarInstance = 
calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
-                CalendarEntityType.LOANS.getValue());
-        Calendar loanCalendar = null;
-        if (loanCalendarInstance != null) {
-            loanCalendar = loanCalendarInstance.getCalendar();
+        
loanApplicationTerms.getLoanTermVariations().getDueDateVariation().removeAll(removeLoanTermVariationsData);
+        if (rescheduleFromDate == null) {
+            rescheduleFromDate = loanRescheduleRequest.getRescheduleFromDate();
         }
-        final FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
-        Boolean isSkipRepaymentOnFirstMonth = false;
-        Integer numberOfDays = 0;
-        boolean isSkipRepaymentOnFirstMonthEnabled = 
this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
-        if(isSkipRepaymentOnFirstMonthEnabled){
-            isSkipRepaymentOnFirstMonth = 
this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), 
loanCalendar);
-            if(isSkipRepaymentOnFirstMonth) { numberOfDays = 
configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
 }
-            
+        List<LoanTermVariationsData> loanTermVariationsData = new 
ArrayList<>();
+        LocalDate adjustedApplicableDate = null;
+        Set<LoanRescheduleRequestToTermVariationMapping> 
loanRescheduleRequestToTermVariationMappings = 
loanRescheduleRequest.getLoanRescheduleRequestToTermVariationMappings();
+        if (!loanRescheduleRequestToTermVariationMappings.isEmpty()) {
+            for (LoanRescheduleRequestToTermVariationMapping 
loanRescheduleRequestToTermVariationMapping : 
loanRescheduleRequestToTermVariationMappings) {
+                if 
(loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().getTermType().isDueDateVariation()
+                        && rescheduleFromDate != null) {
+                    adjustedApplicableDate = 
loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().fetchDateValue();
+                    
loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().setTermApplicableFrom(
+                            rescheduleFromDate.toDate());
+                }
+                
loanTermVariationsData.add(loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().toData());
+            }
         }
-        LoanRescheduleModel loanRescheduleModel = new 
DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
-                loanRescheduleRequest, applicationCurrency, holidayDetailDTO, 
restCalendarInstance, compoundingCalendarInstance,
-                loanCalendar, floatingRateDTO, isSkipRepaymentOnFirstMonth, 
numberOfDays);
-        LoanRescheduleModel loanRescheduleModelWithOldPeriods = 
LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
-                oldPeriods);
-        return loanRescheduleModelWithOldPeriods;
-    }
-
-    private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
-        FloatingRateDTO floatingRateDTO = null;
-        if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
-            boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
-            BigDecimal interestRateDiff = loan.getInterestRateDifferential();
-            List<FloatingRatePeriodData> baseLendingRatePeriods = null;
-            try{
-               baseLendingRatePeriods = 
this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
-                                                                       
.getRatePeriods();
-            }catch(final FloatingRateNotFoundException ex){
-               // Do not do anything
+        
+        for (LoanTermVariationsData loanTermVariation : 
loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
+            if 
(rescheduleFromDate.isBefore(loanTermVariation.getTermApplicableFrom())) {
+                LocalDate applicableDate = 
this.scheduledDateGenerator.generateNextRepaymentDate(rescheduleFromDate, 
loanApplicationTerms,
+                        false, loanApplicationTerms.getHolidayDetailDTO());
+                if 
(loanTermVariation.getTermApplicableFrom().equals(applicableDate)) {
+                    LocalDate adjustedDate = 
this.scheduledDateGenerator.generateNextRepaymentDate(adjustedApplicableDate,
+                            loanApplicationTerms, false, 
loanApplicationTerms.getHolidayDetailDTO());
+                    loanTermVariation.setApplicableFromDate(adjustedDate);
+                    loanTermVariationsData.add(loanTermVariation);
+                }
             }
-            floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, 
loan.getDisbursementDate(), interestRateDiff,
-                    baseLendingRatePeriods);
         }
-        return floatingRateDTO;
+        
+        
loanApplicationTerms.getLoanTermVariations().updateLoanTermVariationsData(loanTermVariationsData);
+        final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
+        final MathContext mathContext = new MathContext(8, roundingMode);
+        final LoanRepaymentScheduleTransactionProcessor 
loanRepaymentScheduleTransactionProcessor = 
this.loanRepaymentScheduleTransactionProcessorFactory
+                .determineProcessor(loan.transactionProcessingStrategy());
+        final LoanScheduleGenerator loanScheduleGenerator = 
this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
+        final LoanLifecycleStateMachine loanLifecycleStateMachine = null;
+        loan.setHelpers(loanLifecycleStateMachine, this.loanSummaryWrapper, 
this.loanRepaymentScheduleTransactionProcessorFactory);
+        final LoanScheduleDTO loanSchedule = 
loanScheduleGenerator.rescheduleNextInstallments(mathContext, 
loanApplicationTerms,
+                loan, loanApplicationTerms.getHolidayDetailDTO(),
+                loanRepaymentScheduleTransactionProcessor, rescheduleFromDate);
+        final LoanScheduleModel loanScheduleModel = 
loanSchedule.getLoanScheduleModel();
+        LoanScheduleModel loanScheduleModels = 
LoanScheduleModel.withLoanScheduleModelPeriods(loanScheduleModel.getPeriods(),
+                loanScheduleModel);
+        
+        return loanScheduleModels;
     }
 
 }

Reply via email to