This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 39a8d5c63e FINERACT-2181: Installment amount in multiples of should be
inherited from loan product to loan level
39a8d5c63e is described below
commit 39a8d5c63e2763bacdcfee132d89289e44f2a88c
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Sat May 31 08:50:52 2025 -0500
FINERACT-2181: Installment amount in multiples of should be inherited from
loan product to loan level
---
.../loanschedule/domain/LoanApplicationTerms.java | 2 +-
.../mapper/LoanTermVariationsMapper.java | 5 ++-
.../service/LoanDownPaymentHandlerServiceImpl.java | 5 ++-
.../portfolio/loanproduct/domain/LoanProduct.java | 7 +---
.../domain/LoanProductRelatedDetail.java | 12 ++++--
.../tenant/module/loan/module-changelog-master.xml | 1 +
..._installment_amount_in_multiples_of_to_loan.xml | 46 ++++++++++++++++++++++
...dvancedPaymentScheduleTransactionProcessor.java | 15 ++++---
...InterestScheduleModelRepositoryWrapperImpl.java | 2 +-
.../InternalProgressiveLoanApiResource.java | 2 +-
.../service/LoanScheduleAssembler.java | 15 ++++---
.../loanaccount/service/LoanAssemblerImpl.java | 6 +--
.../loanaccount/service/LoanProductUpdateUtil.java | 4 +-
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 4 +-
.../LoanProductReadPlatformServiceImpl.java | 2 +-
.../LoanDownPaymentHandlerServiceImplTest.java | 2 +-
16 files changed, 94 insertions(+), 36 deletions(-)
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
index 2c2cad5bbc..308cc55edf 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
@@ -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() {
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
index a11480a64c..6d21260b50 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/mapper/LoanTermVariationsMapper.java
@@ -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,
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
index 621bad353a..5e2004790f 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
@@ -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
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
index d9f7dbd713..f3dae22e9e 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java
@@ -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;
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
index 6ca788655e..e0723e8a53 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRelatedDetail.java
@@ -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) {
diff --git
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
index 89230b66ea..50364a23aa 100644
---
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
+++
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml
@@ -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>
diff --git
a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1029_add_installment_amount_in_multiples_of_to_loan.xml
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1029_add_installment_amount_in_multiples_of_to_loan.xml
new file mode 100644
index 0000000000..c36d41c798
--- /dev/null
+++
b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1029_add_installment_amount_in_multiples_of_to_loan.xml
@@ -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>
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index bd36229754..9ffe5c0a4e 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -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);
}
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java
index 261e5d25d6..2aabbaa89d 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelRepositoryWrapperImpl.java
@@ -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
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
index d2a59a2623..f7bbec6356 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java
@@ -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) {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index 5a87e0e908..1e22e540c8 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -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);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
index a6e6ebc3d0..2725325678 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
@@ -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,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java
index af8d77cc39..ac28a3ea2f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductUpdateUtil.java
@@ -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())) {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index c99e1cf08e..bbd9150810 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -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,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
index 56c2ef8c96..181410b91c 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java
@@ -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, "
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
index 7323ea61bd..231e1bad39 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImplTest.java
@@ -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);