From adcfc3c8ba916ba55c9e83e8646c954ef03be442 Mon Sep 17 00:00:00 2001 From: Jose Alberto Hernandez Date: Tue, 28 May 2024 05:43:38 -0600 Subject: [PATCH] FINERACT-1981: Function Value using simple interest for EMI calculation --- .../calc/emi/FnValueFunctions.java | 44 +++++++++++++++++++ .../ratefactor/RateFactorFunctions.java | 2 +- .../EMICalculationFunctionsTest.java} | 33 +++++++++++++- 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/emi/FnValueFunctions.java rename fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/{ => calc}/ratefactor/RateFactorFunctions.java (96%) rename fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/{ratefactor/RateFactorFunctionsTest.java => calc/EMICalculationFunctionsTest.java} (75%) diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/emi/FnValueFunctions.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/emi/FnValueFunctions.java new file mode 100644 index 00000000000..e7c152afb86 --- /dev/null +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/emi/FnValueFunctions.java @@ -0,0 +1,44 @@ +/** + * 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. + */ +package org.apache.fineract.portfolio.loanproduct.calc.emi; + +import java.math.BigDecimal; +import java.math.MathContext; + +public class FnValueFunctions { + + protected FnValueFunctions() {} + + /** + * To calculate the function value for each period, we are going to use the next formula: + * + * fn = 1 + fnValueFrom * rateFactorEnd + * + * @param previousFnValue + * + * @param currentRateFactor + * + * @param mathContext + * + */ + public static BigDecimal fnValue(final BigDecimal previousFnValue, final BigDecimal currentRateFactor, final MathContext mc) { + return BigDecimal.ONE.add(previousFnValue.multiply(currentRateFactor, mc)); + } + +} diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/ratefactor/RateFactorFunctions.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ratefactor/RateFactorFunctions.java similarity index 96% rename from fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/ratefactor/RateFactorFunctions.java rename to fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ratefactor/RateFactorFunctions.java index c663d4fa763..99f8b68aa9f 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/ratefactor/RateFactorFunctions.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ratefactor/RateFactorFunctions.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.loanproduct.ratefactor; +package org.apache.fineract.portfolio.loanproduct.calc.ratefactor; import java.math.BigDecimal; import java.math.MathContext; diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/ratefactor/RateFactorFunctionsTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculationFunctionsTest.java similarity index 75% rename from fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/ratefactor/RateFactorFunctionsTest.java rename to fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculationFunctionsTest.java index b535992d792..e11be4db5ec 100644 --- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/ratefactor/RateFactorFunctionsTest.java +++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculationFunctionsTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.loanproduct.ratefactor; +package org.apache.fineract.portfolio.loanproduct.calc; import java.math.BigDecimal; import java.math.MathContext; @@ -28,6 +28,8 @@ import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.apache.fineract.portfolio.common.domain.DaysInYearType; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; +import org.apache.fineract.portfolio.loanproduct.calc.emi.FnValueFunctions; +import org.apache.fineract.portfolio.loanproduct.calc.ratefactor.RateFactorFunctions; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -38,7 +40,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -class RateFactorFunctionsTest { +class EMICalculationFunctionsTest { private static MockedStatic moneyHelper = Mockito.mockStatic(MoneyHelper.class); @@ -94,6 +96,33 @@ public void testRateFactorFunctionActual() { } } + @Test + public void testFnValueFunctionDay365() { + // Given + final DaysInYearType daysInYearType = DaysInYearType.DAYS_365; + final MathContext mc = MoneyHelper.getMathContext(); + final String[] expectedValues = new String[] { "1.0000000", "2.0075336", "3.0237007", "4.0472656", "5.0798590", "6.1194484" }; + + final List fnValuesCalculated = new ArrayList<>(); + BigDecimal previousFnValue = BigDecimal.ZERO; + for (LoanRepaymentScheduleInstallment period : periods) { + final Long daysInPeriod = DateUtils.getDifferenceInDays(period.getFromDate(), period.getDueDate()); + final Integer daysInYear = DateUtils.daysInYear(daysInYearType, period.getFromDate()); + final BigDecimal rateFactor = RateFactorFunctions.rateFactor(interestRate, daysInPeriod, daysInYear, + MoneyHelper.getMathContext()); + + final BigDecimal currentFnValue = FnValueFunctions.fnValue(previousFnValue, rateFactor, mc); + fnValuesCalculated.add(currentFnValue); + + previousFnValue = currentFnValue; + } + + int idx = 0; + for (BigDecimal fnValue : fnValuesCalculated) { + Assertions.assertEquals(expectedValues[idx++], fnValue.toString()); + } + } + @NotNull private static LoanRepaymentScheduleInstallment createPeriod(int periodId, LocalDate start, LocalDate end) { LoanRepaymentScheduleInstallment period = Mockito.mock(LoanRepaymentScheduleInstallment.class);