in fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java [178:552]
private LoanApplicationTerms assembleLoanApplicationTermsFrom(final JsonElement element, final LoanProduct loanProduct) {
final Boolean allowOverridingAmortization = loanProduct.getLoanConfigurableAttributes().getAmortizationBoolean();
final Boolean allowOverridingArrearsTolerance = loanProduct.getLoanConfigurableAttributes().getArrearsToleranceBoolean();
final Boolean allowOverridingGraceOnArrearsAging = loanProduct.getLoanConfigurableAttributes().getGraceOnArrearsAgingBoolean();
final Boolean allowOverridingInterestCalcPeriod = loanProduct.getLoanConfigurableAttributes().getInterestCalcPeriodBoolean();
final Boolean allowOverridingInterestMethod = loanProduct.getLoanConfigurableAttributes().getInterestMethodBoolean();
final Boolean allowOverridingGraceOnPrincipalAndInterestPayment = loanProduct.getLoanConfigurableAttributes()
.getGraceOnPrincipalAndInterestPaymentBoolean();
final Boolean allowOverridingRepaymentEvery = loanProduct.getLoanConfigurableAttributes().getRepaymentEveryBoolean();
final MonetaryCurrency currency = loanProduct.getCurrency();
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
// loan terms
final Integer loanTermFrequency = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequency", element);
final Integer loanTermFrequencyType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequencyType", element);
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(loanTermFrequencyType);
final Integer numberOfRepayments = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
final Integer repaymentEvery = allowOverridingRepaymentEvery
? this.fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element)
: loanProduct.getLoanProductRelatedDetail().getRepayEvery();
final Integer repaymentFrequencyType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element);
final PeriodFrequencyType repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyType);
final Integer nthDay = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyNthDayType", element);
final Integer dayOfWeek = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyDayOfWeekType", element);
final DayOfWeekType weekDayType = DayOfWeekType.fromInt(dayOfWeek);
final Integer amortizationType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element);
final AmortizationMethod amortizationMethod = allowOverridingAmortization ? AmortizationMethod.fromInt(amortizationType)
: loanProduct.getLoanProductRelatedDetail().getAmortizationMethod();
boolean isEqualAmortization = false;
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.isEqualAmortizationParam, element)) {
isEqualAmortization = this.fromApiJsonHelper.extractBooleanNamed(LoanApiConstants.isEqualAmortizationParam, element);
}
BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, element);
// interest terms
final Integer interestType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
final InterestMethod interestMethod = allowOverridingInterestMethod ? InterestMethod.fromInt(interestType)
: loanProduct.getLoanProductRelatedDetail().getInterestMethod();
final Integer interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType",
element);
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = allowOverridingInterestCalcPeriod
? InterestCalculationPeriodMethod.fromInt(interestCalculationPeriodType)
: loanProduct.getLoanProductRelatedDetail().getInterestCalculationPeriodMethod();
Boolean allowPartialPeriodInterestCalcualtion = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME, element);
if (allowPartialPeriodInterestCalcualtion == null) {
allowPartialPeriodInterestCalcualtion = loanProduct.getLoanProductRelatedDetail().isAllowPartialPeriodInterestCalcualtion();
}
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
PeriodFrequencyType interestRatePeriodFrequencyType = loanProduct.getInterestPeriodFrequencyType();
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.interestRateFrequencyTypeParameterName, element)) {
final Integer interestRateFrequencyType = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed(LoanApiConstants.interestRateFrequencyTypeParameterName, element);
interestRatePeriodFrequencyType = PeriodFrequencyType.fromInt(interestRateFrequencyType);
}
BigDecimal annualNominalInterestRate = BigDecimal.ZERO;
if (interestRatePerPeriod != null) {
annualNominalInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRatePerPeriod,
numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType);
}
// disbursement details
final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
final Money principalMoney = Money.of(currency, principal);
final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element);
LocalDate repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element);
final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element);
final RepaymentStartDateType repaymentStartDateType = loanProduct.getRepaymentStartDateType();
LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate;
final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element);
Calendar calendar = null;
final String loanTypeParameterName = "loanType";
final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
final AccountType loanType = AccountType.fromName(loanTypeStr);
/*
* If it is JLG loan/Group Loan then make sure loan frequency is same as Group/Center meeting frequency or
* multiple of it. TODO: Check should be either same frequency or loan freq is multiple of center/group meeting
* freq multiples
*/
if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendarId != null) {
calendar = this.calendarRepository.findById(calendarId).orElseThrow(() -> new CalendarNotFoundException(calendarId));
final PeriodFrequencyType meetingPeriodFrequency = CalendarUtils.getMeetingPeriodFrequencyType(calendar.getRecurrence());
validateRepaymentFrequencyIsSameAsMeetingFrequency(meetingPeriodFrequency.getValue(), repaymentFrequencyType,
CalendarUtils.getInterval(calendar.getRecurrence()), repaymentEvery);
} else {
if (repaymentPeriodFrequencyType == PeriodFrequencyType.MONTHS && nthDay != null
&& !nthDay.equals(NthDayType.INVALID.getValue())) {
LocalDate calendarStartDate = repaymentsStartingFromDate;
if (calendarStartDate == null) {
calendarStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType) ? expectedDisbursementDate
: submittedOnDate;
}
calendar = createLoanCalendar(calendarStartDate, repaymentEvery, CalendarFrequencyType.MONTHLY, dayOfWeek, nthDay);
}
}
/*
* If user has not passed the first repayments date then then derive the same based on loan type.
*/
if (calculatedRepaymentsStartingFromDate == null) {
LocalDate tmpCalculatedRepaymentsStartingFromDate = deriveFirstRepaymentDate(loanType, repaymentEvery, expectedDisbursementDate,
repaymentPeriodFrequencyType, 0, calendar, submittedOnDate, repaymentStartDateType);
calculatedRepaymentsStartingFromDate = deriveFirstRepaymentDate(loanType, repaymentEvery, expectedDisbursementDate,
repaymentPeriodFrequencyType, loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment(), calendar, submittedOnDate,
repaymentStartDateType);
// If calculated repayment start date does not match due to minimum days between disbursal and first
// repayment rule, we set repaymentsStartingFromDate (which will be used as seed date later)
if (!tmpCalculatedRepaymentsStartingFromDate.equals(calculatedRepaymentsStartingFromDate)) {
repaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
}
}
/*
* If it is JLG loan/Group Loan synched with a meeting, then make sure first repayment falls on meeting date
*/
final Long groupId = this.fromApiJsonHelper.extractLongNamed("groupId", element);
Group group = null;
if (groupId != null) {
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
}
Boolean isSkipMeetingOnFirstDay = false;
Integer numberOfDays = 0;
boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
isSkipMeetingOnFirstDay = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(group, calendar);
if (isSkipMeetingOnFirstDay) {
numberOfDays = configurationDomainService.retreivePeriodInNumberOfDaysForSkipMeetingDate().intValue();
}
}
if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendar != null) {
validateRepaymentsStartDateWithMeetingDates(calculatedRepaymentsStartingFromDate, calendar, isSkipMeetingOnFirstDay,
numberOfDays);
}
if (RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)) {
validateMinimumDaysBetweenDisbursalAndFirstRepayment(expectedDisbursementDate, calculatedRepaymentsStartingFromDate,
loanProduct.getMinimumDaysBetweenDisbursalAndFirstRepayment());
}
// grace details
final Integer graceOnPrincipalPayment = allowOverridingGraceOnPrincipalAndInterestPayment
? this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element)
: loanProduct.getLoanProductRelatedDetail().getGraceOnPrincipalPayment();
final Integer recurringMoratoriumOnPrincipalPeriods = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed("recurringMoratoriumOnPrincipalPeriods", element);
final Integer graceOnInterestPayment = allowOverridingGraceOnPrincipalAndInterestPayment
? this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element)
: loanProduct.getLoanProductRelatedDetail().getGraceOnInterestPayment();
final Integer graceOnInterestCharged = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestCharged", element);
final LocalDate interestChargedFromDate = this.fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);
final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = this.configurationDomainService
.isInterestChargedFromDateSameAsDisbursementDate();
final Integer graceOnArrearsAgeing = allowOverridingGraceOnArrearsAging
? this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME, element)
: loanProduct.getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
// other
final BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
final Money inArrearsToleranceMoney = allowOverridingArrearsTolerance ? Money.of(currency, inArrearsTolerance)
: loanProduct.getLoanProductRelatedDetail().getInArrearsTolerance();
final BigDecimal emiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedEmiAmountParameterName,
element);
final BigDecimal maxOutstandingBalance = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanApiConstants.maxOutstandingBalanceParameterName, element);
final List<DisbursementData> disbursementDatas = fetchDisbursementData(element.getAsJsonObject());
/**
* Interest recalculation settings copy from product definition
*/
final DaysInMonthType daysInMonthType = loanProduct.fetchDaysInMonthType();
DaysInYearType daysInYearType = null;
final Integer daysInYearTypeIntFromApplication = this.fromApiJsonHelper
.extractIntegerNamed(LoanApiConstants.daysInYearTypeParameterName, element, Locale.getDefault());
if (daysInYearTypeIntFromApplication != null) {
daysInYearType = DaysInYearType.fromInt(daysInYearTypeIntFromApplication);
} else {
daysInYearType = loanProduct.fetchDaysInYearType();
}
final boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled();
RecalculationFrequencyType recalculationFrequencyType = null;
CalendarInstance restCalendarInstance = null;
RecalculationFrequencyType compoundingFrequencyType = null;
CalendarInstance compoundingCalendarInstance = null;
InterestRecalculationCompoundingMethod compoundingMethod = null;
boolean allowCompoundingOnEod = false;
final Boolean isFloatingInterestRate = this.fromApiJsonHelper
.extractBooleanNamed(LoanApiConstants.isFloatingInterestRateParameterName, element);
if (isInterestRecalculationEnabled) {
LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails = loanProduct
.getProductInterestRecalculationDetails();
recalculationFrequencyType = loanProductInterestRecalculationDetails.getRestFrequencyType();
Integer repeatsOnDay = null;
Integer recalculationFrequencyNthDay = loanProductInterestRecalculationDetails.getRestFrequencyOnDay();
if (recalculationFrequencyNthDay == null) {
recalculationFrequencyNthDay = loanProductInterestRecalculationDetails.getRestFrequencyNthDay();
repeatsOnDay = loanProductInterestRecalculationDetails.getRestFrequencyWeekday();
}
Integer frequency = loanProductInterestRecalculationDetails.getRestInterval();
if (recalculationFrequencyType.isSameAsRepayment()) {
restCalendarInstance = createCalendarForSameAsRepayment(repaymentEvery, repaymentPeriodFrequencyType,
expectedDisbursementDate);
} else {
LocalDate calendarStartDate = expectedDisbursementDate;
restCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, recalculationFrequencyType, frequency,
recalculationFrequencyNthDay, repeatsOnDay);
}
compoundingMethod = InterestRecalculationCompoundingMethod
.fromInt(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod());
if (compoundingMethod.isCompoundingEnabled()) {
Integer compoundingRepeatsOnDay = null;
Integer recalculationCompoundingFrequencyNthDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay();
if (recalculationCompoundingFrequencyNthDay == null) {
recalculationCompoundingFrequencyNthDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyNthDay();
compoundingRepeatsOnDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday();
}
compoundingFrequencyType = loanProductInterestRecalculationDetails.getCompoundingFrequencyType();
if (compoundingFrequencyType.isSameAsRepayment()) {
compoundingCalendarInstance = createCalendarForSameAsRepayment(repaymentEvery, repaymentPeriodFrequencyType,
expectedDisbursementDate);
} else {
LocalDate calendarStartDate = expectedDisbursementDate;
compoundingCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, compoundingFrequencyType,
loanProductInterestRecalculationDetails.getCompoundingInterval(), recalculationCompoundingFrequencyNthDay,
compoundingRepeatsOnDay);
}
allowCompoundingOnEod = loanProductInterestRecalculationDetails.getAllowCompoundingOnEod();
}
}
final BigDecimal principalThresholdForLastInstalment = loanProduct.getPrincipalThresholdForLastInstallment();
final Integer installmentAmountInMultiplesOf = loanProduct.getInstallmentAmountInMultiplesOf();
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
if (loanProduct.isLinkedToFloatingInterestRate()) {
final BigDecimal interestRateDiff = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanApiConstants.interestRateDifferentialParameterName, element);
List<FloatingRatePeriodData> baseLendingRatePeriods = null;
try {
baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate().getRatePeriods();
} catch (final FloatingRateNotFoundException ex) {
// Do not do anything
}
FloatingRateDTO floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, expectedDisbursementDate, interestRateDiff,
baseLendingRatePeriods);
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
LocalDate interestRateStartDate = DateUtils.getBusinessLocalDate();
final LocalDate dateValue = null;
final boolean isSpecificToInstallment = false;
for (FloatingRatePeriodData periodData : applicableRates) {
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
LoanEnumerations.loanVariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
periodData.getInterestRate(), dateValue, isSpecificToInstallment);
if (!DateUtils.isBefore(interestRateStartDate, periodData.getFromDateAsLocalDate())) {
interestRateStartDate = periodData.getFromDateAsLocalDate();
annualNominalInterestRate = periodData.getInterestRate();
}
loanTermVariations.add(loanTermVariation);
}
}
final Long clientId = this.fromApiJsonHelper.extractLongNamed("clientId", element);
Client client = null;
Long officeId = null;
if (clientId != null) {
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
officeId = client.getOffice().getId();
} else if (groupId != null) {
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
officeId = group.getOffice().getId();
}
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, expectedDisbursementDate,
HolidayStatusType.ACTIVE.getValue());
final WorkingDays workingDays = this.workingDaysRepository.findOne();
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI = this.configurationDomainService
.isInterestToBeRecoveredFirstWhenGreaterThanEMI();
final boolean isPrincipalCompoundingDisabledForOverdueLoans = this.configurationDomainService
.isPrincipalCompoundingDisabledForOverdueLoans();
boolean isDownPaymentEnabled = loanProduct.getLoanProductRelatedDetail().isEnableDownPayment();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_DOWN_PAYMENT, element)) {
isDownPaymentEnabled = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.ENABLE_DOWN_PAYMENT, element);
}
BigDecimal disbursedAmountPercentageForDownPayment = null;
boolean isAutoRepaymentForDownPaymentEnabled = false;
if (isDownPaymentEnabled) {
isAutoRepaymentForDownPaymentEnabled = loanProduct.getLoanProductRelatedDetail().isEnableAutoRepaymentForDownPayment();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, element)) {
isAutoRepaymentForDownPaymentEnabled = this.fromApiJsonHelper
.extractBooleanNamed(LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, element);
}
disbursedAmountPercentageForDownPayment = loanProduct.getLoanProductRelatedDetail()
.getDisbursedAmountPercentageForDownPayment();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, element)) {
disbursedAmountPercentageForDownPayment = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT, element);
}
}
LoanScheduleType loanScheduleType = loanProduct.getLoanProductRelatedDetail().getLoanScheduleType();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_TYPE, element)) {
loanScheduleType = LoanScheduleType
.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_TYPE, element));
}
LoanScheduleProcessingType loanScheduleProcessingType = loanProduct.getLoanProductRelatedDetail().getLoanScheduleProcessingType();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, element)) {
loanScheduleProcessingType = LoanScheduleProcessingType
.valueOf(this.fromApiJsonHelper.extractStringNamed(LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, element));
}
Integer fixedLength = loanProduct.getLoanProductRelatedDetail().getFixedLength();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.FIXED_LENGTH, element)) {
fixedLength = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.FIXED_LENGTH, element);
}
Boolean interestRecognitionOnDisbursementDate = loanProduct.getLoanProductRelatedDetail().isInterestRecognitionOnDisbursementDate();
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, element)) {
interestRecognitionOnDisbursementDate = this.fromApiJsonHelper
.extractBooleanNamed(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, element);
}
return LoanApplicationTerms.assembleFrom(applicationCurrency.toData(), loanTermFrequency, loanTermPeriodFrequencyType,
numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods,
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney,
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, graceOnArrearsAgeing,
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType, restCalendarInstance,
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO,
loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
allowCompoundingOnEod, isEqualAmortization, isInterestToBeRecoveredFirstWhenGreaterThanEMI,
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
loanScheduleType, loanScheduleProcessingType, fixedLength,
loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting(),
loanProduct.getLoanProductRelatedDetail().getSupportedInterestRefundTypes(),
loanProduct.getLoanProductRelatedDetail().getChargeOffBehaviour(), interestRecognitionOnDisbursementDate,
loanProduct.getLoanProductRelatedDetail().getDaysInYearCustomStrategy(),
loanProduct.getLoanProductRelatedDetail().isEnableIncomeCapitalization(),
loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeCalculationType(),
loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeStrategy(),
loanProduct.getLoanProductRelatedDetail().getCapitalizedIncomeType());
}