FINERACT-2181: Installment amount in multiples of should be inherited from loan product to loan level

This commit is contained in:
Jose Alberto Hernandez
2025-06-06 10:54:29 +02:00
committed by Adam Saghy
parent 95a8231b18
commit 39a8d5c63e
16 changed files with 94 additions and 36 deletions
@@ -1616,7 +1616,7 @@ public final class LoanApplicationTerms {
this.loanScheduleProcessingType, this.fixedLength, this.enableAccrualActivityPosting, this.supportedInterestRefundTypes,
this.chargeOffBehaviour, this.interestRecognitionOnDisbursementDate, this.daysInYearCustomStrategy,
this.enableIncomeCapitalization, this.capitalizedIncomeCalculationType, this.capitalizedIncomeStrategy,
this.capitalizedIncomeType);
this.capitalizedIncomeType, this.installmentAmountInMultiplesOf);
}
public LoanProductMinimumRepaymentScheduleRelatedDetail toLoanProductRelatedDetailMinimumData() {
@@ -112,8 +112,9 @@ public class LoanTermVariationsMapper {
scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), loan.getInArrearsTolerance(),
loan.getLoanRepaymentScheduleDetail(), loan.getLoanProduct().isMultiDisburseLoan(), loan.getFixedEmiAmount(),
disbursementData, loan.getMaxOutstandingLoanBalance(), interestChargedFromDate,
loan.getLoanProduct().getPrincipalThresholdForLastInstallment(), loan.getLoanProduct().getInstallmentAmountInMultiplesOf(),
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
loan.getLoanProduct().getPrincipalThresholdForLastInstallment(),
loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance,
compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
loan.getLoanProduct().preCloseInterestCalculationStrategy(), rescheduleStrategyMethod, calendar,
loan.getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper,
scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), holidayDetailDTO,
@@ -197,8 +197,9 @@ public class LoanDownPaymentHandlerServiceImpl implements LoanDownPaymentHandler
}
Money downPaymentMoney = Money.of(loan.getCurrency(),
MathUtil.percentageOf(disbursementTransaction.getAmount(), disbursedAmountPercentageForDownPayment, 19));
if (loan.getLoanProduct().getInstallmentAmountInMultiplesOf() != null) {
downPaymentMoney = Money.roundToMultiplesOf(downPaymentMoney, loan.getLoanProduct().getInstallmentAmountInMultiplesOf());
if (loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf() != null) {
downPaymentMoney = Money.roundToMultiplesOf(downPaymentMoney,
loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf());
}
final Money adjustedDownPaymentMoney = switch (loan.getLoanProductRelatedDetail().getLoanScheduleType()) {
// For Cumulative loan: To check whether the loan was overpaid when the disbursement happened and to get the
@@ -179,9 +179,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
@Column(name = "can_define_fixed_emi_amount")
private boolean canDefineInstallmentAmount;
@Column(name = "instalment_amount_in_multiples_of")
private Integer installmentAmountInMultiplesOf;
@Column(name = "is_linked_to_floating_interest_rates", nullable = false)
private boolean isLinkedToFloatingInterestRate;
@@ -336,7 +333,8 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
isInterestRecalculationEnabled, isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment,
enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting,
supportedInterestRefundTypes, chargeOffBehaviour, isInterestRecognitionOnDisbursementDate, daysInYearCustomStrategy,
enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType);
enableIncomeCapitalization, capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType,
installmentAmountInMultiplesOf);
this.loanProductMinMaxConstraints = new LoanProductMinMaxConstraints(defaultMinPrincipal, defaultMaxPrincipal,
defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultMinNumberOfInstallments,
@@ -368,7 +366,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
this.principalThresholdForLastInstallment = principalThresholdForLastInstallment;
this.accountMovesOutOfNPAOnlyOnArrearsCompletion = accountMovesOutOfNPAOnlyOnArrearsCompletion;
this.canDefineInstallmentAmount = canDefineEmiAmount;
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
this.canUseForTopup = canUseForTopup;
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
@@ -186,6 +186,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "capitalized_income_type")
private LoanCapitalizedIncomeType capitalizedIncomeType;
@Column(name = "installment_amount_in_multiples_of")
private Integer installmentAmountInMultiplesOf;
public static LoanProductRelatedDetail createFrom(final CurrencyData currencyData, final BigDecimal principal,
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
@@ -202,7 +205,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate,
final DaysInYearCustomStrategyType daysInYearCustomStrategy, final boolean enableIncomeCapitalization,
final LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType,
final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType) {
final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType,
final Integer installmentAmountInMultiplesOf) {
final MonetaryCurrency currency = MonetaryCurrency.fromCurrencyData(currencyData);
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
@@ -213,7 +217,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment,
loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes,
chargeOffBehaviour, interestRecognitionOnDisbursementDate, daysInYearCustomStrategy, enableIncomeCapitalization,
capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType);
capitalizedIncomeCalculationType, capitalizedIncomeStrategy, capitalizedIncomeType, installmentAmountInMultiplesOf);
}
protected LoanProductRelatedDetail() {
@@ -236,7 +240,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate,
final DaysInYearCustomStrategyType daysInYearCustomStrategy, final boolean enableIncomeCapitalization,
final LoanCapitalizedIncomeCalculationType capitalizedIncomeCalculationType,
final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType) {
final LoanCapitalizedIncomeStrategy capitalizedIncomeStrategy, final LoanCapitalizedIncomeType capitalizedIncomeType,
final Integer installmentAmountInMultiplesOf) {
this.currency = currency;
this.principal = defaultPrincipal;
this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod;
@@ -278,6 +283,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.capitalizedIncomeCalculationType = capitalizedIncomeCalculationType;
this.capitalizedIncomeStrategy = capitalizedIncomeStrategy;
this.capitalizedIncomeType = capitalizedIncomeType;
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
}
private Integer defaultToNullIfZero(final Integer value) {
@@ -51,4 +51,5 @@
<include relativeToChangelogFile="true" file="parts/1026_add_interest_recognition_flag.xml"/>
<include relativeToChangelogFile="true" file="parts/1027_add_capitalized_income_transaction_type.xml"/>
<include relativeToChangelogFile="true" file="parts/1028_add_missing_indexes.xml"/>
<include relativeToChangelogFile="true" file="parts/1029_add_installment_amount_in_multiples_of_to_loan.xml"/>
</databaseChangeLog>
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
<changeSet author="fineract" id="1029-1">
<addColumn tableName="m_loan">
<column defaultValueComputed="NULL" name="installment_amount_in_multiples_of" type="DECIMAL(19, 6)"/>
</addColumn>
</changeSet>
<changeSet author="fineract" id="1029-2" objectQuotingStrategy="QUOTE_ALL_OBJECTS">
<renameColumn tableName="m_product_loan" oldColumnName="instalment_amount_in_multiples_of" newColumnName="installment_amount_in_multiples_of" columnDataType="DECIMAL(19, 6)"/>
</changeSet>
<changeSet author="fineract" id="1029-3-postgresql" context="postgresql">
<sql>
UPDATE m_loan SET installment_amount_in_multiples_of = lp.installment_amount_in_multiples_of FROM (
SELECT id, installment_amount_in_multiples_of FROM m_product_loan
) lp WHERE lp.id = m_loan.product_id
</sql>
</changeSet>
<changeSet author="fineract" id="1029-3-mysql" context="mysql">
<sql>
UPDATE m_loan l inner join m_product_loan lp on lp.id = l.product_id set l.installment_amount_in_multiples_of = lp.installment_amount_in_multiples_of
</sql>
</changeSet>
</databaseChangeLog>
@@ -215,7 +215,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
final Loan loan = loanTransactions.get(0).getLoan();
List<LoanTermVariationsData> loanTermVariations = loan.getActiveLoanTermVariations().stream().map(LoanTermVariations::toData)
.collect(Collectors.toCollection(ArrayList::new));
final Integer installmentAmountInMultiplesOf = loan.getLoanProduct().getInstallmentAmountInMultiplesOf();
final Integer installmentAmountInMultiplesOf = loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf();
final LoanProductRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
ProgressiveLoanInterestScheduleModel scheduleModel = emiCalculator.generateInstallmentInterestScheduleModel(installments,
loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, overpaymentHolder.getMoneyObject().getMc());
@@ -464,7 +464,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
.max(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate)).get();
BigDecimal reAmortizationAmountPerInstallment = overallOverDuePrincipal.divide(BigDecimal.valueOf(futureInstallments.size()),
MoneyHelper.getRoundingMode());
Integer installmentAmountInMultiplesOf = loanTransaction.getLoan().getLoanProduct().getInstallmentAmountInMultiplesOf();
Integer installmentAmountInMultiplesOf = loanTransaction.getLoan().getLoanProductRelatedDetail()
.getInstallmentAmountInMultiplesOf();
for (LoanRepaymentScheduleInstallment installment : futureInstallments) {
if (lastFutureInstallment.equals(installment)) {
@@ -1225,7 +1226,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
final MathContext mc = MoneyHelper.getMathContext();
Loan loan = disbursementTransaction.getLoan();
LoanProductRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
Integer installmentAmountInMultiplesOf = loan.getLoanProduct().getInstallmentAmountInMultiplesOf();
Integer installmentAmountInMultiplesOf = loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf();
List<LoanRepaymentScheduleInstallment> installments = transactionCtx.getInstallments();
LocalDate transactionDate = disbursementTransaction.getTransactionDate();
MonetaryCurrency currency = transactionCtx.getCurrency();
@@ -1259,7 +1260,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
i -> i.getDueDate().isAfter(disbursementTransaction.getTransactionDate()) && !i.isDownPayment() && !i.isAdditional())
.toList();
LoanProductRelatedDetail loanProductRelatedDetail = disbursementTransaction.getLoan().getLoanRepaymentScheduleDetail();
Integer installmentAmountInMultiplesOf = disbursementTransaction.getLoan().getLoanProduct().getInstallmentAmountInMultiplesOf();
Integer installmentAmountInMultiplesOf = disbursementTransaction.getLoan().getLoanProductRelatedDetail()
.getInstallmentAmountInMultiplesOf();
Money downPaymentAmount = Money.zero(currency);
if (loanProductRelatedDetail.isEnableDownPayment()) {
LoanRepaymentScheduleInstallment downPaymentInstallment = installments.stream()
@@ -1311,7 +1313,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
List<LoanRepaymentScheduleInstallment> candidateRepaymentInstallments = installments.stream().filter(
i -> i.getDueDate().isAfter(capitalizedIncomeTransaction.getTransactionDate()) && !i.isDownPayment() && !i.isAdditional())
.toList();
Integer installmentAmountInMultiplesOf = capitalizedIncomeTransaction.getLoan().getLoanProduct()
Integer installmentAmountInMultiplesOf = capitalizedIncomeTransaction.getLoan().getLoanProduct().getLoanProductRelatedDetail()
.getInstallmentAmountInMultiplesOf();
Money amortizableAmount = capitalizedIncomeTransaction.getAmount(currency);
@@ -2622,7 +2624,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
if (outstandingPrincipalBalance.get().isGreaterThanZero()) {
calculatedPrincipal = outstandingPrincipalBalance.get()
.dividedBy(loanTransaction.getLoanReAgeParameter().getNumberOfInstallments(), MoneyHelper.getMathContext());
Integer installmentAmountInMultiplesOf = loanTransaction.getLoan().getLoanProduct().getInstallmentAmountInMultiplesOf();
Integer installmentAmountInMultiplesOf = loanTransaction.getLoan().getLoanProductRelatedDetail()
.getInstallmentAmountInMultiplesOf();
if (installmentAmountInMultiplesOf != null) {
calculatedPrincipal = Money.roundToMultiplesOf(calculatedPrincipal, installmentAmountInMultiplesOf);
}
@@ -83,7 +83,7 @@ public class InterestScheduleModelRepositoryWrapperImpl implements InterestSched
return progressiveLoanModel.map(ProgressiveLoanModel::getJsonModel) //
.map(jsonModel -> progressiveLoanInterestScheduleModelParserService.fromJson(jsonModel,
progressiveLoanModel.get().getLoan().getLoanProductRelatedDetail(), MoneyHelper.getMathContext(),
progressiveLoanModel.get().getLoan().getLoanProduct().getInstallmentAmountInMultiplesOf()));
progressiveLoanModel.get().getLoan().getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf()));
}
@Override
@@ -83,7 +83,7 @@ public class InternalProgressiveLoanApiResource implements InitializingBean {
}
return writePlatformService.readProgressiveLoanInterestScheduleModel(loanId, loan.getLoanRepaymentScheduleDetail(),
loan.getLoanProduct().getInstallmentAmountInMultiplesOf()).orElse(null);
loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf()).orElse(null);
}
private ProgressiveLoanInterestScheduleModel reprocessTransactionsAndGetModel(final Loan loan) {
@@ -432,8 +432,6 @@ public class LoanScheduleAssembler {
final BigDecimal principalThresholdForLastInstalment = loanProduct.getPrincipalThresholdForLastInstallment();
final Integer installmentAmountInMultiplesOf = loanProduct.getInstallmentAmountInMultiplesOf();
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
if (loanProduct.isLinkedToFloatingInterestRate()) {
final BigDecimal interestRateDiff = this.fromApiJsonHelper
@@ -538,8 +536,9 @@ public class LoanScheduleAssembler {
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,
loanProduct.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf(),
loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO, loanTermVariations,
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
allowCompoundingOnEod, isEqualAmortization, isInterestToBeRecoveredFirstWhenGreaterThanEMI,
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
@@ -673,8 +672,8 @@ public class LoanScheduleAssembler {
}
}
public LoanProductRelatedDetail assembleLoanProductRelatedDetail(final JsonElement element, final LoanProduct loanProduct) {
final LoanApplicationTerms loanApplicationTerms = assembleLoanApplicationTermsFrom(element, loanProduct);
public LoanProductRelatedDetail assembleLoanProductRelatedDetail(final LoanApplicationTerms loanApplicationTerms,
final JsonElement element) {
LoanProductRelatedDetail loanProductRelatedDetail = loanApplicationTerms.toLoanProductRelatedDetail();
final String interestRateFrequencyTypeParamName = "interestRateFrequencyType";
if (this.fromApiJsonHelper.parameterExists(interestRateFrequencyTypeParamName, element)) {
@@ -684,6 +683,10 @@ public class LoanScheduleAssembler {
return loanProductRelatedDetail;
}
public LoanProductRelatedDetail assembleLoanProductRelatedDetail(final JsonElement element, final LoanProduct loanProduct) {
return assembleLoanProductRelatedDetail(assembleLoanApplicationTermsFrom(element, loanProduct), element);
}
public LoanScheduleModel assembleLoanScheduleFrom(final JsonElement element) {
// This method is getting called from calculate loan schedule.
final LoanApplicationTerms loanApplicationTerms = assembleLoanTerms(element);
@@ -221,8 +221,9 @@ public class LoanAssemblerImpl implements LoanAssembler {
// Here we add Rates to LoanApplication
final List<Rate> rates = this.rateAssembler.fromParsedJson(element);
final LoanProductRelatedDetail loanProductRelatedDetail = this.loanScheduleAssembler.assembleLoanProductRelatedDetail(element,
loanProduct);
final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element);
final LoanProductRelatedDetail loanProductRelatedDetail = this.loanScheduleAssembler
.assembleLoanProductRelatedDetail(loanApplicationTerms, element);
final BigDecimal interestRateDifferential = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanApiConstants.interestRateDifferentialParameterName, element);
@@ -247,7 +248,6 @@ public class LoanAssemblerImpl implements LoanAssembler {
isEnableInstallmentLevelDelinquency = loanProduct.isEnableInstallmentLevelDelinquency();
}
final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element);
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
Long officeId = client != null ? client.getOffice().getId() : group.getOffice().getId();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId,
@@ -410,11 +410,11 @@ public class LoanProductUpdateUtil {
}
if (command.isChangeInIntegerParameterNamedWithNullCheck(LoanProductConstants.installmentAmountInMultiplesOfParamName,
loanProduct.getInstallmentAmountInMultiplesOf())) {
loanProduct.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.installmentAmountInMultiplesOfParamName);
actualChanges.put(LoanProductConstants.installmentAmountInMultiplesOfParamName, newValue);
actualChanges.put("locale", localeAsInput);
loanProduct.setInstallmentAmountInMultiplesOf(newValue);
loanProduct.getLoanProductRelatedDetail().setInstallmentAmountInMultiplesOf(newValue);
}
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.CAN_USE_FOR_TOPUP, loanProduct.isCanUseForTopup())) {
@@ -444,9 +444,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.getDisbursedAmountPercentageForDownPayment();
Money downPaymentMoney = Money.of(loan.getCurrency(),
MathUtil.percentageOf(amountToDisburse.getAmount(), disbursedAmountPercentageForDownPayment, 19));
if (loan.getLoanProduct().getInstallmentAmountInMultiplesOf() != null) {
if (loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf() != null) {
downPaymentMoney = Money.roundToMultiplesOf(downPaymentMoney,
loan.getLoanProduct().getInstallmentAmountInMultiplesOf());
loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf());
}
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate,
downPaymentMoney.getAmount(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
@@ -254,7 +254,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
+ "lp.allow_multiple_disbursals as multiDisburseLoan, lp.max_disbursals as maxTrancheCount, lp.max_outstanding_loan_balance as outstandingLoanBalance, "
+ "lp.disallow_expected_disbursements as disallowExpectedDisbursements, lp.allow_approved_disbursed_amounts_over_applied as allowApprovedDisbursedAmountsOverApplied, lp.over_applied_calculation_type as overAppliedCalculationType, over_applied_number as overAppliedNumber, "
+ "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, "
+ "lp.can_define_fixed_emi_amount as canDefineInstallmentAmount, lp.instalment_amount_in_multiples_of as installmentAmountInMultiplesOf, "
+ "lp.can_define_fixed_emi_amount as canDefineInstallmentAmount, lp.installment_amount_in_multiples_of as installmentAmountInMultiplesOf, "
+ "lp.due_days_for_repayment_event as dueDaysForRepaymentEvent, lp.overdue_days_for_repayment_event as overDueDaysForRepaymentEvent, lp.enable_down_payment as enableDownPayment, lp.disbursed_amount_percentage_for_down_payment as disbursedAmountPercentageForDownPayment, lp.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment, lp.repayment_start_date_type_enum as repaymentStartDateType, "
+ "lp.enable_installment_level_delinquency as enableInstallmentLevelDelinquency, "
+ "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
@@ -160,6 +160,7 @@ public class LoanDownPaymentHandlerServiceImplTest {
when(downPaymentMoney.getCurrencyCode()).thenReturn(loanCurrency.getCode());
when(overPaymentPortionMoney.getCurrencyCode()).thenReturn(loanCurrency.getCode());
when(loanRepaymentRelatedDetail.getInstallmentAmountInMultiplesOf()).thenReturn(10);
when(loanForProcessing.getLoanRepaymentScheduleDetail()).thenReturn(loanRepaymentRelatedDetail);
when(loanForProcessing.repaymentScheduleDetail()).thenReturn(loanRepaymentRelatedDetail);
when(loanRepaymentRelatedDetail.isInterestRecalculationEnabled()).thenReturn(true);
@@ -168,7 +169,6 @@ public class LoanDownPaymentHandlerServiceImplTest {
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
when(loanForProcessing.loanCurrency()).thenReturn(loanCurrency);
when(loanForProcessing.getLoanProduct()).thenReturn(loanProduct);
when(loanProduct.getInstallmentAmountInMultiplesOf()).thenReturn(10);
when(loanForProcessing.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
when(loanTransactionProcessingService.reprocessLoanTransactions(any(), any(), any(), any(), any(), any()))
.thenReturn(changedTransactionDetail);