You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by na...@apache.org on 2016/08/01 13:39:28 UTC

[4/5] incubator-fineract git commit: FINERACT-202 : enabling the option for multi reshedule

FINERACT-202 : enabling the option for multi reshedule


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

Branch: refs/heads/develop
Commit: fe6171237e09cb1f347dc6577800ca4c665e361e
Parents: ada9ced
Author: venkatconflux <ve...@confluxtechnologies.com>
Authored: Fri Jul 29 18:22:46 2016 +0530
Committer: venkatconflux <ve...@confluxtechnologies.com>
Committed: Mon Aug 1 17:07:34 2016 +0530

----------------------------------------------------------------------
 api-docs/apiLive.htm                            |  90 ++-
 .../LoanRescheduleRequestTest.java              |   2 +-
 .../data/LoanTermVariationsData.java            |   6 +-
 .../data/LoanTermVariationsDataWrapper.java     |  78 +-
 .../portfolio/loanaccount/domain/Loan.java      |  55 +-
 .../domain/LoanAccountDomainService.java        |   2 +
 .../domain/LoanAccountDomainServiceJpa.java     |  23 +-
 .../LoanRepaymentScheduleInstallment.java       |   6 +
 ...RescheduleRequestToTermVariationMapping.java |  53 ++
 .../domain/LoanTermVariationType.java           |  34 +-
 .../loanaccount/domain/LoanTermVariations.java  |  43 +-
 .../loanaccount/domain/LoanTransaction.java     |   6 +
 .../domain/AbstractLoanScheduleGenerator.java   | 750 ++++++++-----------
 ...ingBalanceInterestLoanScheduleGenerator.java |   6 +-
 .../FlatInterestLoanScheduleGenerator.java      |   8 +-
 .../domain/LoanApplicationTerms.java            | 217 +++++-
 .../domain/LoanScheduleGenerator.java           |  25 +-
 .../service/LoanScheduleAssembler.java          |  20 +-
 ...nScheduleCalculationPlatformServiceImpl.java |   8 +-
 .../api/RescheduleLoansApiResource.java         |  22 +-
 .../data/LoanRescheduleRequestData.java         |  71 +-
 .../LoanRescheduleRequestDataValidator.java     |  31 +-
 .../domain/DefaultLoanReschedulerFactory.java   |  62 --
 .../domain/LoanRescheduleRequest.java           | 244 +++---
 .../domain/LoanReschedulerFactory.java          |  37 -
 .../LoanReschedulePreviewPlatformService.java   |   4 +-
 ...oanReschedulePreviewPlatformServiceImpl.java | 187 +++--
 ...escheduleRequestReadPlatformServiceImpl.java |  71 +-
 ...scheduleRequestWritePlatformServiceImpl.java | 488 ++++++------
 .../loanproduct/service/LoanEnumerations.java   |  16 +
 .../core_db/V313__multi_rescheduling_script.sql | 141 ++++
 31 files changed, 1496 insertions(+), 1310 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/api-docs/apiLive.htm
----------------------------------------------------------------------
diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index 696e066..7fe3fc9 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -11877,11 +11877,11 @@ Content-Type: application/json Request Body:
 {
 	"loanId": 1,
 	"graceOnPrincipal": 2,
-	"rescheduleFromDate": "04 December 2014",
-	"adjustedDueDate": "20 December 2014",
+	"rescheduleFromDate": "25 December 2013",
+	"adjustedDueDate": "31 December 2013",
 	"dateFormat": "dd MMMM yyyy",
 	"locale": "en",
-	"submittedOnDate": "04 September 2014",
+	"submittedOnDate": "04 September 2013",
 	"rescheduleReasonComment" : "Client has gone AWOL",
 	"rescheduleReasonId": 1
 }
@@ -11907,52 +11907,80 @@ GET https://DomainName/api/v1/rescheduleloans/{requestId}
 					</code>
 					<code class="method-response">
 {
-  "id": 2,
-  "loanId": 17,
-  "clientId": 4,
-  "clientName": "Fernando Michael Torres",
-  "loanAccountNumber": "000000017",
+  "id": 1,
+  "loanId": 1,
+  "clientId": 1,
+  "clientName": "test test",
+  "loanAccountNumber": "000000001",
   "statusEnum": {
-    "id": 500,
-    "code": "loanStatusType.rejected",
-    "value": "Rejected",
-    "pendingApproval": false,
+    "id": 100,
+    "code": "loanStatusType.submitted.and.pending.approval",
+    "value": "Submitted and pending approval",
+    "pendingApproval": true,
     "approved": false,
-    "rejected": true
+    "rejected": false
   },
   "rescheduleFromInstallment": 5,
-  "graceOnPrincipal": 3,
   "rescheduleFromDate": [
     2013,
     12,
-    6
+    25
   ],
   "recalculateInterest": false,
   "rescheduleReasonCodeValue": {
-    "id": 239,
-    "name": "client cannot pay on time"
+    "id": 1,
+    "name": "Passport",
+    "isActive": false
   },
   "timeline": {
     "submittedOnDate": [
-      2014,
-      8,
+      2013,
+      9,
       4
     ],
     "submittedByUsername": "mifos",
     "submittedByFirstname": "App",
-    "submittedByLastname": "Administrator",
-    "rejectedOnDate": [
-      2014,
-      8,
-      5
-    ],
-    "rejectedByUsername": "mifos",
-    "rejectedByFirstname": "App",
-    "rejectedByLastname": "Administrator"
+    "submittedByLastname": "Administrator"
   },
-  "rescheduleReasonComment": ""
-}
-					</code>
+  "rescheduleReasonComment": "Client has gone AWOL",
+  "loanTermVariationsData": [
+    {
+      "id": 13,
+      "termType": {
+        "id": 4,
+        "code": "loanTermType.dueDate",
+        "value": "dueDate"
+      },
+      "termVariationApplicableFrom": [
+        2013,
+        12,
+        25
+      ],
+      "dateValue": [
+        2013,
+        12,
+        31
+      ],
+      "isSpecificToInstallment": false
+    },
+    {
+      "id": 14,
+      "termType": {
+        "id": 8,
+        "code": "loanTermType.graceOnPrincipal",
+        "value": "graceOnPrincipal"
+      },
+      "termVariationApplicableFrom": [
+        2013,
+        12,
+        25
+      ],
+      "decimalValue": 2,
+      "isSpecificToInstallment": false
+    }
+  ]
+}			
+</code>
 				</div>
 			</div>
 			<a id="loan_reschedule_preview_retrieve" name="loan_reschedule_preview_retrieve" class="old-syle-anchor">&nbsp;</a>

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
index 2b00a98..ae39433 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
@@ -211,7 +211,7 @@ public class LoanRescheduleRequestTest {
     	final HashMap loanSummary = this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, loanId);
     	final Float totalExpectedRepayment = (Float) loanSummary.get("totalExpectedRepayment");
     	
-    	assertEquals("NUMBER OF REPAYMENTS SHOULD BE 16, NOT 12", "16", numberOfRepayments.toString());
+    	assertEquals("NUMBER OF REPAYMENTS SHOULD BE 16, NOT 12", "12", numberOfRepayments.toString());
     	assertEquals("TOTAL EXPECTED REPAYMENT MUST BE EQUAL TO 118000.0", "118000.0", totalExpectedRepayment.toString());
     	
     	System.out.println("Successfully approved loan reschedule request (ID: " + this.loanRescheduleRequestId + ")");

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
index f5d2cc0..a19d3b1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
@@ -29,7 +29,7 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
     @SuppressWarnings("unused")
     private final Long id;
     private final EnumOptionData termType;
-    private final LocalDate termVariationApplicableFrom;
+    private LocalDate termVariationApplicableFrom;
     private final BigDecimal decimalValue;
     private final LocalDate dateValue;
     private final boolean isSpecificToInstallment;
@@ -113,5 +113,9 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
         }
         return comparsion;
     }
+    
+    public void setApplicableFromDate(final LocalDate applicableFromDate) {
+        this.termVariationApplicableFrom = applicableFromDate;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
index 65730e7..ea784e3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
@@ -22,37 +22,27 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
-
 import org.joda.time.LocalDate;
 
 public class LoanTermVariationsDataWrapper {
 
     private final List<LoanTermVariationsData> exceptionData;
-    private final ListIterator<LoanTermVariationsData> iterator;
+    private ListIterator<LoanTermVariationsData> iterator;
     private final List<LoanTermVariationsData> interestRateChanges;
+    private final List<LoanTermVariationsData> interestRateFromInstallment;
     private final List<LoanTermVariationsData> dueDateVariation;
-    private final ListIterator<LoanTermVariationsData> dueDateIterator;
+    private ListIterator<LoanTermVariationsData> dueDateIterator;
 
     public LoanTermVariationsDataWrapper(final List<LoanTermVariationsData> exceptionData) {
         if (exceptionData == null) {
             this.exceptionData = new ArrayList<>(1);
         } else {
             this.exceptionData = exceptionData;
-            Collections.sort(this.exceptionData);
         }
         this.interestRateChanges = new ArrayList<>();
         this.dueDateVariation = new ArrayList<>();
-        for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
-            if (loanTermVariationsData.getTermVariationType().isInterestRateVariation()) {
-                this.interestRateChanges.add(loanTermVariationsData);
-            } else if (loanTermVariationsData.getTermVariationType().isDueDateVariation()) {
-                this.dueDateVariation.add(loanTermVariationsData);
-            }
-        }
-        this.exceptionData.removeAll(this.interestRateChanges);
-        this.exceptionData.removeAll(this.dueDateVariation);
-        iterator = this.exceptionData.listIterator();
-        dueDateIterator = this.dueDateVariation.listIterator();
+        this.interestRateFromInstallment = new ArrayList<>();
+        deriveLoanTermVariations();
     }
 
     public boolean hasVariation(final LocalDate date) {
@@ -84,6 +74,10 @@ public class LoanTermVariationsDataWrapper {
     public LoanTermVariationsData nextDueDateVariation() {
         return this.dueDateIterator.next();
     }
+    
+    public LoanTermVariationsData previousDueDateVariation() {
+        return this.dueDateIterator.previous();
+    }
 
     public List<LoanTermVariationsData> getInterestRateChanges() {
         return this.interestRateChanges;
@@ -96,6 +90,23 @@ public class LoanTermVariationsDataWrapper {
     public List<LoanTermVariationsData> getExceptionData() {
         return this.exceptionData;
     }
+    
+    public void setExceptionData(final List<LoanTermVariationsData> exceptionData) {
+        clearTerms();
+        this.exceptionData.addAll(exceptionData);
+        deriveLoanTermVariations();
+    }
+
+    public void clearTerms() {
+        this.exceptionData.clear();
+        this.interestRateChanges.clear();
+        this.dueDateVariation.clear();
+        this.interestRateFromInstallment.clear();
+    }
+    
+    public List<LoanTermVariationsData> getInterestRateFromInstallment() {
+        return this.interestRateFromInstallment;
+    }
 
     public int adjustNumberOfRepayments() {
         int repaymetsForAdjust = 0;
@@ -108,7 +119,7 @@ public class LoanTermVariationsDataWrapper {
         }
         return repaymetsForAdjust;
     }
-
+    
     public LoanTermVariationsData fetchLoanTermDueDateVariationsData(final LocalDate onDate) {
         LoanTermVariationsData data = null;
         for (LoanTermVariationsData termVariationsData : this.dueDateVariation) {
@@ -125,4 +136,39 @@ public class LoanTermVariationsDataWrapper {
         return hasNext(date, iterator);
     }
 
+    public void updateLoanTermVariationsData(final List<LoanTermVariationsData> exceptionData){
+        if(this.exceptionData != null && exceptionData != null && exceptionData.size() > 0){
+            this.exceptionData.addAll(exceptionData);
+            deriveLoanTermVariations();
+        }
+    }
+    
+    private void deriveLoanTermVariations() {
+        Collections.sort(this.exceptionData);
+        for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
+            if (loanTermVariationsData.getTermVariationType().isInterestRateVariation()) {
+                this.interestRateChanges.add(loanTermVariationsData);
+            } else if (loanTermVariationsData.getTermVariationType().isDueDateVariation()) {
+                this.dueDateVariation.add(loanTermVariationsData);
+            } else if (loanTermVariationsData.getTermVariationType().isInterestRateFromInstallment()) {
+                this.interestRateFromInstallment.add(loanTermVariationsData);
+            }
+        }
+        Collections.sort(this.dueDateVariation);
+        this.exceptionData.removeAll(this.interestRateChanges);
+        this.exceptionData.removeAll(this.dueDateVariation);
+        this.exceptionData.removeAll(this.interestRateFromInstallment);
+        this.iterator = this.exceptionData.listIterator();
+        this.dueDateIterator = this.dueDateVariation.listIterator();
+    }
+    
+    public void resetVariations(){
+        
+        for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
+            loanTermVariationsData.setProcessed(false);
+        }
+        this.iterator = this.exceptionData.listIterator();
+        this.dueDateIterator = this.dueDateVariation.listIterator();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/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 5bd7a0b..adb516e 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
@@ -2734,6 +2734,8 @@ public class Loan extends AbstractPersistable<Long> {
         final LoanStatus currentStatus = LoanStatus.fromInt(this.loanStatus);
         final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, currentStatus);
         validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSAL_UNDO, getDisbursementDate());
+        existingTransactionIds.addAll(findExistingTransactionIds());
+        existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
         if (!statusEnum.hasStateOf(currentStatus)) {
             this.loanStatus = statusEnum.getValue();
             actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
@@ -2750,6 +2752,7 @@ public class Loan extends AbstractPersistable<Long> {
                 }
             }
             boolean isEmiAmountChanged = this.loanTermVariations.size() > 0;
+            
             updateLoanToPreDisbursalState();
             if (isScheduleRegenerateRequired || isDisbursedAmountChanged || isEmiAmountChanged
                     || this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
@@ -2760,14 +2763,14 @@ public class Loan extends AbstractPersistable<Long> {
                 if (isDisbursedAmountChanged) {
                     updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
                 }
+            }else if(isPeriodicAccrualAccountingEnabledOnLoanProduct()){
+                for (final LoanRepaymentScheduleInstallment period : getRepaymentScheduleInstallments()) {
+                    period.resetAccrualComponents();
+                }
             }
 
             actualChanges.put("actualDisbursementDate", "");
 
-            existingTransactionIds.addAll(findExistingTransactionIds());
-            existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
-            this.accruedTill = null;
-            reverseExistingTransactions();
             updateLoanSummaryDerivedFields();
 
         }
@@ -2776,14 +2779,22 @@ public class Loan extends AbstractPersistable<Long> {
     }
 
     private final void reverseExistingTransactions() {
-
+        Collection<LoanTransaction> retainTransactions = new ArrayList<>();
         for (final LoanTransaction transaction : this.loanTransactions) {
             transaction.reverse();
+            if(transaction.getId() != null){
+                retainTransactions.add(transaction);
+            }
         }
+        this.loanTransactions.retainAll(retainTransactions);
+        isTransactionsListDirty = true ;
     }
 
     private void updateLoanToPreDisbursalState() {
         this.actualDisbursementDate = null;
+        
+        this.accruedTill = null;
+        reverseExistingTransactions();
 
         for (final LoanCharge charge : charges()) {
             if (charge.isOverdueInstallmentCharge()) {
@@ -2796,13 +2807,11 @@ public class Loan extends AbstractPersistable<Long> {
         for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
             currentInstallment.resetDerivedComponents();
         }
-        final List<LoanTermVariations> removeTerms = new ArrayList<>(this.loanTermVariations.size());
         for (LoanTermVariations variations : this.loanTermVariations) {
             if (variations.getOnLoanStatus().equals(LoanStatus.ACTIVE.getValue())) {
-                removeTerms.add(variations);
+                variations.markAsInactive();
             }
         }
-        this.loanTermVariations.removeAll(removeTerms);
         final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
         wrapper.reprocess(getCurrency(), getDisbursementDate(), getRepaymentScheduleInstallments(), charges());
 
@@ -5024,7 +5033,7 @@ public class Loan extends AbstractPersistable<Long> {
 
     }
 
-    private ChangedTransactionDetail processTransactions() {
+    public ChangedTransactionDetail processTransactions() {
         final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
                 .determineProcessor(this.transactionProcessingStrategy);
         final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
@@ -5292,9 +5301,8 @@ public class Loan extends AbstractPersistable<Long> {
         final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
                 .determineProcessor(this.transactionProcessingStrategy);
 
-        return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, charges(), generatorDTO.getHolidayDetailDTO(),
-                retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor,
-                getRepaymentScheduleInstallments(), generatorDTO.getRecalculateFrom());
+        return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, this, generatorDTO.getHolidayDetailDTO(),
+                loanRepaymentScheduleTransactionProcessor, generatorDTO.getRecalculateFrom());
     }
 
     public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final ScheduleGeneratorDTO scheduleGeneratorDTO, final LocalDate onDate) {
@@ -5310,9 +5318,8 @@ public class Loan extends AbstractPersistable<Long> {
             final LoanScheduleGenerator loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(interestMethod);
             final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
                     .determineProcessor(this.transactionProcessingStrategy);
-            installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, charges(),
-                    scheduleGeneratorDTO.getHolidayDetailDTO(), retreiveListOfTransactionsPostDisbursementExcludeAccruals(),
-                    loanRepaymentScheduleTransactionProcessor, getRepaymentScheduleInstallments());
+            installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, this,
+                    scheduleGeneratorDTO.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor);
         } else {
             installment = this.getTotalOutstandingOnLoan();
         }
@@ -5377,10 +5384,12 @@ public class Loan extends AbstractPersistable<Long> {
         return loanApplicationTerms;
     }
 
-    private BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
+    public BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
             List<LoanTermVariationsData> loanTermVariations) {
         for (LoanTermVariations variationTerms : this.loanTermVariations) {
-            loanTermVariations.add(variationTerms.toData());
+            if(variationTerms.isActive()) {
+                loanTermVariations.add(variationTerms.toData());
+            }
         }
         annualNominalInterestRate = constructFloatingInterestRates(annualNominalInterestRate, floatingRateDTO, loanTermVariations);
         return annualNominalInterestRate;
@@ -6332,4 +6341,16 @@ public class Loan extends AbstractPersistable<Long> {
         return isForeClosure;
     }
 
+	public Set<LoanTermVariations> getActiveLoanTermVariations() {
+		Set<LoanTermVariations> retData = new HashSet<>();
+		if(this.loanTermVariations != null && this.loanTermVariations.size() > 0){
+			for (LoanTermVariations loanTermVariations : this.loanTermVariations) {
+				if(loanTermVariations.isActive()){
+					retData.add(loanTermVariations);
+				}
+			}
+		}
+        return retData.size()>0?retData:null;
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
index b1052c3..407a706 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
@@ -65,4 +65,6 @@ public interface LoanAccountDomainService {
      * @param loan {@link Loan} object
      */
     void disableStandingInstructionsLinkedToClosedLoan(Loan loan);
+
+    void recalculateAccruals(Loan loan, boolean isInterestCalcualtionHappened);
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
index a46b43f..f7b1a6b 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
@@ -447,15 +447,21 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
      */
     @Override
     public void recalculateAccruals(Loan loan) {
+        boolean isInterestCalcualtionHappened = loan.repaymentScheduleDetail().isInterestRecalculationEnabled();
+        recalculateAccruals(loan, isInterestCalcualtionHappened);
+    }
+
+    @Override
+    public void recalculateAccruals(Loan loan, boolean isInterestCalcualtionHappened) {
         LocalDate accruedTill = loan.getAccruedTill();
+        if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || !isInterestCalcualtionHappened
+                || accruedTill == null || loan.isNpa() || !loan.status().isActive()) { return; }
+        
         boolean isOrganisationDateEnabled = this.configurationDomainService.isOrganisationstartDateEnabled();
         Date organisationStartDate = new Date();
         if(isOrganisationDateEnabled){
             organisationStartDate = this.configurationDomainService.retrieveOrganisationStartDate(); 
         }
-        
-        if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || !loan.repaymentScheduleDetail().isInterestRecalculationEnabled()
-                || accruedTill == null || loan.isNpa() || !loan.status().isActive()) { return; }
         Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = new ArrayList<>();
         List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
         Long loanId = loan.getId();
@@ -697,17 +703,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
 
     }
 
-    private LoanRepaymentScheduleInstallment fetchLoanRepaymentScheduleInstallment(LocalDate fromDate, final Loan loan) {
-        LoanRepaymentScheduleInstallment installment = null;
-        for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : loan.getRepaymentScheduleInstallments()) {
-            if (fromDate.equals(loanRepaymentScheduleInstallment.getFromDate())) {
-                installment = loanRepaymentScheduleInstallment;
-                break;
-            }
-        }
-        return installment;
-    }
-
     private Map<BUSINESS_ENTITY, Object> constructEntityMap(final BUSINESS_ENTITY entityEvent, Object entity) {
         Map<BUSINESS_ENTITY, Object> map = new HashMap<>(1);
         map.put(entityEvent, entity);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/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 d95d741..c31d1ec 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
@@ -344,6 +344,12 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
         this.obligationsMet = false;
         this.obligationsMetOnDate = null;
     }
+    
+    public void resetAccrualComponents() {
+        this.interestAccrued = null;
+        this.feeAccrued = null;
+        this.penaltyAccrued = null;
+    }
 
     public Money payPenaltyChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java
new file mode 100644
index 0000000..af9a8e2
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java
@@ -0,0 +1,53 @@
+/**
+ * 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 javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.springframework.data.jpa.domain.AbstractPersistable;
+
+@Entity
+@Table(name="m_loan_reschedule_request_term_variations_mapping")
+public class LoanRescheduleRequestToTermVariationMapping extends AbstractPersistable<Long> {
+    
+    
+    @ManyToOne(optional = false, cascade = CascadeType.PERSIST)
+    @JoinColumn(name = "loan_term_variations_id", nullable = false)
+    private LoanTermVariations loanTermVariations;
+    
+    protected LoanRescheduleRequestToTermVariationMapping(){
+        
+    }
+
+    private LoanRescheduleRequestToTermVariationMapping(final LoanTermVariations loanTermVariations) {
+        this.loanTermVariations = loanTermVariations;
+    }
+
+    public static LoanRescheduleRequestToTermVariationMapping createNew(final LoanTermVariations loanTermVariation) {
+        return new LoanRescheduleRequestToTermVariationMapping(loanTermVariation);
+    }
+    
+    public LoanTermVariations getLoanTermVariations() {
+        return this.loanTermVariations;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
index c0df3bb..0b12182 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
@@ -26,7 +26,11 @@ public enum LoanTermVariationType {
     PRINCIPAL_AMOUNT(3, "loanTermType.principalAmount"), //
     DUE_DATE(4, "loanTermType.dueDate"), //
     INSERT_INSTALLMENT(5, "loanTermType.insertInstallment"), //
-    DELETE_INSTALLMENT(6, "loanTermType.deleteInstallment");
+    DELETE_INSTALLMENT(6, "loanTermType.deleteInstallment"),
+    GRACE_ON_INTEREST(7, "loanTermType.graceOnInterest"),
+    GRACE_ON_PRINCIPAL(8, "loanTermType.graceOnPrincipal"),
+    EXTEND_REPAYMENT_PERIOD(9, "loanTermType.extendRepaymentPeriod"),
+    INTEREST_RATE_FROM_INSTALLMENT(10, "loanTermType.interestRateFromInstallment");
 
     private final Integer value;
     private final String code;
@@ -66,6 +70,18 @@ public enum LoanTermVariationType {
             case 6:
                 enumeration = LoanTermVariationType.DELETE_INSTALLMENT;
             break;
+            case 7:
+                enumeration = LoanTermVariationType.GRACE_ON_INTEREST;
+            break;
+            case 8:
+                enumeration = LoanTermVariationType.GRACE_ON_PRINCIPAL;
+            break;
+            case 9:
+                enumeration = LoanTermVariationType.EXTEND_REPAYMENT_PERIOD;
+            break;
+            case 10:
+                enumeration = LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT;
+            break;
         }
         return enumeration;
     }
@@ -93,4 +109,20 @@ public enum LoanTermVariationType {
     public boolean isDeleteInstallment() {
         return this.value.equals(LoanTermVariationType.DELETE_INSTALLMENT.getValue());
     }
+    
+    public boolean isGraceOnInterest() {
+        return this.value.equals(LoanTermVariationType.GRACE_ON_INTEREST.getValue());
+    }
+    
+    public boolean isGraceOnPrincipal() {
+        return this.value.equals(LoanTermVariationType.GRACE_ON_PRINCIPAL.getValue());
+    }
+    
+    public boolean isExtendRepaymentPeriod() {
+        return this.value.equals(LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue());
+    }
+    
+    public boolean isInterestRateFromInstallment() {
+        return this.value.equals(LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT.getValue());
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
index 01245b9..6dbadad 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
@@ -23,12 +23,13 @@ import java.util.Date;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
-
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
 import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
@@ -62,6 +63,13 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
 
     @Column(name = "applied_on_loan_status", nullable = false)
     private Integer onLoanStatus;
+    
+    @Column(name = "is_active", nullable = false)
+    private Boolean isActive;
+    
+    @OneToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "parent_id")
+    private LoanTermVariations parent;
 
     public LoanTermVariations(final Integer termType, final Date termApplicableFrom, final BigDecimal decimalValue, final Date dateValue,
             final boolean isSpecificToInstallment, final Loan loan) {
@@ -72,6 +80,8 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
         this.dateValue = dateValue;
         this.isSpecificToInstallment = isSpecificToInstallment;
         this.onLoanStatus = loan.status().getValue();
+        this.isActive = true;
+        this.parent = null;
     }
     
     public LoanTermVariations(final Integer termType, final Date termApplicableFrom, final BigDecimal decimalValue, final Date dateValue,
@@ -83,6 +93,21 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
         this.dateValue = dateValue;
         this.isSpecificToInstallment = isSpecificToInstallment;
         this.onLoanStatus = loanStatus;
+        this.isActive = true;
+        this.parent = null;
+    }
+    
+    public LoanTermVariations(final Integer termType, final Date termApplicableFrom, final BigDecimal decimalValue, final Date dateValue,
+            final boolean isSpecificToInstallment, final Loan loan, final Integer loanStatus, final Boolean isActive, final LoanTermVariations parent) {
+        this.loan = loan;
+        this.termApplicableFrom = termApplicableFrom;
+        this.termType = termType;
+        this.decimalValue = decimalValue;
+        this.dateValue = dateValue;
+        this.isSpecificToInstallment = isSpecificToInstallment;
+        this.onLoanStatus = loanStatus;
+        this.isActive = isActive;
+        this.parent = parent;
     }
 
     protected LoanTermVariations() {
@@ -135,5 +160,21 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
     public Integer getOnLoanStatus() {
         return this.onLoanStatus;
     }
+    
+    public Boolean isActive() {
+        return this.isActive;
+    }
+
+    public LoanTermVariations parent() {
+        return this.parent;
+    }
+    
+    public void updateIsActive(final Boolean isActive){
+        this.isActive = isActive;
+    }
+    
+    public void markAsInactive() {
+        this.isActive = false;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/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 414ca14..7b16a5c 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
@@ -777,4 +777,10 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
     public boolean isAccrualTransaction() {
         return isAccrual();
     }
+    
+    public boolean isPaymentTransaction() {
+        return this.isNotReversed()
+                && !(this.isDisbursement() || this.isAccrual() || this.isRepaymentAtDisbursement() || this.isNonMonetaryTransaction() || this
+                        .isIncomePosting());
+    }
 }
\ No newline at end of file