From 8e3de2b72aeaab01518dec08b66e5f042485f05e Mon Sep 17 00:00:00 2001 From: kengneruphine Date: Thu, 25 Sep 2025 21:14:06 +0200 Subject: [PATCH] FINERACT-2359: Wrong Days in Year configuration used for calculating interest --- .../loanschedule/domain/AprCalculator.java | 8 +++-- .../service/LoanScheduleAssembler.java | 30 +++++++++---------- .../service/LoanProductAssembler.java | 9 +++--- .../LoanProductRelatedDetailUpdateUtil.java | 3 +- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AprCalculator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AprCalculator.java index 331c0418c..e22e02f9c 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AprCalculator.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AprCalculator.java @@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain; import java.math.BigDecimal; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; +import org.apache.fineract.portfolio.common.domain.DaysInYearType; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.springframework.stereotype.Component; @@ -27,11 +28,12 @@ import org.springframework.stereotype.Component; public class AprCalculator { public BigDecimal calculateFrom(final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal interestRatePerPeriod, - final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType) { + final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, + final DaysInYearType daysInYearType) { BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO; switch (interestPeriodFrequencyType) { case DAYS: - defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(365)); + defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(daysInYearType.getValue())); break; case WEEKS: defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(52)); @@ -48,7 +50,7 @@ public class AprCalculator { switch (repaymentPeriodFrequencyType) { case DAYS: - defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(365)); + defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(daysInYearType.getValue())); break; case WEEKS: defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(52)); 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 89318fcc7..c0742533d 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 @@ -219,6 +219,20 @@ public class LoanScheduleAssembler { BigDecimal fixedPrincipalPercentagePerInstallment = this.fromApiJsonHelper .extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, element); + /** + * 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(); + } + // interest terms final Integer interestType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element); final InterestMethod interestMethod = allowOverridingInterestMethod ? InterestMethod.fromInt(interestType) @@ -246,7 +260,7 @@ public class LoanScheduleAssembler { BigDecimal annualNominalInterestRate = BigDecimal.ZERO; if (interestRatePerPeriod != null) { annualNominalInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRatePerPeriod, - numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType); + numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, daysInYearType); } // disbursement details @@ -365,20 +379,6 @@ public class LoanScheduleAssembler { final List 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; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java index fcdc4a5f2..07644c8d5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductAssembler.java @@ -113,6 +113,10 @@ public class LoanProductAssembler { Integer minimumGapBetweenInstallments = null; Integer maximumGapBetweenInstallments = null; + // Declaring this variable here to be used throughout the file + final DaysInYearType daysInYearType = DaysInYearType + .fromInt(command.integerValueOfParameterNamed(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME)); + final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery"); final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments"); final Boolean isLinkedToFloatingInterestRates = command.booleanObjectValueOfParameterNamed("isLinkedToFloatingInterestRates"); @@ -129,7 +133,7 @@ public class LoanProductAssembler { minInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("minInterestRatePerPeriod"); maxInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("maxInterestRatePerPeriod"); annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod, numberOfRepayments, - repaymentEvery, repaymentFrequencyType); + repaymentEvery, repaymentFrequencyType, daysInYearType); } @@ -204,9 +208,6 @@ public class LoanProductAssembler { final DaysInMonthType daysInMonthType = DaysInMonthType .fromInt(command.integerValueOfParameterNamed(LoanProductConstants.DAYS_IN_MONTH_TYPE_PARAMETER_NAME)); - final DaysInYearType daysInYearType = DaysInYearType - .fromInt(command.integerValueOfParameterNamed(LoanProductConstants.DAYS_IN_YEAR_TYPE_PARAMETER_NAME)); - final DaysInYearCustomStrategyType daysInYearCustomStrategy = command.enumValueOfParameterNamed( LoanProductConstants.DAYS_IN_YEAR_CUSTOM_STRATEGY_TYPE_PARAMETER_NAME, DaysInYearCustomStrategyType.class); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java index c1842b3e7..3133bf007 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanProductRelatedDetailUpdateUtil.java @@ -373,7 +373,8 @@ public class LoanProductRelatedDetailUpdateUtil { final AprCalculator aprCalculator) { BigDecimal annualNominalInterestRate = aprCalculator.calculateFrom(loanRepaymentScheduleDetail.getInterestPeriodFrequencyType(), loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod(), loanRepaymentScheduleDetail.getNumberOfRepayments(), - loanRepaymentScheduleDetail.getRepayEvery(), loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType()); + loanRepaymentScheduleDetail.getRepayEvery(), loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType(), + loanRepaymentScheduleDetail.fetchDaysInYearType()); loanRepaymentScheduleDetail.setAnnualNominalInterestRate(annualNominalInterestRate); } }