This is an automated email from the ASF dual-hosted git repository.

avikg pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 7c235c5  
FINERACT-1443-loan-interest-recover-policy-fix-when-interest-more-than-EMI 
(#2033)
7c235c5 is described below

commit 7c235c583b5fe2b85f2b4cbd8a53f59c05d0fc46
Author: Manoj <[email protected]>
AuthorDate: Fri Feb 18 23:52:51 2022 +0530

    FINERACT-1443-loan-interest-recover-policy-fix-when-interest-more-than-EMI 
(#2033)
---
 .../domain/ConfigurationDomainService.java         |   6 +-
 .../domain/ConfigurationDomainServiceJpa.java      |   9 +-
 .../loanaccount/data/ScheduleGeneratorDTO.java     |  17 ++-
 .../portfolio/loanaccount/domain/Loan.java         |   5 +-
 .../domain/AbstractLoanScheduleGenerator.java      |  70 ++---------
 ...liningBalanceInterestLoanScheduleGenerator.java |  48 ++++----
 .../domain/DefaultScheduledDateGenerator.java      |  18 +++
 .../loanschedule/domain/LoanApplicationTerms.java  |  63 +++++++---
 .../loanschedule/domain/PrincipalInterest.java     |   9 ++
 .../domain/ScheduledDateGenerator.java             |   3 +
 .../service/LoanScheduleAssembler.java             |   8 +-
 .../loanaccount/service/LoanUtilService.java       |   8 +-
 .../V392__interest_recovery_conf_for_rescedule.sql |  29 +++++
 .../LoanRescheduleOnDecliningBalanceLoanTest.java  | 130 ++++++++++++++++++---
 .../common/GlobalConfigurationHelper.java          |  28 +++--
 .../common/loans/LoanApplicationTestBuilder.java   |   7 ++
 16 files changed, 310 insertions(+), 148 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
index 8a2a726..037f4d6 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -75,6 +75,10 @@ public interface ConfigurationDomainService {
 
     boolean isSkippingMeetingOnFirstDayOfMonthEnabled();
 
+    boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI();
+
+    boolean isPrincipalCompoundingDisabledForOverdueLoans();
+
     Long retreivePeroidInNumberOfDaysForSkipMeetingDate();
 
     boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled();
@@ -97,8 +101,6 @@ public interface ConfigurationDomainService {
 
     boolean isFirstRepaymentDateAfterRescheduleAllowedOnHoliday();
 
-    boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI();
-
     String getAccountMappingForPaymentType();
 
     String getAccountMappingForCharge();
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index 6b6c595..30426ef 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -259,8 +259,13 @@ public class ConfigurationDomainServiceJpa implements 
ConfigurationDomainService
     }
 
     @Override
-    public boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI() {
-        return 
getGlobalConfigurationPropertyData("is-interest-to-be-appropriated-equally-when-greater-than-emi").isEnabled();
+    public boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI() {
+        return 
getGlobalConfigurationPropertyData("is-interest-to-be-recovered-first-when-greater-than-emi").isEnabled();
+    }
+
+    @Override
+    public boolean isPrincipalCompoundingDisabledForOverdueLoans() {
+        return 
getGlobalConfigurationPropertyData("is-principal-compounding-disabled-for-overdue-loans").isEnabled();
     }
 
     @Override
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
index 4d609bf..8fc3371 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/ScheduleGeneratorDTO.java
@@ -44,7 +44,8 @@ public class ScheduleGeneratorDTO {
     final boolean isSkipRepaymentOnFirstDayofMonth;
     final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
     final boolean isFirstRepaymentDateAllowedOnHoliday;
-    final boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
+    final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI;
+    final boolean isPrincipalCompoundingDisabledForOverdueLoans;
 
     public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory 
loanScheduleFactory, final ApplicationCurrency applicationCurrency,
             final LocalDate calculatedRepaymentsStartingFromDate, final 
HolidayDetailDTO holidayDetailDTO,
@@ -53,7 +54,8 @@ public class ScheduleGeneratorDTO {
             final Calendar calendar, final CalendarHistoryDataWrapper 
calendarHistoryDataWrapper,
             final Boolean isInterestChargedFromDateAsDisbursementDateEnabled, 
final Integer numberOfdays,
             final boolean isSkipRepaymentOnFirstDayofMonth, final Boolean 
isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled,
-            final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean 
isInterestToBeAppropriatedEquallyWhenGreaterThanEMI) {
+            final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean 
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
+            final boolean isPrincipalCompoundingDisabledForOverdueLoans) {
 
         this.loanScheduleFactory = loanScheduleFactory;
         this.applicationCurrency = applicationCurrency;
@@ -71,7 +73,8 @@ public class ScheduleGeneratorDTO {
         this.isSkipRepaymentOnFirstDayofMonth = 
isSkipRepaymentOnFirstDayofMonth;
         this.isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = 
isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
         this.isFirstRepaymentDateAllowedOnHoliday = 
isFirstRepaymentDateAllowedOnHoliday;
-        this.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI = 
isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
+        this.isInterestToBeRecoveredFirstWhenGreaterThanEMI = 
isInterestToBeRecoveredFirstWhenGreaterThanEMI;
+        this.isPrincipalCompoundingDisabledForOverdueLoans = 
isPrincipalCompoundingDisabledForOverdueLoans;
     }
 
     public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
@@ -150,7 +153,11 @@ public class ScheduleGeneratorDTO {
         return isFirstRepaymentDateAllowedOnHoliday;
     }
 
-    public boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI() {
-        return isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
+    public boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI() {
+        return isInterestToBeRecoveredFirstWhenGreaterThanEMI;
+    }
+
+    public boolean isPrincipalCompoundingDisabledForOverdueLoans() {
+        return isPrincipalCompoundingDisabledForOverdueLoans;
     }
 }
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 104ddea..0cfe9b5 100644
--- 
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
@@ -5623,7 +5623,8 @@ public class Loan extends AbstractPersistableCustom {
                 rescheduleStrategyMethod, calendar, getApprovedPrincipal(), 
annualNominalInterestRate, loanTermVariations,
                 calendarHistoryDataWrapper, 
scheduleGeneratorDTO.getNumberOfdays(), 
scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(),
                 holidayDetailDTO, allowCompoundingOnEod, 
scheduleGeneratorDTO.isFirstRepaymentDateAllowedOnHoliday(),
-                
scheduleGeneratorDTO.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI(), 
this.fixedPrincipalPercentagePerInstallment);
+                
scheduleGeneratorDTO.isInterestToBeRecoveredFirstWhenGreaterThanEMI(), 
this.fixedPrincipalPercentagePerInstallment,
+                
scheduleGeneratorDTO.isPrincipalCompoundingDisabledForOverdueLoans());
         return loanApplicationTerms;
     }
 
@@ -5905,7 +5906,7 @@ public class Loan extends AbstractPersistableCustom {
                 compoundingCalendarInstance, compoundingFrequencyType, 
this.loanProduct.preCloseInterestCalculationStrategy(),
                 rescheduleStrategyMethod, loanCalendar, 
getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
                 calendarHistoryDataWrapper, numberofdays, 
isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod, false,
-                false, this.fixedPrincipalPercentagePerInstallment);
+                false, this.fixedPrincipalPercentagePerInstallment, false);
     }
 
     /**
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
index 94a6f59..fd008cf 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
@@ -286,8 +286,7 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
 
             // will check for EMI amount greater than interest calculated
             if (loanApplicationTerms.getFixedEmiAmount() != null
-                    && 
loanApplicationTerms.getFixedEmiAmount().compareTo(principalInterestForThisPeriod.interest().getAmount())
 < 0
-                    && 
!loanApplicationTerms.isInterestToBeAppropriatedEquallyWhenGreaterThanEMIEnabled())
 {
+                    && 
loanApplicationTerms.getFixedEmiAmount().compareTo(principalInterestForThisPeriod.interest().getAmount())
 < 0) {
                 String errorMsg = "EMI amount must be greater than : " + 
principalInterestForThisPeriod.interest().getAmount();
                 throw new MultiDisbursementEmiAmountException(errorMsg, 
principalInterestForThisPeriod.interest().getAmount(),
                         loanApplicationTerms.getFixedEmiAmount());
@@ -333,7 +332,9 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
                     scheduleParams.getOutstandingBalance(), 
currentPeriodParams.getInterestForThisPeriod(),
                     currentPeriodParams.getFeeChargesForInstallment(), 
currentPeriodParams.getPenaltyChargesForInstallment(),
                     totalInstallmentDue, !isCompletePeriod);
-
+            if (principalInterestForThisPeriod.getRescheduleInterestPortion() 
!= null) {
+                
installment.setRescheduleInterestPortion(principalInterestForThisPeriod.getRescheduleInterestPortion().getAmount());
+            }
             
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), 
installment);
             // apply loan transactions on installments to identify early/late
             // payments for interest recalculation
@@ -379,44 +380,6 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
             
scheduleParams.setTotalOutstandingInterestPaymentDueToGrace(Money.zero(currency));
         }
 
-        if 
(loanApplicationTerms.isInterestToBeAppropriatedEquallyWhenGreaterThanEMIEnabled()
-                && loanApplicationTerms.getInterestTobeApproppriated() != null
-                && 
loanApplicationTerms.getInterestTobeApproppriated().isGreaterThanZero()) {
-            int emisTobeChanged = 1;
-            for (LoanScheduleModelPeriod installment : 
(List<LoanScheduleModelPeriod>) periods) {
-                if (!installment.isEMIFixedSpecificToInstallment()) {
-                    emisTobeChanged++;
-                }
-            }
-            if (emisTobeChanged > 1) {
-                emisTobeChanged--;
-            }
-            Money interestTobeApproppriated = 
loanApplicationTerms.getInterestTobeApproppriated();
-            Money interestFraction = 
interestTobeApproppriated.dividedBy(emisTobeChanged, mc.getRoundingMode());
-            BigDecimal roundFraction = 
interestFraction.getAmount().remainder(BigDecimal.ONE);
-            interestFraction = interestFraction.minus(roundFraction);
-            for (LoanScheduleModelPeriod installment : 
(List<LoanScheduleModelPeriod>) periods) {
-                if (!installment.isEMIFixedSpecificToInstallment()) {
-                    installment.addInterestAmount(interestFraction);
-                    
installment.setRescheduleInterestPortion(interestFraction.getAmount());
-                    interestTobeApproppriated = 
interestTobeApproppriated.minus(interestFraction);
-                }
-            }
-            LoanScheduleModelPeriod lastInstallment = 
((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1);
-
-            if (interestTobeApproppriated.isGreaterThanZero()) {
-                lastInstallment.addInterestAmount(interestTobeApproppriated);
-                BigDecimal rescheduleInterestPortion = BigDecimal.ZERO;
-                if (lastInstallment.rescheduleInterestPortion() != null) {
-                    rescheduleInterestPortion = 
lastInstallment.rescheduleInterestPortion();
-                }
-                
lastInstallment.setRescheduleInterestPortion(rescheduleInterestPortion.add(interestTobeApproppriated.getAmount()));
-            }
-            
scheduleParams.addTotalRepaymentExpected(loanApplicationTerms.getInterestTobeApproppriated());
-            
scheduleParams.addTotalCumulativeInterest(loanApplicationTerms.getInterestTobeApproppriated());
-            
loanApplicationTerms.setInterestTobeApproppriated(Money.zero(currency));
-        }
-
         // determine fees and penalties for charges which depends on total
         // loan interest
         updatePeriodsWithCharges(currency, scheduleParams, periods, 
nonCompoundingCharges);
@@ -1054,6 +1017,7 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
                 modifiedScheduledDueDate = 
loanTermVariationsData.getDateValue();
                 if (!loanTermVariationsData.isSpecificToInstallment()) {
                     
scheduleParams.setActualRepaymentDate(modifiedScheduledDueDate);
+                    
loanApplicationTerms.setNewScheduledDueDateStart(modifiedScheduledDueDate);
                 }
                 loanTermVariationsData.setProcessed(true);
             }
@@ -2397,23 +2361,11 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
             periods.clear();
         }
 
-        BigDecimal rescheuleInterestPortionTobeRetained = BigDecimal.ZERO;
-        for (LoanRepaymentScheduleInstallment retainedInstallment : 
retainedInstallments) {
-            if (retainedInstallment.getRescheduleInterestPortion() != null) {
-                rescheuleInterestPortionTobeRetained = 
rescheuleInterestPortionTobeRetained
-                        
.add(retainedInstallment.getRescheduleInterestPortion());
-            }
-        }
-
-        BigDecimal rescheuleInterestPortionTotal = BigDecimal.ZERO;
-        for (LoanRepaymentScheduleInstallment inst : 
loan.getRepaymentScheduleInstallments()) {
-            if (inst.getRescheduleInterestPortion() != null) {
-                rescheuleInterestPortionTotal = 
rescheuleInterestPortionTotal.add(inst.getRescheduleInterestPortion());
-            }
+        if (retainedInstallments.size() > 0
+                && retainedInstallments.get(retainedInstallments.size() - 
1).getRescheduleInterestPortion() != null) {
+            loanApplicationTerms.setInterestTobeApproppriated(
+                    Money.of(loan.getCurrency(), 
retainedInstallments.get(retainedInstallments.size() - 
1).getRescheduleInterestPortion()));
         }
-
-        BigDecimal rescheuleInterestPortionTobeAppropriated = 
rescheuleInterestPortionTotal.subtract(rescheuleInterestPortionTobeRetained);
-        
loanApplicationTerms.setInterestTobeApproppriated(Money.of(loan.getCurrency(), 
rescheuleInterestPortionTobeAppropriated));
         LoanScheduleModel loanScheduleModel = generate(mc, 
loanApplicationTerms, loan.charges(), holidayDetailDTO, loanScheduleParams);
 
         for (LoanScheduleModelPeriod loanScheduleModelPeriod : 
loanScheduleModel.getPeriods()) {
@@ -2640,8 +2592,8 @@ public abstract class AbstractLoanScheduleGenerator 
implements LoanScheduleGener
             final HolidayDetailDTO holidayDetailDTO) {
         LocalDate nextScheduleDate = null;
         if 
(loanApplicationTerms.getRecalculationFrequencyType().isSameAsRepayment()) {
-            nextScheduleDate = 
this.scheduledDateGenerator.generateNextScheduleDateStartingFromDisburseDate(startDate,
 loanApplicationTerms,
-                    holidayDetailDTO);
+            nextScheduleDate = 
this.scheduledDateGenerator.generateNextScheduleDateStartingFromDisburseDateOrRescheduleDate(startDate,
+                    loanApplicationTerms, holidayDetailDTO);
         } else {
             CalendarInstance calendarInstance = 
loanApplicationTerms.getRestCalendarInstance();
             nextScheduleDate = 
CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), startDate);
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
index a120fa8..c391125 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
@@ -113,7 +113,11 @@ public class DecliningBalanceInterestLoanScheduleGenerator 
extends AbstractLoanS
                         compoundFee = compoundingMap.get(principal.getKey());
                         compoundingMap.put(principal.getKey(), 
interestToBeCompounded.plus(compoundFee));
                     }
-                    balanceForInterestCalculation = 
balanceForInterestCalculation.plus(principal.getValue()).plus(compoundFee);
+                    if 
(!loanApplicationTerms.isPrincipalCompoundingDisabledForOverdueLoans()) {
+                        balanceForInterestCalculation = 
balanceForInterestCalculation.plus(principal.getValue());
+                    }
+                    balanceForInterestCalculation = 
balanceForInterestCalculation.plus(compoundFee);
+
                     if (interestRates.containsKey(principal.getKey())) {
                         
loanApplicationTerms.updateAnnualNominalInterestRate(interestRates.get(principal.getKey()));
                     }
@@ -128,42 +132,27 @@ public class 
DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
         interestForThisInstallment = 
interestForThisInstallment.plus(result.interest());
         cumulatingInterestDueToGrace = result.interestPaymentDueToGrace();
 
-        Money interestTobeApproppriated = 
loanApplicationTerms.getInterestTobeApproppriated() == null
-                ? Money.zero(interestForThisInstallment.getCurrency())
-                : loanApplicationTerms.getInterestTobeApproppriated();
-
-        if (loanApplicationTerms.getFixedEmiAmount() != null
-                && 
loanApplicationTerms.isInterestToBeAppropriatedEquallyWhenGreaterThanEMIEnabled()
 && interestForThisInstallment
-                        
.isGreaterThan(Money.of(interestForThisInstallment.getCurrency(), 
loanApplicationTerms.getFixedEmiAmount()))) {
-            LocalDate actualPeriodEndDate = 
this.scheduledDateGenerator.generateNextRepaymentDate(interestStartDate, 
loanApplicationTerms,
-                    false);
-            PrincipalInterest tempInterest = 
loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
-                    interestCalculationGraceOnRepaymentPeriodFraction, 
periodNumber, mc, cumulatingInterestDueToGrace,
-                    balanceForInterestCalculation, interestStartDate, 
actualPeriodEndDate);
-
-            Money fixedEmi = 
Money.of(interestForThisInstallment.getCurrency(), 
loanApplicationTerms.getFixedEmiAmount());
-
-            if (tempInterest.interest().isGreaterThan(fixedEmi)) {
-                loanApplicationTerms
-                        
.setInterestTobeApproppriated(interestTobeApproppriated.plus(interestForThisInstallment.minus(fixedEmi)));
-                interestForThisInstallment = fixedEmi;
-            } else {
-                loanApplicationTerms.setInterestTobeApproppriated(
-                        
interestTobeApproppriated.plus(interestForThisInstallment.minus(tempInterest.interest())));
-                interestForThisInstallment = tempInterest.interest();
-            }
+        if 
(loanApplicationTerms.isInterestToBeRecoveredFirstWhenGreaterThanEMIEnabled()
+                && loanApplicationTerms.isInterestTobeApproppriated()) {
+            interestForThisInstallment = 
interestForThisInstallment.add(loanApplicationTerms.getInterestTobeApproppriated());
+            
loanApplicationTerms.setInterestTobeApproppriated(interestForThisInstallment.zero());
         }
 
-        cumulatingInterestDueToGrace = result.interestPaymentDueToGrace();
-
         Money interestForPeriod = interestForThisInstallment;
         if (interestForPeriod.isGreaterThanZero()) {
             interestForPeriod = 
interestForPeriod.minus(cumulatingInterestPaymentDueToGrace);
         } else {
             interestForPeriod = 
cumulatingInterestDueToGrace.minus(cumulatingInterestPaymentDueToGrace);
         }
+
         Money principalForThisInstallment = 
loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, 
outstandingBalance,
                 periodNumber, mc, interestForPeriod);
+        if 
(loanApplicationTerms.isInterestToBeRecoveredFirstWhenGreaterThanEMIEnabled() 
&& principalForThisInstallment.isLessThanZero()
+                && !loanApplicationTerms.isLastRepaymentPeriod(periodNumber)) {
+            
loanApplicationTerms.setInterestTobeApproppriated(principalForThisInstallment.abs());
+            interestForThisInstallment = 
interestForThisInstallment.minus(loanApplicationTerms.getInterestTobeApproppriated());
+            principalForThisInstallment = principalForThisInstallment.zero();
+        }
 
         // update cumulative fields for principal & interest
         final Money interestBroughtFowardDueToGrace = 
cumulatingInterestDueToGrace;
@@ -173,6 +162,9 @@ public class DecliningBalanceInterestLoanScheduleGenerator 
extends AbstractLoanS
         principalForThisInstallment = 
loanApplicationTerms.adjustPrincipalIfLastRepaymentPeriod(principalForThisInstallment,
                 totalCumulativePrincipalToDate, periodNumber);
 
-        return new PrincipalInterest(principalForThisInstallment, 
interestForThisInstallment, interestBroughtFowardDueToGrace);
+        PrincipalInterest principalInterest = new 
PrincipalInterest(principalForThisInstallment, interestForThisInstallment,
+                interestBroughtFowardDueToGrace);
+        
principalInterest.setRescheduleInterestPortion(loanApplicationTerms.getInterestTobeApproppriated());
+        return principalInterest;
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
index d2853d4..584de8c 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
@@ -327,4 +327,22 @@ public class DefaultScheduledDateGenerator implements 
ScheduledDateGenerator {
         generatedDate = adjustRepaymentDate(generatedDate, 
loanApplicationTerms, holidayDetailDTO).getChangedScheduleDate();
         return generatedDate;
     }
+
+    @Override
+    public LocalDate 
generateNextScheduleDateStartingFromDisburseDateOrRescheduleDate(LocalDate 
lastRepaymentDate,
+            LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO 
holidayDetailDTO) {
+
+        LocalDate generatedDate = 
loanApplicationTerms.getExpectedDisbursementDate();
+        boolean isFirstRepayment = true;
+        if (loanApplicationTerms.getNewScheduledDueDateStart() != null) {
+            generatedDate = loanApplicationTerms.getNewScheduledDueDateStart();
+            isFirstRepayment = false;
+        }
+        while (!generatedDate.isAfter(lastRepaymentDate)) {
+            generatedDate = generateNextRepaymentDate(generatedDate, 
loanApplicationTerms, isFirstRepayment);
+            isFirstRepayment = false;
+        }
+        generatedDate = adjustRepaymentDate(generatedDate, 
loanApplicationTerms, holidayDetailDTO).getChangedScheduleDate();
+        return generatedDate;
+    }
 }
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 6386d37..11a344b 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
@@ -188,7 +188,9 @@ public final class LoanApplicationTerms {
 
     private final boolean isFirstRepaymentDateAllowedOnHoliday;
 
-    private final boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
+    private final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI;
+
+    private boolean isPrincipalCompoundingDisabledForOverdueLoans;
 
     private final HolidayDetailDTO holidayDetailDTO;
 
@@ -209,6 +211,8 @@ public final class LoanApplicationTerms {
     private Money interestTobeApproppriated;
     private final BigDecimal fixedPrincipalPercentagePerInstallment;
 
+    private LocalDate newScheduledDueDateStart;
+
     public static LoanApplicationTerms assembleFrom(final ApplicationCurrency 
currency, final Integer loanTermFrequency,
             final PeriodFrequencyType loanTermPeriodFrequencyType, final 
Integer numberOfRepayments, final Integer repaymentEvery,
             final PeriodFrequencyType repaymentPeriodFrequencyType, Integer 
nthDay, DayOfWeekType weekDayType,
@@ -230,7 +234,8 @@ public final class LoanApplicationTerms {
             BigDecimal approvedAmount, List<LoanTermVariationsData> 
loanTermVariations,
             Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled, final 
Integer numberOfDays,
             boolean isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO 
holidayDetailDTO, final boolean allowCompoundingOnEod,
-            final boolean isEqualAmortization, final BigDecimal 
fixedPrincipalPercentagePerInstallment) {
+            final boolean isEqualAmortization, final boolean 
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
+            final BigDecimal fixedPrincipalPercentagePerInstallment, final 
boolean isPrincipalCompoundingDisabledForOverdueLoans) {
 
         final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
         final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
@@ -245,8 +250,9 @@ public final class LoanApplicationTerms {
                 recalculationFrequencyType, compoundingCalendarInstance, 
compoundingFrequencyType, principalThresholdForLastInstalment,
                 installmentAmountInMultiplesOf, 
preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, 
loanTermVariations,
                 calendarHistoryDataWrapper, 
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
-                isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, 
allowCompoundingOnEod, isEqualAmortization, false, false,
-                fixedPrincipalPercentagePerInstallment);
+                isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, 
allowCompoundingOnEod, isEqualAmortization, false,
+                isInterestToBeRecoveredFirstWhenGreaterThanEMI, 
fixedPrincipalPercentagePerInstallment,
+                isPrincipalCompoundingDisabledForOverdueLoans);
 
     }
 
@@ -273,7 +279,7 @@ public final class LoanApplicationTerms {
                 compoundingMethod, compoundingCalendarInstance, 
compoundingFrequencyType, loanPreClosureInterestCalculationStrategy,
                 rescheduleStrategyMethod, loanCalendar, approvedAmount, 
annualNominalInterestRate, loanTermVariations,
                 calendarHistoryDataWrapper, numberOfDays, 
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, 
false,
-                false, null);
+                false, null, false);
     }
 
     public static LoanApplicationTerms assembleFrom(final ApplicationCurrency 
applicationCurrency, final Integer loanTermFrequency,
@@ -291,8 +297,8 @@ public final class LoanApplicationTerms {
             BigDecimal annualNominalInterestRate, final 
List<LoanTermVariationsData> loanTermVariations,
             final CalendarHistoryDataWrapper calendarHistoryDataWrapper, final 
Integer numberOfDays,
             final boolean isSkipRepaymentOnFirstDayOfMonth, final 
HolidayDetailDTO holidayDetailDTO, final boolean allowCompoundingOnEod,
-            final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean 
isInterestToBeAppropriatedEquallyWhenGreaterThanEMI,
-            final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean 
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
+            final BigDecimal fixedPrincipalPercentagePerInstallment, final 
boolean isPrincipalCompoundingDisabledForOverdueLoans) {
 
         final Integer numberOfRepayments = 
loanProductRelatedDetail.getNumberOfRepayments();
         final Integer repaymentEvery = 
loanProductRelatedDetail.getRepayEvery();
@@ -331,7 +337,8 @@ public final class LoanApplicationTerms {
                 loanPreClosureInterestCalculationStrategy, loanCalendar, 
approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
                 isInterestChargedFromDateSameAsDisbursalDateEnabled, 
numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO,
                 allowCompoundingOnEod, isEqualAmortization, 
isFirstRepaymentDateAllowedOnHoliday,
-                isInterestToBeAppropriatedEquallyWhenGreaterThanEMI, 
fixedPrincipalPercentagePerInstallment);
+                isInterestToBeRecoveredFirstWhenGreaterThanEMI, 
fixedPrincipalPercentagePerInstallment,
+                isPrincipalCompoundingDisabledForOverdueLoans);
     }
 
     public static LoanApplicationTerms assembleFrom(final ApplicationCurrency 
applicationCurrency, final Integer loanTermFrequency,
@@ -390,7 +397,7 @@ public final class LoanApplicationTerms {
                 recalculationFrequencyType, compoundingCalendarInstance, 
compoundingFrequencyType, principalThresholdForLastInstalment,
                 installmentAmountInMultiplesOf, 
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, 
loanTermVariations,
                 calendarHistoryDataWrapper, 
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
-                isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, 
allowCompoundingOnEod, isEqualAmortization, false, false, null);
+                isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, 
allowCompoundingOnEod, isEqualAmortization, false, false, null, false);
 
     }
 
@@ -417,8 +424,8 @@ public final class LoanApplicationTerms {
                 applicationTerms.calendarHistoryDataWrapper, 
applicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled,
                 applicationTerms.numberOfDays, 
applicationTerms.isSkipRepaymentOnFirstDayOfMonth, 
applicationTerms.holidayDetailDTO,
                 applicationTerms.allowCompoundingOnEod, 
applicationTerms.isEqualAmortization,
-                applicationTerms.isFirstRepaymentDateAllowedOnHoliday, 
applicationTerms.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI,
-                applicationTerms.fixedPrincipalPercentagePerInstallment);
+                applicationTerms.isFirstRepaymentDateAllowedOnHoliday, 
applicationTerms.isInterestToBeRecoveredFirstWhenGreaterThanEMI,
+                applicationTerms.fixedPrincipalPercentagePerInstallment, 
applicationTerms.isPrincipalCompoundingDisabledForOverdueLoans);
     }
 
     private LoanApplicationTerms(final ApplicationCurrency currency, final 
Integer loanTermFrequency,
@@ -443,7 +450,8 @@ public final class LoanApplicationTerms {
             final CalendarHistoryDataWrapper calendarHistoryDataWrapper, 
Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled,
             final Integer numberOfDays, final boolean 
isSkipRepaymentOnFirstDayOfMonth, final HolidayDetailDTO holidayDetailDTO,
             final boolean allowCompoundingOnEod, final boolean 
isEqualAmortization, final boolean isFirstRepaymentDateAllowedOnHoliday,
-            final boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI, 
final BigDecimal fixedPrincipalPercentagePerInstallment) {
+            final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI, 
final BigDecimal fixedPrincipalPercentagePerInstallment,
+            final boolean isPrincipalCompoundingDisabledForOverdueLoans) {
 
         this.currency = currency;
         this.loanTermFrequency = loanTermFrequency;
@@ -517,8 +525,9 @@ public final class LoanApplicationTerms {
         this.totalPrincipalAccounted = principal.zero();
         this.isEqualAmortization = isEqualAmortization;
         this.isFirstRepaymentDateAllowedOnHoliday = 
isFirstRepaymentDateAllowedOnHoliday;
-        this.isInterestToBeAppropriatedEquallyWhenGreaterThanEMI = 
isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
+        this.isInterestToBeRecoveredFirstWhenGreaterThanEMI = 
isInterestToBeRecoveredFirstWhenGreaterThanEMI;
         this.fixedPrincipalPercentagePerInstallment = 
fixedPrincipalPercentagePerInstallment;
+        this.isPrincipalCompoundingDisabledForOverdueLoans = 
isPrincipalCompoundingDisabledForOverdueLoans;
     }
 
     public Money adjustPrincipalIfLastRepaymentPeriod(final Money 
principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -743,6 +752,10 @@ public final class LoanApplicationTerms {
         return periodNumber == numberOfRepayments;
     }
 
+    public boolean isLastRepaymentPeriod(final int periodNumber) {
+        return periodNumber == this.actualNumberOfRepayments;
+    }
+
     /**
      * general method to calculate totalInterestDue discounting any grace 
settings
      */
@@ -1248,7 +1261,7 @@ public final class LoanApplicationTerms {
         Money interestDue = Money.zero(outstandingBalance.getCurrency());
 
         final BigDecimal periodicInterestRate = 
periodicInterestRate(calculator, mc, this.daysInMonthType, this.daysInYearType,
-                periodStartDate, periodEndDate);
+                periodStartDate, periodEndDate);// 0.021232877 ob:14911.64
         interestDue = 
outstandingBalance.multiplyRetainScale(periodicInterestRate, 
mc.getRoundingMode());
 
         return interestDue;
@@ -1334,7 +1347,6 @@ public final class LoanApplicationTerms {
 
     private Money calculatePrincipalDueForInstallment(final int periodNumber, 
final Money totalDuePerInstallment,
             final Money periodInterest) {
-
         Money principal = totalDuePerInstallment.minus(periodInterest);
         if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
             principal = principal.zero();
@@ -1795,15 +1807,30 @@ public final class LoanApplicationTerms {
     }
 
     public Money getInterestTobeApproppriated() {
-        return interestTobeApproppriated;
+        return interestTobeApproppriated == null ? this.principal.zero() : 
interestTobeApproppriated;
     }
 
     public void setInterestTobeApproppriated(Money interestTobeApproppriated) {
         this.interestTobeApproppriated = interestTobeApproppriated;
     }
 
-    public boolean 
isInterestToBeAppropriatedEquallyWhenGreaterThanEMIEnabled() {
-        return isInterestToBeAppropriatedEquallyWhenGreaterThanEMI;
+    public Boolean isInterestTobeApproppriated() {
+        return interestTobeApproppriated != null && 
interestTobeApproppriated.isGreaterThanZero();
+    }
+
+    public boolean isInterestToBeRecoveredFirstWhenGreaterThanEMIEnabled() {
+        return isInterestToBeRecoveredFirstWhenGreaterThanEMI;
+    }
+
+    public boolean isPrincipalCompoundingDisabledForOverdueLoans() {
+        return isPrincipalCompoundingDisabledForOverdueLoans;
     }
 
+    public LocalDate getNewScheduledDueDateStart() {
+        return newScheduledDueDateStart;
+    }
+
+    public void setNewScheduledDueDateStart(LocalDate 
newScheduledDueDateStart) {
+        this.newScheduledDueDateStart = newScheduledDueDateStart;
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/PrincipalInterest.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/PrincipalInterest.java
index 63c77aa..3a0e724 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/PrincipalInterest.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/PrincipalInterest.java
@@ -25,6 +25,7 @@ public class PrincipalInterest {
     private final Money principal;
     private final Money interest;
     private final Money interestPaymentDueToGrace;
+    private Money rescheduleInterestPortion;
 
     public PrincipalInterest(final Money principal, final Money interest, 
final Money interestPaymentDueToGrace) {
         this.principal = principal;
@@ -43,4 +44,12 @@ public class PrincipalInterest {
     public Money interestPaymentDueToGrace() {
         return this.interestPaymentDueToGrace;
     }
+
+    public Money getRescheduleInterestPortion() {
+        return rescheduleInterestPortion;
+    }
+
+    public void setRescheduleInterestPortion(Money rescheduleInterestPortion) {
+        this.rescheduleInterestPortion = rescheduleInterestPortion;
+    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
index 969db0e..f2e6de2 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
@@ -43,4 +43,7 @@ public interface ScheduledDateGenerator {
 
     LocalDate generateNextScheduleDateStartingFromDisburseDate(LocalDate 
lastRepaymentDate, LoanApplicationTerms loanApplicationTerms,
             HolidayDetailDTO holidayDetailDTO);
+
+    LocalDate 
generateNextScheduleDateStartingFromDisburseDateOrRescheduleDate(LocalDate 
lastRepaymentDate,
+            LoanApplicationTerms loanApplicationTerms, HolidayDetailDTO 
holidayDetailDTO);
 }
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 d41e0e3..205fb84 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
@@ -448,7 +448,10 @@ public class LoanScheduleAssembler {
                 
Date.from(expectedDisbursementDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
 HolidayStatusType.ACTIVE.getValue());
         final WorkingDays workingDays = this.workingDaysRepository.findOne();
         HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, 
holidays, workingDays);
-
+        final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI = 
this.configurationDomainService
+                .isInterestToBeRecoveredFirstWhenGreaterThanEMI();
+        final boolean isPrincipalCompoundingDisabledForOverdueLoans = 
this.configurationDomainService
+                .isPrincipalCompoundingDisabledForOverdueLoans();
         return LoanApplicationTerms.assembleFrom(applicationCurrency, 
loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
                 repaymentEvery, repaymentPeriodFrequencyType, nthDay, 
weekDayType, amortizationMethod, interestMethod,
                 interestRatePerPeriod, interestRatePeriodFrequencyType, 
annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -460,7 +463,8 @@ public class LoanScheduleAssembler {
                 compoundingMethod, compoundingCalendarInstance, 
compoundingFrequencyType, principalThresholdForLastInstalment,
                 installmentAmountInMultiplesOf, 
loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO,
                 loanTermVariations, 
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, 
isSkipMeetingOnFirstDay, detailDTO,
-                allowCompoundingOnEod, isEqualAmortization, 
fixedPrincipalPercentagePerInstallment);
+                allowCompoundingOnEod, isEqualAmortization, 
isInterestToBeRecoveredFirstWhenGreaterThanEMI,
+                fixedPrincipalPercentagePerInstallment, 
isPrincipalCompoundingDisabledForOverdueLoans);
     }
 
     private CalendarInstance createCalendarForSameAsRepayment(final Integer 
repaymentEvery,
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
index ee201c8..0653a72 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java
@@ -144,15 +144,17 @@ public class LoanUtilService {
         boolean isFirstRepaymentDateAllowedOnHoliday = 
this.configurationDomainService
                 .isFirstRepaymentDateAfterRescheduleAllowedOnHoliday();
 
-        boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI = 
this.configurationDomainService
-                .isInterestToBeAppropriatedEquallyWhenGreaterThanEMI();
+        boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI = 
this.configurationDomainService
+                .isInterestToBeRecoveredFirstWhenGreaterThanEMI();
+        boolean isPrincipalCompoundingDisabledForOverdueLoans = 
this.configurationDomainService
+                .isPrincipalCompoundingDisabledForOverdueLoans();
 
         ScheduleGeneratorDTO scheduleGeneratorDTO = new 
ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
                 calculatedRepaymentsStartingFromDate, holidayDetails, 
restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
                 overdurPenaltyWaitPeriod, floatingRateDTO, calendar, 
calendarHistoryDataWrapper,
                 isInterestChargedFromDateAsDisbursementDateEnabled, 
numberOfDays, isSkipRepaymentOnFirstMonth,
                 isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled, 
isFirstRepaymentDateAllowedOnHoliday,
-                isInterestToBeAppropriatedEquallyWhenGreaterThanEMI);
+                isInterestToBeRecoveredFirstWhenGreaterThanEMI, 
isPrincipalCompoundingDisabledForOverdueLoans);
 
         return scheduleGeneratorDTO;
     }
diff --git 
a/fineract-provider/src/main/resources/sql/migrations/core_db/V392__interest_recovery_conf_for_rescedule.sql
 
b/fineract-provider/src/main/resources/sql/migrations/core_db/V392__interest_recovery_conf_for_rescedule.sql
new file mode 100644
index 0000000..c866dd0
--- /dev/null
+++ 
b/fineract-provider/src/main/resources/sql/migrations/core_db/V392__interest_recovery_conf_for_rescedule.sql
@@ -0,0 +1,29 @@
+--
+-- 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.
+--
+
+delete from c_configuration where name = 
'is-interest-to-be-appropriated-equally-when-greater-than-emi';
+
+INSERT INTO `c_configuration` (`name`, `value`, `date_value`, `enabled`, 
`is_trap_door`, `description`)
+VALUES
+    ('is-interest-to-be-recovered-first-when-greater-than-emi', 0, NULL, 0, 0, 
'If enabled, when interest amount is greater than EMI, the additional interest 
is recovered first before princupal');
+
+
+INSERT INTO `c_configuration` (`name`, `value`, `date_value`, `enabled`, 
`is_trap_door`, `description`)
+VALUES
+    ('is-principal-compounding-disabled-for-overdue-loans', 0, NULL, 0, 0, 'If 
enabled, it donot consider principal of an upaid installment for calculating 
interest of next installment. this is for testing back-dated loan sshedule');
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java
index 4734355..6fb1607 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java
@@ -225,31 +225,31 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
     }
 
     /**
-     * enables the configuration 
`is-interest-to-be-appropriated-equally-when-greater-than-emi`
+     * enables the configuration 
`is-interest-to-be-recovered-first-when-greater-than-emi`
      **/
     private void enableConfig() {
-        
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
 this.responseSpec, "34", true);
+        
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
 this.responseSpec, "42", true);
     }
 
     /**
-     * disables the configuration 
`is-interest-to-be-appropriated-equally-when-greater-than-emi`
+     * disables the configuration 
`is-interest-to-be-recovered-first-when-greater-than-emi`
      **/
     private void disableConfig() {
-        
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
 this.responseSpec, "34", false);
+        
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
 this.responseSpec, "42", false);
     }
 
     @Test
     public void testCreateLoanRescheduleRequestWithInterestAppropriation() {
         // create all required entities
         this.createRequiredEntities();
-        this.createAndApproveLoanRescheduleRequestForInterestAppropriation();
+        
this.createAndApproveLoanRescheduleRequestForRecoverInterestInterestFirst();
 
     }
 
     /**
      * create new loan reschedule request
      **/
-    private void 
createAndApproveLoanRescheduleRequestForInterestAppropriation() {
+    private void 
createAndApproveLoanRescheduleRequestForRecoverInterestInterestFirst() {
         LOG.info(
                 "---------------------------------CREATING LOAN RESCHEDULE 
REQUEST FOR INTEREST APPROPRIATTION-------------------------------------");
 
@@ -279,8 +279,8 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
         final HashMap loanSummary = 
this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, 
loanId);
         final Float totalExpectedRepayment = (Float) 
loanSummary.get("totalExpectedRepayment");
 
-        assertEquals(12186, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
is NOK");
-        assertEquals(123682, totalExpectedRepayment.intValue(), "TOTAL 
EXPECTED REPAYMENT is NOK");
+        assertEquals(10831, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
is NOK");
+        assertEquals(125184, totalExpectedRepayment.intValue(), "TOTAL 
EXPECTED REPAYMENT is NOK");
 
         LOG.info("Successfully approved loan reschedule request (ID: {})", 
this.loanRescheduleRequestId);
 
@@ -327,7 +327,7 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
         final HashMap loanSummary = 
this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, 
loanId);
         final Float totalExpectedRepayment = (Float) 
loanSummary.get("totalExpectedRepayment");
 
-        assertEquals(12326, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
is NOK");
+        assertEquals(10831, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
is NOK");
         assertEquals(131512, totalExpectedRepayment.intValue(), "TOTAL 
EXPECTED REPAYMENT is NOK");
 
         LOG.info("Successfully approved loan reschedule request (ID: {})", 
this.loanRescheduleRequestId);
@@ -338,13 +338,13 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
     public void 
testCreateLoanRescheduleRequestForInterestAppropriationAndFixedEMI() {
         // create all required entities
         this.createRequiredEntities();
-        
this.createAndApproveLoanRescheduleRequestForInterestAppropriationAndFixedEMI();
+        
this.createAndApproveLoanRescheduleRequestForRecoverInterestFirstAndFixedEMI();
     }
 
     /**
-     * create new loan reschedule request with combination of date change, 
interest appropriation and fixed emi
+     * create new loan reschedule request with combination of date change, 
recover interest first and fixed emi
      **/
-    private void 
createAndApproveLoanRescheduleRequestForInterestAppropriationAndFixedEMI() {
+    private void 
createAndApproveLoanRescheduleRequestForRecoverInterestFirstAndFixedEMI() {
         LOG.info(
                 "---------------------------------CREATING LOAN RESCHEDULE 
REQUEST FOR INTEREST APPROPRIATTION-------------------------------------");
 
@@ -379,8 +379,8 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
 
         assertEquals(5000, totalFixedDueForPeriod.intValue(), "EXPECTED FIXED 
REPAYMENT is NOK");
 
-        assertEquals(15316, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
is NOK");
-        assertEquals(120806, totalExpectedRepayment.intValue(), "TOTAL 
EXPECTED REPAYMENT is NOK");
+        assertEquals(15417, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
is NOK");
+        assertEquals(121412, totalExpectedRepayment.intValue(), "TOTAL 
EXPECTED REPAYMENT is NOK");
 
         LOG.info("Successfully approved loan reschedule request (ID: {})", 
this.loanRescheduleRequestId);
 
@@ -390,7 +390,7 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
     public void 
testCreateLoanRescheduleRequestWithMultpleInterestAppropriation() {
         // create all required entities
         this.createRequiredEntities();
-        this.createAndApproveLoanRescheduleRequestForInterestAppropriation();
+        
this.createAndApproveLoanRescheduleRequestForRecoverInterestInterestFirst();
 
         
this.createAndApproveLoanRescheduleRequestForSecondInterestAppropriation();
 
@@ -429,9 +429,105 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
         final HashMap loanSummary = 
this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, 
loanId);
         final Float totalExpectedRepayment = (Float) 
loanSummary.get("totalExpectedRepayment");
 
-        assertEquals(12187, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
in Second Reschedule is NOK");
-        assertEquals(130750, totalExpectedRepayment.intValue(), "TOTAL 
EXPECTED in Second Reschedule REPAYMENT is NOK");
+        assertEquals(10831, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT 
in Second Reschedule is NOK");
+        assertEquals(133470, totalExpectedRepayment.intValue(), "TOTAL 
EXPECTED in Second Reschedule REPAYMENT is NOK");
 
         LOG.info("Successfully approved loan reschedule request (ID: {})", 
this.loanRescheduleRequestId);
     }
+
+    @Test
+    public void 
testCreateLoanInterestGreaterThanEMIFromGapWithRecalculationEnabledAndPrincipalCompoundingOff()
 {
+        this.enableConfig();
+        this.enablePrincipalCompoundingConfig();
+        // create all required entities
+        
this.createRequiredEntitiesWithRecalculationEnabledWithPrincipalCompoundingOff();
+        
this.createApproveLoanRescheduleRequestWithRecalculationEnabledWithPrincipalCompoundingOff();
+        this.disablePrincipalCompoundingConfig();
+        this.disableConfig();
+    }
+
+    private void 
createRequiredEntitiesWithRecalculationEnabledWithPrincipalCompoundingOff() {
+        this.createClientEntity();
+        this.createLoanProductWithInterestRecalculation();
+        
this.createLoanEntityWithScheduleGapWithInterestGreaterThanEMIAndPrincipalCompoundingOff();
+    }
+
+    /**
+     * enables the configuration 
`is-principal-compounding-disabled-for-overdue-loans`
+     **/
+    private void enablePrincipalCompoundingConfig() {
+        
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
 this.responseSpec, "43", true);
+    }
+
+    /**
+     * disables the configuration 
`is-principal-compounding-disabled-for-overdue-loans`
+     **/
+    private void disablePrincipalCompoundingConfig() {
+        
GlobalConfigurationHelper.updateEnabledFlagForGlobalConfiguration(this.requestSpec,
 this.responseSpec, "43", false);
+    }
+
+    /**
+     * submit a new loan application, approve and disburse the loan
+     **/
+    private void 
createLoanEntityWithScheduleGapWithInterestGreaterThanEMIAndPrincipalCompoundingOff()
 {
+        String firstRepaymentDate = "01 January 2015";
+
+        LOG.info("---------------------------------NEW LOAN 
APPLICATION------------------------------------------");
+
+        final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal("15000").withLoanTermFrequency("24")
+                
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("24").withRepaymentEveryAfter("1")
+                
.withRepaymentFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestCalculationPeriodTypeAsDays()
+                
.withInterestRatePerPeriod("25").withInterestTypeAsDecliningBalance().withSubmittedOnDate(this.dateString)
+                
.withExpectedDisbursementDate(this.dateString).withFirstRepaymentDate(firstRepaymentDate)
+                
.withinterestChargedFromDate(this.dateString).build(this.clientId.toString(), 
this.loanProductId.toString(), null);
+
+        this.loanId = 
this.loanTransactionHelper.getLoanId(loanApplicationJSON);
+
+        LOG.info("Sucessfully created loan (ID: {} )", this.loanId);
+
+        this.approveLoanApplication();
+        this.disburseLoan();
+    }
+
+    /**
+     * create new loan reschedule request with recalculation enabled in Loan 
product
+     **/
+
+    private void 
createApproveLoanRescheduleRequestWithRecalculationEnabledWithPrincipalCompoundingOff()
 {
+        LOG.info(
+                "---------------------------------CREATING LOAN RESCHEDULE 
REQUEST FOR LOAN WITH RECALCULATION------------------------------------");
+
+        final String requestJSON = new 
LoanRescheduleRequestTestBuilder().updateGraceOnPrincipal(null).updateGraceOnInterest(null)
+                .updateExtraTerms(null).updateRescheduleFromDate("01 March 
2015").updateAdjustedDueDate("01 July 2015")
+                .updateRecalculateInterest(true).build(this.loanId.toString());
+
+        this.loanRescheduleRequestId = 
this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
+        
this.loanRescheduleRequestHelper.verifyCreationOfLoanRescheduleRequest(this.loanRescheduleRequestId);
+
+        LOG.info("Successfully created loan reschedule request (ID: {} )", 
this.loanRescheduleRequestId);
+
+        final String aproveRequestJSON = new 
LoanRescheduleRequestTestBuilder().getApproveLoanRescheduleRequestJSON();
+        
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(this.loanRescheduleRequestId,
 aproveRequestJSON);
+        final HashMap response = (HashMap) 
this.loanRescheduleRequestHelper.getLoanRescheduleRequest(loanRescheduleRequestId,
 "statusEnum");
+        assertTrue((Boolean) response.get("approved"));
+
+        LOG.info("Successfully approved loan reschedule request (ID: {})", 
this.loanRescheduleRequestId);
+
+        final Map repaymentSchedule = (Map) 
this.loanTransactionHelper.getLoanDetail(requestSpec, generalResponseSpec, 
loanId,
+                "repaymentSchedule");
+        final ArrayList periods = (ArrayList) repaymentSchedule.get("periods");
+
+        HashMap period = (HashMap) periods.get(5);
+        Float totalDueForPeriod = (Float) period.get("totalDueForPeriod");
+
+        final HashMap loanSummary = 
this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, 
loanId);
+        final Float totalExpectedRepayment = (Float) 
loanSummary.get("totalExpectedRepayment");
+
+        assertEquals(798, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT is 
NOK");
+        assertEquals(22567, totalExpectedRepayment.intValue(), "TOTAL EXPECTED 
REPAYMENT is NOK");
+
+        LOG.info("Successfully approved loan reschedule request (ID: {})", 
this.loanRescheduleRequestId);
+
+    }
+
 }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
index 9ff751e..a58551a 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
@@ -90,8 +90,8 @@ public class GlobalConfigurationHelper {
         ArrayList<HashMap> actualGlobalConfigurations = 
getAllGlobalConfigurations(requestSpec, responseSpec);
 
         // There are currently 37 global configurations.
-        Assertions.assertEquals(37, expectedGlobalConfigurations.size());
-        Assertions.assertEquals(37, actualGlobalConfigurations.size());
+        Assertions.assertEquals(38, expectedGlobalConfigurations.size());
+        Assertions.assertEquals(38, actualGlobalConfigurations.size());
 
         for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
 
@@ -355,14 +355,6 @@ public class GlobalConfigurationHelper {
         isFirstPaydayAllowedOnHoliday.put("trapDoor", false);
         defaults.add(isFirstPaydayAllowedOnHoliday);
 
-        HashMap<String, Object> isInterestAppropriationEnabled = new 
HashMap<>();
-        isInterestAppropriationEnabled.put("id", 34);
-        isInterestAppropriationEnabled.put("name", 
"is-interest-to-be-appropriated-equally-when-greater-than-emi");
-        isInterestAppropriationEnabled.put("value", 0);
-        isInterestAppropriationEnabled.put("enabled", false);
-        isInterestAppropriationEnabled.put("trapDoor", false);
-        defaults.add(isInterestAppropriationEnabled);
-
         HashMap<String, Object> isAccountMappedForPayment = new HashMap<>();
         isAccountMappedForPayment.put("id", 35);
         isAccountMappedForPayment.put("name", 
"account-mapping-for-payment-type");
@@ -423,6 +415,22 @@ public class GlobalConfigurationHelper {
         isAccountNumberRandomGenerated.put("trapDoor", false);
         defaults.add(isAccountNumberRandomGenerated);
 
+        HashMap<String, Object> isInterestAppropriationEnabled = new 
HashMap<>();
+        isInterestAppropriationEnabled.put("id", 42);
+        isInterestAppropriationEnabled.put("name", 
"is-interest-to-be-recovered-first-when-greater-than-emi");
+        isInterestAppropriationEnabled.put("value", 0);
+        isInterestAppropriationEnabled.put("enabled", false);
+        isInterestAppropriationEnabled.put("trapDoor", false);
+        defaults.add(isInterestAppropriationEnabled);
+
+        HashMap<String, Object> isPrincipalCompoundingDisabled = new 
HashMap<>();
+        isPrincipalCompoundingDisabled.put("id", 43);
+        isPrincipalCompoundingDisabled.put("name", 
"is-principal-compounding-disabled-for-overdue-loans");
+        isPrincipalCompoundingDisabled.put("value", 0);
+        isPrincipalCompoundingDisabled.put("enabled", false);
+        isPrincipalCompoundingDisabled.put("trapDoor", false);
+        defaults.add(isPrincipalCompoundingDisabled);
+
         return defaults;
     }
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
index a0d17f8..06fb68a 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
@@ -77,6 +77,7 @@ public class LoanApplicationTestBuilder {
     private List<HashMap<String, Object>> datatables = null;
     private List<Map<String, Object>> approvalFormData = null;
     private String fixedPrincipalPercentagePerInstallment;
+    private String interestChargedFromDate;
 
     public String build(final String clientID, final String groupID, final 
String loanProductId, final String savingsID) {
         final HashMap<String, Object> map = new HashMap<>();
@@ -150,6 +151,7 @@ public class LoanApplicationTestBuilder {
         map.put("submittedOnDate", this.submittedOnDate);
         map.put("loanType", this.loanType);
         map.put("collateral", this.collaterals);
+        map.put("interestChargedFromDate", this.interestChargedFromDate);
 
         if (repaymentsStartingFromDate != null) {
             map.put("repaymentsStartingFromDate", 
this.repaymentsStartingFromDate);
@@ -382,4 +384,9 @@ public class LoanApplicationTestBuilder {
         this.fixedPrincipalPercentagePerInstallment = 
fixedPrincipalPercentagePerInstallment;
         return this;
     }
+
+    public LoanApplicationTestBuilder withinterestChargedFromDate(String 
interestChargedFromDate) {
+        this.interestChargedFromDate = interestChargedFromDate;
+        return this;
+    }
 }

Reply via email to