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

<TRUNCATED>

Reply via email to