You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ad...@apache.org on 2024/10/22 16:45:34 UTC
(fineract) branch develop updated: FINERACT-1981: Remove hardcoded MoneyHelper dependency during progressive loan
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 a9ecdf97a FINERACT-1981: Remove hardcoded MoneyHelper dependency during progressive loan
a9ecdf97a is described below
commit a9ecdf97a4ccb94ae50bad6dc7623f3d06ba0f0e
Author: Andrii Kulminskyi <ku...@gmail.com>
AuthorDate: Mon Oct 21 13:48:03 2024 +0300
FINERACT-1981: Remove hardcoded MoneyHelper dependency during progressive loan
---
.../infrastructure/core/service/MathUtil.java | 17 ++
.../organisation/monetary/domain/Money.java | 177 +++++++++++++++++----
.../organisation/monetary/domain/MoneyHelper.java | 1 +
fineract-loan/dependencies.gradle | 5 +
.../loanschedule/data/LoanScheduleParams.java | 72 +++++----
.../AbstractCumulativeLoanScheduleGenerator.java | 26 +--
.../domain/DefaultScheduledDateGenerator.java | 61 +++----
.../loanschedule/domain/LoanApplicationTerms.java | 41 +++--
.../domain/LoanScheduleModelRepaymentPeriod.java | 24 +--
.../domain/ScheduledDateGenerator.java | 5 +-
...argeRepaymentScheduleProcessingWrapperTest.java | 7 +-
...dvancedPaymentScheduleTransactionProcessor.java | 2 +-
.../loanschedule/data/InterestPeriod.java | 25 +--
.../data/ProgressiveLoanInterestScheduleModel.java | 20 ++-
.../loanschedule/data/RepaymentPeriod.java | 55 ++++---
.../domain/ProgressiveLoanScheduleGenerator.java | 34 ++--
.../portfolio/loanproduct/calc/EMICalculator.java | 5 +-
.../loanproduct/calc/ProgressiveEMICalculator.java | 156 +++++++++---------
...cedPaymentScheduleTransactionProcessorTest.java | 4 +-
.../domain/LoanScheduleGeneratorTest.java | 63 ++------
.../calc/ProgressiveEMICalculatorTest.java | 43 ++---
.../CheckLoanRepaymentOverdueBusinessStepTest.java | 2 +
...AccountDelinquencyRangeEventSerializerTest.java | 15 +-
.../LoanRepaymentBusinessEventSerializerTest.java | 4 +-
.../LoanDelinquencyDomainServiceTest.java | 4 +-
.../DefaultLoanLifecycleStateMachineTest.java | 4 +-
...nRepaymentScheduleTransactionProcessorTest.java | 2 +
...nRepaymentScheduleTransactionProcessorTest.java | 2 +
.../domain/DefaultScheduledDateGeneratorTest.java | 7 +-
.../LoanCalculateRepaymentPastDueServiceTest.java | 4 +-
.../LoanDownPaymentHandlerServiceImplTest.java | 4 +-
31 files changed, 536 insertions(+), 355 deletions(-)
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java
index 406f16c08..2e0779ef9 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java
@@ -359,6 +359,11 @@ public final class MathUtil {
return value == null || isGreaterThanZero(value) ? value : Money.zero(value.getCurrency());
}
+ /** @return parameter value or ZERO if it is negative */
+ public static Money negativeToZero(Money value, MathContext mc) {
+ return value == null || isGreaterThanZero(value, mc) ? value : Money.zero(value.getCurrency(), mc);
+ }
+
public static boolean isEmpty(Money value) {
return value == null || value.isZero();
}
@@ -367,6 +372,10 @@ public final class MathUtil {
return value != null && value.isGreaterThanZero();
}
+ public static boolean isGreaterThanZero(Money value, MathContext mc) {
+ return value != null && value.isGreaterThanZero(mc);
+ }
+
public static boolean isLessThanZero(Money value) {
return value != null && value.isLessThanZero();
}
@@ -387,10 +396,18 @@ public final class MathUtil {
return first == null ? second : second == null ? first : first.plus(second);
}
+ public static Money plus(Money first, Money second, MathContext mc) {
+ return first == null ? second : second == null ? first : first.plus(second, mc);
+ }
+
public static Money plus(Money first, Money second, Money third) {
return plus(plus(first, second), third);
}
+ public static Money plus(Money first, Money second, Money third, MathContext mc) {
+ return plus(plus(first, second), third, mc);
+ }
+
public static Money plus(Money first, Money second, Money third, Money fourth) {
return plus(plus(plus(first, second), third), fourth);
}
diff --git a/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/Money.java b/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/Money.java
index 9e2d51af9..8ec1a84fc 100644
--- a/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/Money.java
+++ b/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/Money.java
@@ -21,11 +21,14 @@ package org.apache.fineract.organisation.monetary.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Iterator;
+import lombok.Getter;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
@Embeddable
+@Getter
public class Money implements Comparable<Money> {
@Column(name = "currency_code", length = 3)
@@ -40,6 +43,16 @@ public class Money implements Comparable<Money> {
@Column(name = "amount", scale = 6, precision = 19)
private BigDecimal amount;
+ private final transient MathContext mc;
+
+ protected Money() {
+ this.currencyCode = null;
+ this.currencyDigitsAfterDecimal = 0;
+ this.inMultiplesOf = 0;
+ this.amount = null;
+ this.mc = getMc();
+ }
+
public static Money total(final Money... monies) {
if (monies.length == 0) {
throw new IllegalArgumentException("Money array must not be empty");
@@ -53,7 +66,7 @@ public class Money implements Comparable<Money> {
public static Money total(final Iterable<? extends Money> monies) {
final Iterator<? extends Money> it = monies.iterator();
- if (it.hasNext() == false) {
+ if (!it.hasNext()) {
throw new IllegalArgumentException("Money iterator must not be empty");
}
Money total = it.next();
@@ -63,34 +76,47 @@ public class Money implements Comparable<Money> {
return total;
}
+ public static Money of(final MonetaryCurrency currency, final BigDecimal newAmount, final MathContext mc) {
+ return new Money(currency.getCode(), currency.getDigitsAfterDecimal(), defaultToZeroIfNull(newAmount),
+ currency.getCurrencyInMultiplesOf(), mc);
+ }
+
public static Money of(final MonetaryCurrency currency, final BigDecimal newAmount) {
return new Money(currency.getCode(), currency.getDigitsAfterDecimal(), defaultToZeroIfNull(newAmount),
- currency.getCurrencyInMultiplesOf());
+ currency.getCurrencyInMultiplesOf(), null);
}
public static Money of(final CurrencyData currency, final BigDecimal newAmount) {
- return new Money(currency.getCode(), currency.getDecimalPlaces(), defaultToZeroIfNull(newAmount), currency.getInMultiplesOf());
+ return new Money(currency.getCode(), currency.getDecimalPlaces(), defaultToZeroIfNull(newAmount), currency.getInMultiplesOf(),
+ null);
+ }
+
+ public static Money of(final CurrencyData currency, final BigDecimal newAmount, final MathContext mc) {
+ return new Money(currency.getCode(), currency.getDecimalPlaces(), defaultToZeroIfNull(newAmount), currency.getInMultiplesOf(), mc);
}
public static Money zero(final MonetaryCurrency currency) {
- return new Money(currency.getCode(), currency.getDigitsAfterDecimal(), BigDecimal.ZERO, currency.getCurrencyInMultiplesOf());
+ return new Money(currency.getCode(), currency.getDigitsAfterDecimal(), BigDecimal.ZERO, currency.getCurrencyInMultiplesOf(), null);
}
- public static Money zero(final CurrencyData currency) {
- return new Money(currency.getCode(), currency.getDecimalPlaces(), BigDecimal.ZERO, currency.getInMultiplesOf());
+ public static Money zero(final MonetaryCurrency currency, MathContext mc) {
+ return new Money(currency.getCode(), currency.getDigitsAfterDecimal(), BigDecimal.ZERO, currency.getCurrencyInMultiplesOf(), mc);
}
- protected Money() {
- this.currencyCode = null;
- this.currencyDigitsAfterDecimal = 0;
- this.inMultiplesOf = 0;
- this.amount = null;
+ public static Money zero(final CurrencyData currency, MathContext mc) {
+ return new Money(currency.getCode(), currency.getDecimalPlaces(), BigDecimal.ZERO, currency.getInMultiplesOf(), mc);
+ }
+
+ public static Money zero(final CurrencyData currency) {
+ return new Money(currency.getCode(), currency.getDecimalPlaces(), BigDecimal.ZERO, currency.getInMultiplesOf(), null);
}
- private Money(final String currencyCode, final int digitsAfterDecimal, final BigDecimal amount, final Integer inMultiplesOf) {
+ private Money(final String currencyCode, final int digitsAfterDecimal, final BigDecimal amount, final Integer inMultiplesOf,
+ final MathContext mc) {
this.currencyCode = currencyCode;
this.currencyDigitsAfterDecimal = digitsAfterDecimal;
this.inMultiplesOf = inMultiplesOf;
+ this.mc = mc;
final BigDecimal amountZeroed = defaultToZeroIfNull(amount);
final BigDecimal amountStripped = amountZeroed.stripTrailingZeros();
@@ -101,7 +127,7 @@ public class Money implements Comparable<Money> {
final double existingVal = amountScaled.doubleValue();
amountScaled = BigDecimal.valueOf(roundToMultiplesOf(existingVal, inMultiplesOf));
}
- this.amount = amountScaled.setScale(this.currencyDigitsAfterDecimal, MoneyHelper.getRoundingMode());
+ this.amount = amountScaled.setScale(this.currencyDigitsAfterDecimal, getMc().getRoundingMode());
}
public static double roundToMultiplesOf(final double existingVal, final Integer inMultiplesOf) {
@@ -130,10 +156,14 @@ public class Money implements Comparable<Money> {
}
public static Money roundToMultiplesOf(final Money existingVal, final Integer inMultiplesOf) {
+ return roundToMultiplesOf(existingVal, inMultiplesOf, MoneyHelper.getMathContext());
+ }
+
+ public static Money roundToMultiplesOf(final Money existingVal, final Integer inMultiplesOf, final MathContext mc) {
BigDecimal amountScaled = existingVal.getAmount();
BigDecimal inMultiplesOfValue = BigDecimal.valueOf(inMultiplesOf.intValue());
if (inMultiplesOfValue.compareTo(BigDecimal.ZERO) > 0) {
- amountScaled = amountScaled.divide(inMultiplesOfValue, 0, MoneyHelper.getRoundingMode()).multiply(inMultiplesOfValue);
+ amountScaled = amountScaled.divide(inMultiplesOfValue, 0, mc.getRoundingMode()).multiply(inMultiplesOfValue);
}
return Money.of(existingVal.getCurrency(), amountScaled);
}
@@ -171,7 +201,7 @@ public class Money implements Comparable<Money> {
}
public Money copy() {
- return new Money(this.currencyCode, this.currencyDigitsAfterDecimal, this.amount.stripTrailingZeros(), this.inMultiplesOf);
+ return new Money(this.currencyCode, this.currencyDigitsAfterDecimal, this.amount.stripTrailingZeros(), this.inMultiplesOf, this.mc);
}
public Money plus(final Iterable<? extends Money> moniesToAdd) {
@@ -188,6 +218,11 @@ public class Money implements Comparable<Money> {
return this.plus(toAdd.getAmount());
}
+ public Money plus(final Money moneyToAdd, final MathContext mc) {
+ final Money toAdd = checkCurrencyEqual(moneyToAdd);
+ return this.plus(toAdd.getAmount(), mc);
+ }
+
public Money plus(final BigDecimal amountToAdd) {
if (amountToAdd == null || amountToAdd.compareTo(BigDecimal.ZERO) == 0) {
return this;
@@ -196,6 +231,14 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), newAmount);
}
+ public Money plus(final BigDecimal amountToAdd, MathContext mc) {
+ if (amountToAdd == null || amountToAdd.compareTo(BigDecimal.ZERO) == 0) {
+ return this;
+ }
+ final BigDecimal newAmount = this.amount.add(amountToAdd);
+ return Money.of(monetaryCurrency(), newAmount, mc);
+ }
+
public Money plus(final double amountToAdd) {
if (amountToAdd == 0) {
return this;
@@ -209,11 +252,21 @@ public class Money implements Comparable<Money> {
return this.minus(toSubtract.getAmount());
}
+ public Money minus(final Money moneyToSubtract, final MathContext mc) {
+ final Money toSubtract = checkCurrencyEqual(moneyToSubtract);
+ return this.minus(toSubtract.getAmount(), mc);
+ }
+
public Money add(final Money moneyToAdd) {
final Money toAdd = checkCurrencyEqual(moneyToAdd);
return this.add(toAdd.getAmount());
}
+ public Money add(final Money moneyToAdd, final MathContext mc) {
+ final Money toAdd = checkCurrencyEqual(moneyToAdd);
+ return this.add(toAdd.getAmount(), mc);
+ }
+
public Money add(final BigDecimal amountToAdd) {
if (amountToAdd == null || amountToAdd.compareTo(BigDecimal.ZERO) == 0) {
return this;
@@ -222,6 +275,14 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), newAmount);
}
+ public Money add(final BigDecimal amountToAdd, final MathContext mc) {
+ if (amountToAdd == null || amountToAdd.compareTo(BigDecimal.ZERO) == 0) {
+ return this;
+ }
+ final BigDecimal newAmount = this.amount.add(amountToAdd);
+ return Money.of(monetaryCurrency(), newAmount, mc);
+ }
+
public Money minus(final BigDecimal amountToSubtract) {
if (amountToSubtract == null || amountToSubtract.compareTo(BigDecimal.ZERO) == 0) {
return this;
@@ -230,8 +291,16 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), newAmount);
}
+ public Money minus(final BigDecimal amountToSubtract, final MathContext mc) {
+ if (amountToSubtract == null || amountToSubtract.compareTo(BigDecimal.ZERO) == 0) {
+ return this;
+ }
+ final BigDecimal newAmount = this.amount.subtract(amountToSubtract);
+ return Money.of(monetaryCurrency(), newAmount, mc);
+ }
+
private Money checkCurrencyEqual(final Money money) {
- if (isSameCurrency(money) == false) {
+ if (!isSameCurrency(money)) {
throw new UnsupportedOperationException("currencies are different.");
}
return money;
@@ -249,6 +318,14 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), newAmount);
}
+ public Money dividedBy(final BigDecimal valueToDivideBy, final RoundingMode roundingMode, final MathContext mc) {
+ if (valueToDivideBy.compareTo(BigDecimal.ONE) == 0) {
+ return this;
+ }
+ final BigDecimal newAmount = this.amount.divide(valueToDivideBy, roundingMode);
+ return Money.of(monetaryCurrency(), newAmount, mc);
+ }
+
public Money dividedBy(final double valueToDivideBy, final RoundingMode roundingMode) {
if (valueToDivideBy == 1) {
return this;
@@ -265,6 +342,14 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), newAmount);
}
+ public Money dividedBy(final long valueToDivideBy, final RoundingMode roundingMode, final MathContext mc) {
+ if (valueToDivideBy == 1) {
+ return this;
+ }
+ final BigDecimal newAmount = this.amount.divide(BigDecimal.valueOf(valueToDivideBy), roundingMode);
+ return Money.of(monetaryCurrency(), newAmount, mc);
+ }
+
public Money multipliedBy(final BigDecimal valueToMultiplyBy) {
if (valueToMultiplyBy.compareTo(BigDecimal.ONE) == 0) {
return this;
@@ -273,6 +358,14 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), newAmount);
}
+ public Money multipliedBy(final BigDecimal valueToMultiplyBy, final MathContext mc) {
+ if (valueToMultiplyBy.compareTo(BigDecimal.ONE) == 0) {
+ return this;
+ }
+ final BigDecimal newAmount = this.amount.multiply(valueToMultiplyBy);
+ return Money.of(monetaryCurrency(), newAmount, mc);
+ }
+
public Money multipliedBy(final double valueToMultiplyBy) {
if (valueToMultiplyBy == 1) {
return this;
@@ -289,6 +382,14 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), newAmount);
}
+ public Money multipliedBy(final long valueToMultiplyBy, final MathContext mc) {
+ if (valueToMultiplyBy == 1) {
+ return this;
+ }
+ final BigDecimal newAmount = this.amount.multiply(BigDecimal.valueOf(valueToMultiplyBy));
+ return Money.of(monetaryCurrency(), newAmount, mc);
+ }
+
public Money multiplyRetainScale(final BigDecimal valueToMultiplyBy, final RoundingMode roundingMode) {
if (valueToMultiplyBy.compareTo(BigDecimal.ONE) == 0) {
return this;
@@ -309,17 +410,20 @@ public class Money implements Comparable<Money> {
@Override
public int compareTo(final Money other) {
- final Money otherMoney = other;
- if (this.currencyCode.equals(otherMoney.currencyCode) == false) {
+ if (!this.currencyCode.equals(other.currencyCode)) {
throw new UnsupportedOperationException("currencies arent different");
}
- return this.amount.compareTo(otherMoney.amount);
+ return this.amount.compareTo(other.amount);
}
public boolean isZero() {
return isEqualTo(Money.zero(getCurrency()));
}
+ public boolean isZero(final MathContext mc) {
+ return isEqualTo(Money.zero(getCurrency(), mc));
+ }
+
public boolean isEqualTo(final Money other) {
return compareTo(other) == 0;
}
@@ -340,6 +444,10 @@ public class Money implements Comparable<Money> {
return isGreaterThan(Money.zero(getCurrency()));
}
+ public boolean isGreaterThanZero(MathContext mc) {
+ return isGreaterThan(Money.zero(getCurrency(), mc));
+ }
+
public boolean isLessThan(final Money other) {
return compareTo(other) < 0;
}
@@ -348,22 +456,14 @@ public class Money implements Comparable<Money> {
return isLessThan(Money.zero(getCurrency()));
}
- public String getCurrencyCode() {
- return this.currencyCode;
- }
-
- public int getCurrencyDigitsAfterDecimal() {
- return this.currencyDigitsAfterDecimal;
+ public boolean isLessThanZero(final MathContext mc) {
+ return isLessThan(Money.zero(getCurrency(), mc));
}
public Integer getCurrencyInMultiplesOf() {
return this.inMultiplesOf;
}
- public BigDecimal getAmount() {
- return this.amount;
- }
-
public BigDecimal getAmountDefaultedToNullIfZero() {
return defaultToNullIfZero(this.amount);
}
@@ -388,10 +488,21 @@ public class Money implements Comparable<Money> {
return Money.of(monetaryCurrency(), this.amount.negate());
}
+ public Money negated(final MathContext mc) {
+ if (isZero(mc)) {
+ return this;
+ }
+ return Money.of(monetaryCurrency(), this.amount.negate(), mc);
+ }
+
public Money abs() {
return isLessThanZero() ? negated() : this;
}
+ public Money abs(MathContext mc) {
+ return isLessThanZero(mc) ? negated(mc) : this;
+ }
+
public MonetaryCurrency getCurrency() {
return monetaryCurrency();
}
@@ -403,4 +514,12 @@ public class Money implements Comparable<Money> {
public Money zero() {
return Money.zero(getCurrency());
}
+
+ public Money zero(MathContext mc) {
+ return Money.zero(getCurrency(), mc);
+ }
+
+ public MathContext getMc() {
+ return mc != null ? mc : MoneyHelper.getMathContext();
+ }
}
diff --git a/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java b/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java
index d3cefb27d..1a99e7311 100644
--- a/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java
+++ b/fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MoneyHelper.java
@@ -65,6 +65,7 @@ public class MoneyHelper {
public static void fetchRoundingModeFromGlobalConfig() {
roundingMode = RoundingMode.valueOf(staticConfigurationDomainService.getRoundingMode());
log.info("Fetch Rounding Mode from Global Config {}", roundingMode.name());
+ mathContext = null;
}
}
diff --git a/fineract-loan/dependencies.gradle b/fineract-loan/dependencies.gradle
index 2122febb5..5d439e708 100644
--- a/fineract-loan/dependencies.gradle
+++ b/fineract-loan/dependencies.gradle
@@ -59,6 +59,11 @@ dependencies {
'org.apache.commons:commons-collections4'
)
+ implementation ('org.mnode.ical4j:ical4j') {
+ exclude group: 'commons-logging'
+ exclude group: 'javax.activation'
+ exclude group: 'com.sun.mail', module: 'javax.mail'
+ }
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor'
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
index f73f67b19..635b62bd7 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanScheduleParams.java
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
+import java.math.MathContext;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
@@ -98,6 +99,7 @@ public final class LoanScheduleParams {
private int loanTermInDays;
private final MonetaryCurrency currency;
private final boolean applyInterestRecalculation;
+ private final MathContext mc;
private LoanScheduleParams(final int periodNumber, final int instalmentNumber, int loanTermInDays, LocalDate periodStartDate,
final LocalDate actualRepaymentDate, final Money totalCumulativePrincipal, final Money totalCumulativeInterest,
@@ -108,7 +110,7 @@ public final class LoanScheduleParams {
final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
final Collection<RecalculationDetail> recalculationDetails,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
- final boolean partialUpdate, final MonetaryCurrency currency, final boolean applyInterestRecalculation) {
+ final boolean partialUpdate, final MonetaryCurrency currency, final boolean applyInterestRecalculation, final MathContext mc) {
this.periodNumber = periodNumber;
this.instalmentNumber = instalmentNumber;
this.loanTermInDays = loanTermInDays;
@@ -136,8 +138,9 @@ public final class LoanScheduleParams {
this.partialUpdate = partialUpdate;
this.currency = currency;
this.applyInterestRecalculation = applyInterestRecalculation;
+ this.mc = mc;
if (this.currency != null) {
- this.compoundedInLastInstallment = Money.zero(this.currency);
+ this.compoundedInLastInstallment = Money.zero(this.currency, mc);
}
}
@@ -150,19 +153,19 @@ public final class LoanScheduleParams {
final Money principalToBeScheduled, final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
- final MonetaryCurrency currency, final boolean applyInterestRecalculation) {
+ final MonetaryCurrency currency, final boolean applyInterestRecalculation, final MathContext mc) {
final boolean partialUpdate = true;
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
- scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
+ scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
}
public static LoanScheduleParams createLoanScheduleParamsForCompleteUpdate(final Collection<RecalculationDetail> recalculationDetails,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
- final boolean applyInterestRecalculation) {
+ final boolean applyInterestRecalculation, MathContext mc) {
final int periodNumber = 1;
final int instalmentNumber = 1;
final LocalDate periodStartDate = null;
@@ -191,22 +194,22 @@ public final class LoanScheduleParams {
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
- scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
+ scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
}
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
- final LocalDate periodStartDate, final Money principalToBeScheduled) {
+ final LocalDate periodStartDate, final Money principalToBeScheduled, final MathContext mc) {
final int loanTermInDays = 0;
final int periodNumber = 1;
final int instalmentNumber = 1;
- final Money totalCumulativePrincipal = Money.zero(currency);
- final Money totalCumulativeInterest = Money.zero(currency);
- final Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
+ final Money totalCumulativePrincipal = Money.zero(currency, mc);
+ final Money totalCumulativeInterest = Money.zero(currency, mc);
+ final Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency, mc);
final LocalDate actualRepaymentDate = periodStartDate;
final Money totalFeeChargesCharged = chargesDueAtTimeOfDisbursement;
- final Money totalPenaltyChargesCharged = Money.zero(currency);
+ final Money totalPenaltyChargesCharged = Money.zero(currency, mc);
final Money totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
- final Money reducePrincipal = Money.zero(currency);
+ final Money reducePrincipal = Money.zero(currency, mc);
final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
final Map<LocalDate, Money> compoundingMap = new TreeMap<>();
@@ -218,27 +221,28 @@ public final class LoanScheduleParams {
final Collection<RecalculationDetail> recalculationDetails = null;
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = null;
final LocalDate scheduleTillDate = null;
- final Money unCompoundedAmount = Money.zero(currency);
+ final Money unCompoundedAmount = Money.zero(currency, mc);
final boolean applyInterestRecalculation = false;
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
- scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
+ scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
}
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
- final LocalDate periodStartDate, final Money principalToBeScheduled, final LoanScheduleParams loanScheduleParams) {
+ final LocalDate periodStartDate, final Money principalToBeScheduled, final LoanScheduleParams loanScheduleParams,
+ MathContext mc) {
final int loanTermInDays = 0;
final int periodNumber = 1;
final int instalmentNumber = 1;
- final Money totalCumulativePrincipal = Money.zero(currency);
- final Money totalCumulativeInterest = Money.zero(currency);
- final Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
+ final Money totalCumulativePrincipal = Money.zero(currency, mc);
+ final Money totalCumulativeInterest = Money.zero(currency, mc);
+ final Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency, mc);
final LocalDate actualRepaymentDate = periodStartDate;
final Money totalFeeChargesCharged = chargesDueAtTimeOfDisbursement;
- final Money totalPenaltyChargesCharged = Money.zero(currency);
+ final Money totalPenaltyChargesCharged = Money.zero(currency, mc);
final Money totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
final Money reducePrincipal = Money.zero(currency);
final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
@@ -253,13 +257,13 @@ public final class LoanScheduleParams {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanScheduleParams.loanRepaymentScheduleTransactionProcessor;
final LocalDate scheduleTillDate = loanScheduleParams.scheduleTillDate;
final boolean applyInterestRecalculation = loanScheduleParams.applyInterestRecalculation;
- final Money unCompoundedAmount = Money.zero(currency);
+ final Money unCompoundedAmount = Money.zero(currency, mc);
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
- scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
+ scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
}
public int getPeriodNumber() {
@@ -288,7 +292,7 @@ public final class LoanScheduleParams {
public void addTotalCumulativePrincipal(final Money totalCumulativePrincipal) {
if (this.totalCumulativePrincipal != null) {
- this.totalCumulativePrincipal = this.totalCumulativePrincipal.plus(totalCumulativePrincipal);
+ this.totalCumulativePrincipal = this.totalCumulativePrincipal.plus(totalCumulativePrincipal, mc);
} else {
this.totalCumulativePrincipal = totalCumulativePrincipal;
}
@@ -300,7 +304,7 @@ public final class LoanScheduleParams {
public void addTotalCumulativeInterest(final Money totalCumulativeInterest) {
if (this.totalCumulativeInterest != null) {
- this.totalCumulativeInterest = this.totalCumulativeInterest.plus(totalCumulativeInterest);
+ this.totalCumulativeInterest = this.totalCumulativeInterest.plus(totalCumulativeInterest, mc);
} else {
this.totalCumulativeInterest = totalCumulativeInterest;
}
@@ -312,7 +316,7 @@ public final class LoanScheduleParams {
public void addTotalFeeChargesCharged(final Money totalFeeChargesCharged) {
if (this.totalFeeChargesCharged != null) {
- this.totalFeeChargesCharged = this.totalFeeChargesCharged.plus(totalFeeChargesCharged);
+ this.totalFeeChargesCharged = this.totalFeeChargesCharged.plus(totalFeeChargesCharged, mc);
} else {
this.totalFeeChargesCharged = totalFeeChargesCharged;
}
@@ -324,7 +328,7 @@ public final class LoanScheduleParams {
public void addTotalPenaltyChargesCharged(final Money totalPenaltyChargesCharged) {
if (this.totalPenaltyChargesCharged != null) {
- this.totalPenaltyChargesCharged = this.totalPenaltyChargesCharged.plus(totalPenaltyChargesCharged);
+ this.totalPenaltyChargesCharged = this.totalPenaltyChargesCharged.plus(totalPenaltyChargesCharged, mc);
} else {
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
}
@@ -336,7 +340,7 @@ public final class LoanScheduleParams {
public void addTotalRepaymentExpected(final Money totalRepaymentExpected) {
if (this.totalRepaymentExpected != null) {
- this.totalRepaymentExpected = this.totalRepaymentExpected.plus(totalRepaymentExpected);
+ this.totalRepaymentExpected = this.totalRepaymentExpected.plus(totalRepaymentExpected, mc);
} else {
this.totalRepaymentExpected = totalRepaymentExpected;
}
@@ -428,7 +432,7 @@ public final class LoanScheduleParams {
public void addReducePrincipal(Money reducePrincipal) {
if (this.reducePrincipal != null) {
- this.reducePrincipal = this.reducePrincipal.plus(reducePrincipal);
+ this.reducePrincipal = this.reducePrincipal.plus(reducePrincipal, mc);
} else {
this.reducePrincipal = reducePrincipal;
}
@@ -436,13 +440,13 @@ public final class LoanScheduleParams {
public void reduceReducePrincipal(Money reducePrincipal) {
if (this.reducePrincipal != null) {
- this.reducePrincipal = this.reducePrincipal.minus(reducePrincipal);
+ this.reducePrincipal = this.reducePrincipal.minus(reducePrincipal, mc);
}
}
public void addPrincipalToBeScheduled(Money principalToBeScheduled) {
if (this.principalToBeScheduled != null) {
- this.principalToBeScheduled = this.principalToBeScheduled.plus(principalToBeScheduled);
+ this.principalToBeScheduled = this.principalToBeScheduled.plus(principalToBeScheduled, mc);
} else {
this.principalToBeScheduled = principalToBeScheduled;
}
@@ -450,7 +454,7 @@ public final class LoanScheduleParams {
public void addOutstandingBalance(Money outstandingBalance) {
if (this.outstandingBalance != null) {
- this.outstandingBalance = this.outstandingBalance.plus(outstandingBalance);
+ this.outstandingBalance = this.outstandingBalance.plus(outstandingBalance, mc);
} else {
this.outstandingBalance = outstandingBalance;
}
@@ -458,13 +462,13 @@ public final class LoanScheduleParams {
public void reduceOutstandingBalance(Money outstandingBalance) {
if (this.outstandingBalance != null) {
- this.outstandingBalance = this.outstandingBalance.minus(outstandingBalance);
+ this.outstandingBalance = this.outstandingBalance.minus(outstandingBalance, mc);
}
}
public void addOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
if (this.outstandingBalanceAsPerRest != null) {
- this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.plus(outstandingBalanceAsPerRest);
+ this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.plus(outstandingBalanceAsPerRest, mc);
} else {
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
}
@@ -472,7 +476,7 @@ public final class LoanScheduleParams {
public void reduceOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
if (this.outstandingBalanceAsPerRest != null) {
- this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.minus(outstandingBalanceAsPerRest);
+ this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.minus(outstandingBalanceAsPerRest, mc);
}
}
@@ -522,7 +526,7 @@ public final class LoanScheduleParams {
public void minusUnCompoundedAmount(Money unCompoundedAmount) {
if (this.unCompoundedAmount != null) {
- this.unCompoundedAmount = this.unCompoundedAmount.minus(unCompoundedAmount);
+ this.unCompoundedAmount = this.unCompoundedAmount.minus(unCompoundedAmount, mc);
}
}
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
index b891ace31..2d6382b55 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractCumulativeLoanScheduleGenerator.java
@@ -94,10 +94,10 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
: loanApplicationTerms.getSubmittedOnDate();
if (loanScheduleParams == null) {
scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency, Money.of(currency, chargesDueAtTimeOfDisbursement),
- periodStartDate, getPrincipalToBeScheduled(loanApplicationTerms));
+ periodStartDate, getPrincipalToBeScheduled(loanApplicationTerms), mc);
} else if (!loanScheduleParams.isPartialUpdate()) {
scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency, Money.of(currency, chargesDueAtTimeOfDisbursement),
- periodStartDate, getPrincipalToBeScheduled(loanApplicationTerms), loanScheduleParams);
+ periodStartDate, getPrincipalToBeScheduled(loanApplicationTerms), loanScheduleParams, mc);
} else {
scheduleParams = loanScheduleParams;
}
@@ -345,7 +345,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
scheduleParams.getPeriodStartDate(), scheduledDueDate, currentPeriodParams.getPrincipalForThisPeriod(),
scheduleParams.getOutstandingBalance(), currentPeriodParams.getInterestForThisPeriod(),
currentPeriodParams.getFeeChargesForInstallment(), currentPeriodParams.getPenaltyChargesForInstallment(),
- totalInstallmentDue, !isCompletePeriod);
+ totalInstallmentDue, !isCompletePeriod, mc);
if (principalInterestForThisPeriod.getRescheduleInterestPortion() != null) {
installment.setRescheduleInterestPortion(principalInterestForThisPeriod.getRescheduleInterestPortion().getAmount());
}
@@ -651,7 +651,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
scheduleParams.getPeriodStartDate(), transactionDate, currentPeriodParams.getPrincipalForThisPeriod(),
scheduleParams.getOutstandingBalance(), currentPeriodParams.getInterestForThisPeriod(),
currentPeriodParams.getFeeChargesForInstallment(), currentPeriodParams.getPenaltyChargesForInstallment(),
- currentPeriodParams.fetchTotalAmountForPeriod(), false);
+ currentPeriodParams.fetchTotalAmountForPeriod(), false, mc);
scheduleParams.setTotalOutstandingInterestPaymentDueToGrace(interestTillDate.interestPaymentDueToGrace());
}
}
@@ -789,7 +789,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
installment = LoanScheduleModelRepaymentPeriod.repayment(scheduleParams.getInstalmentNumber(),
scheduleParams.getPeriodStartDate(), transactionDate, principalForThisPeriod,
scheduleParams.getOutstandingBalance(), interestForCurrentInstallment, feeChargesForInstallment,
- penaltyChargesForInstallment, totalInstallmentDue, true);
+ penaltyChargesForInstallment, totalInstallmentDue, true, mc);
periods.add(installment);
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, scheduleParams, lastRestDate, scheduledDueDate);
@@ -1416,7 +1416,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
LoanScheduleModelRepaymentPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(params.getInstalmentNumber(),
startDate, transactionDate, totalInterest.zero(), totalInterest.zero(), totalInterest, totalInterest.zero(),
- totalInterest.zero(), totalInterest, true);
+ totalInterest.zero(), totalInterest, true, mc);
params.incrementInstalmentNumber();
periods.add(installment);
totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest);
@@ -1489,7 +1489,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
if (totalInterest.isGreaterThanZero()) {
LoanScheduleModelRepaymentPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(params.getInstalmentNumber(),
startDate, params.getActualRepaymentDate(), totalInterest.zero(), totalInterest.zero(), totalInterest,
- totalInterest.zero(), totalInterest.zero(), totalInterest, true);
+ totalInterest.zero(), totalInterest.zero(), totalInterest, true, mc);
params.incrementInstalmentNumber();
periods.add(installment);
params.getCompoundingDateVariations().put(startDate, new TreeMap<>(params.getCompoundingMap()));
@@ -2189,7 +2189,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
// for complete schedule generation
LoanScheduleParams loanScheduleParams = LoanScheduleParams.createLoanScheduleParamsForCompleteUpdate(recalculationDetails,
- loanRepaymentScheduleTransactionProcessor, scheduleTillDate, applyInterestRecalculation);
+ loanRepaymentScheduleTransactionProcessor, scheduleTillDate, applyInterestRecalculation, mc);
List<LoanScheduleModelPeriod> periods = new ArrayList<>();
final List<LoanRepaymentScheduleInstallment> retainedInstallments = new ArrayList<>();
@@ -2402,7 +2402,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
installment.resetDerivedComponents();
newRepaymentScheduleInstallments.add(installment);
outstandingBalance = outstandingBalance.minus(installment.getPrincipal(currency));
- final LoanScheduleModelPeriod loanScheduleModelPeriod = createLoanScheduleModelPeriod(installment, outstandingBalance);
+ final LoanScheduleModelPeriod loanScheduleModelPeriod = createLoanScheduleModelPeriod(installment, outstandingBalance, mc);
periods.add(loanScheduleModelPeriod);
totalCumulativePrincipal = totalCumulativePrincipal.plus(installment.getPrincipal(currency));
totalCumulativeInterest = totalCumulativeInterest.plus(installment.getInterestCharged(currency));
@@ -2493,7 +2493,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap,
uncompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest,
newRepaymentScheduleInstallments, recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate,
- currency, applyInterestRecalculation);
+ currency, applyInterestRecalculation, mc);
retainedInstallments.addAll(newRepaymentScheduleInstallments);
loanScheduleParams.getCompoundingDateVariations().putAll(compoundingDateVariations);
loanApplicationTerms.updateTotalInterestDue(Money.of(currency, loan.getSummary().getTotalInterestCharged()));
@@ -2729,13 +2729,13 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
}
private LoanScheduleModelPeriod createLoanScheduleModelPeriod(final LoanRepaymentScheduleInstallment installment,
- final Money outstandingPrincipal) {
+ final Money outstandingPrincipal, final MathContext mc) {
final MonetaryCurrency currency = outstandingPrincipal.getCurrency();
return LoanScheduleModelRepaymentPeriod.repayment(installment.getInstallmentNumber(), installment.getFromDate(),
installment.getDueDate(), installment.getPrincipal(currency), outstandingPrincipal,
installment.getInterestCharged(currency), installment.getFeeChargesCharged(currency),
- installment.getPenaltyChargesCharged(currency), installment.getDue(currency),
- installment.isRecalculatedInterestComponent());
+ installment.getPenaltyChargesCharged(currency), installment.getDue(currency), installment.isRecalculatedInterestComponent(),
+ mc);
}
private LocalDate getNextRestScheduleDate(LocalDate startDate, LoanApplicationTerms loanApplicationTerms,
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
similarity index 90%
rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
rename to fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
index eb077751e..c0e9f4d9b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
+import java.math.MathContext;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
@@ -45,9 +46,9 @@ import org.springframework.stereotype.Component;
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
@Override
- public List<LoanScheduleModelRepaymentPeriod> generateRepaymentPeriods(final LocalDate scheduleStartDate,
+ public List<LoanScheduleModelRepaymentPeriod> generateRepaymentPeriods(final MathContext mc, final LocalDate scheduleStartDate,
final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO) {
- final Money zeroAmount = Money.zero(loanApplicationTerms.getCurrency());
+ final Money zeroAmount = Money.zero(loanApplicationTerms.getCurrency(), mc);
final int numberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
final ArrayList<LoanScheduleModelRepaymentPeriod> repaymentPeriods = new ArrayList<>(numberOfRepayments);
LocalDate lastRepaymentDate = scheduleStartDate;
@@ -65,7 +66,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
}
nextRepaymentDate = applyLoanTermVariations(loanApplicationTerms, nextRepaymentDate);
repaymentPeriods.add(LoanScheduleModelRepaymentPeriod.repayment(repaymentPeriodNumber, lastRepaymentDate, nextRepaymentDate,
- zeroAmount, zeroAmount, zeroAmount, zeroAmount, zeroAmount, zeroAmount, false));
+ zeroAmount, zeroAmount, zeroAmount, zeroAmount, zeroAmount, zeroAmount, false, mc));
lastRepaymentDate = nextRepaymentDate;
isFirstRepayment = false;
}
@@ -75,11 +76,13 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
private LocalDate applyLoanTermVariations(final LoanApplicationTerms loanApplicationTerms, final LocalDate scheduledDueDate) {
LocalDate modifiedScheduledDueDate = scheduledDueDate;
// due date changes should be applied only for that dueDate
- if (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(scheduledDueDate)) {
- LoanTermVariationsData loanTermVariationsData = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation();
- if (DateUtils.isEqual(modifiedScheduledDueDate, loanTermVariationsData.getTermVariationApplicableFrom())) {
- modifiedScheduledDueDate = loanTermVariationsData.getDateValue();
- loanApplicationTerms.updateVariationDays(DateUtils.getDifferenceInDays(scheduledDueDate, modifiedScheduledDueDate));
+ if (loanApplicationTerms.getLoanTermVariations() != null) {
+ if (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(scheduledDueDate)) {
+ LoanTermVariationsData loanTermVariationsData = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation();
+ if (DateUtils.isEqual(modifiedScheduledDueDate, loanTermVariationsData.getTermVariationApplicableFrom())) {
+ modifiedScheduledDueDate = loanTermVariationsData.getDateValue();
+ loanApplicationTerms.updateVariationDays(DateUtils.getDifferenceInDays(scheduledDueDate, modifiedScheduledDueDate));
+ }
}
}
return modifiedScheduledDueDate;
@@ -197,28 +200,30 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
private AdjustedDateDetailsDTO recursivelyCheckNonWorkingDaysAndHolidaysAndWorkingDaysExemptionToGenerateNextRepaymentPeriodDate(
final AdjustedDateDetailsDTO adjustedDateDetailsDTO, final LoanApplicationTerms loanApplicationTerms,
final HolidayDetailDTO holidayDetailDTO, final boolean isFirstRepayment) {
- final Recur recur = CalendarUtils.getICalRecur(holidayDetailDTO.getWorkingDays().getRecurrence());
- final boolean isSevenDaysWeek = (recur.getDayList().size() == 7); // 7 Seven days in the week
- // If Workings days are not seven day week
- if (!isSevenDaysWeek) {
- checkAndUpdateWorkingDayIfRepaymentDateIsNonWorkingDay(adjustedDateDetailsDTO, holidayDetailDTO, loanApplicationTerms,
+ if (holidayDetailDTO != null) {
+ final Recur recur = CalendarUtils.getICalRecur(holidayDetailDTO.getWorkingDays().getRecurrence());
+ final boolean isSevenDaysWeek = (recur.getDayList().size() == 7); // 7 Seven days in the week
+ // If Workings days are not seven day week
+ if (!isSevenDaysWeek) {
+ checkAndUpdateWorkingDayIfRepaymentDateIsNonWorkingDay(adjustedDateDetailsDTO, holidayDetailDTO, loanApplicationTerms,
+ isFirstRepayment);
+ }
+ // Check Holidays If applied
+ checkAndUpdateWorkingDayIfRepaymentDateIsHolidayDay(adjustedDateDetailsDTO, holidayDetailDTO, loanApplicationTerms,
isFirstRepayment);
- }
- // Check Holidays If applied
- checkAndUpdateWorkingDayIfRepaymentDateIsHolidayDay(adjustedDateDetailsDTO, holidayDetailDTO, loanApplicationTerms,
- isFirstRepayment);
-
- /**
- * Check Changed Schedule Date is holiday or is not a working day Then re-call this method to get the non
- * holiday and working day
- */
- if ((holidayDetailDTO.isHolidayEnabled() && HolidayUtil.getApplicableHoliday(adjustedDateDetailsDTO.getChangedScheduleDate(),
- holidayDetailDTO.getHolidays()) != null)
- || WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), adjustedDateDetailsDTO.getChangedScheduleDate())) {
- recursivelyCheckNonWorkingDaysAndHolidaysAndWorkingDaysExemptionToGenerateNextRepaymentPeriodDate(adjustedDateDetailsDTO,
- loanApplicationTerms, holidayDetailDTO, isFirstRepayment);
- }
+ /**
+ * Check Changed Schedule Date is holiday or is not a working day Then re-call this method to get the non
+ * holiday and working day
+ */
+ if ((holidayDetailDTO.isHolidayEnabled() && HolidayUtil.getApplicableHoliday(adjustedDateDetailsDTO.getChangedScheduleDate(),
+ holidayDetailDTO.getHolidays()) != null)
+ || WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(),
+ adjustedDateDetailsDTO.getChangedScheduleDate())) {
+ recursivelyCheckNonWorkingDaysAndHolidaysAndWorkingDaysExemptionToGenerateNextRepaymentPeriodDate(adjustedDateDetailsDTO,
+ loanApplicationTerms, holidayDetailDTO, isFirstRepayment);
+ }
+ }
return adjustedDateDetailsDTO;
}
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 8f13670bc..e4fb8fd2b 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
@@ -249,6 +249,8 @@ public final class LoanApplicationTerms {
this.inArrearsTolerance = builder.inArrearsTolerance;
this.disbursementDatas = builder.disbursementDatas;
this.downPaymentAmount = builder.downPaymentAmount;
+ this.submittedOnDate = builder.submittedOnDate;
+ this.seedDate = builder.seedDate;
}
public static class Builder {
@@ -272,6 +274,8 @@ public final class LoanApplicationTerms {
private Money inArrearsTolerance;
private List<DisbursementData> disbursementDatas;
private Money downPaymentAmount;
+ private LocalDate submittedOnDate;
+ private LocalDate seedDate;
public Builder currency(ApplicationCurrency currency) {
this.currency = currency;
@@ -343,11 +347,6 @@ public final class LoanApplicationTerms {
return this;
}
- public Builder variationsDataWrapper(LoanTermVariationsDataWrapper variationsDataWrapper) {
- this.variationsDataWrapper = variationsDataWrapper;
- return this;
- }
-
public Builder fixedLength(Integer fixedLength) {
this.fixedLength = fixedLength;
return this;
@@ -368,23 +367,41 @@ public final class LoanApplicationTerms {
return this;
}
+ public Builder submittedOnDate(LocalDate submittedOnDate) {
+ this.submittedOnDate = submittedOnDate;
+ return this;
+ }
+
+ public Builder seedDate(LocalDate seedDate) {
+ this.seedDate = seedDate;
+ return this;
+ }
+
public LoanApplicationTerms build() {
return new LoanApplicationTerms(this);
}
}
- public static LoanApplicationTerms assembleFrom(LoanRepaymentScheduleModelData modelData) {
- Money principal = Money.of(modelData.currency().toData(), modelData.disbursementAmount());
- Money downPaymentAmount = Money.zero(modelData.currency().toData());
+ public static LoanApplicationTerms assembleFrom(LoanRepaymentScheduleModelData modelData, MathContext mc) {
+ Money principal = Money.of(modelData.currency().toData(), modelData.disbursementAmount(), mc);
+ Money downPaymentAmount = Money.zero(modelData.currency().toData(), mc);
if (modelData.downPaymentEnabled()) {
downPaymentAmount = Money.of(modelData.currency().toData(),
- MathUtil.percentageOf(principal.getAmount(), modelData.disbursementAmount(), 19));
+ MathUtil.percentageOf(principal.getAmount(), modelData.disbursementAmount(), mc), mc);
if (modelData.installmentAmountInMultiplesOf() != null) {
- downPaymentAmount = Money.roundToMultiplesOf(downPaymentAmount, modelData.installmentAmountInMultiplesOf());
+ downPaymentAmount = Money.roundToMultiplesOf(downPaymentAmount, modelData.installmentAmountInMultiplesOf(), mc);
}
}
+ LocalDate seedDate;
+
+ if (modelData.disbursementDate() != null) {
+ seedDate = modelData.disbursementDate();
+ } else {
+ seedDate = modelData.scheduleGenerationStartDate();
+ }
+
return new Builder().currency(modelData.currency()).loanTermFrequency(modelData.numberOfRepayments())
.loanTermPeriodFrequencyType(PeriodFrequencyType.valueOf(modelData.repaymentFrequencyType()))
.numberOfRepayments(modelData.numberOfRepayments()).repaymentEvery(modelData.repaymentFrequency())
@@ -394,8 +411,8 @@ public final class LoanApplicationTerms {
.annualNominalInterestRate(modelData.annualNominalInterestRate()).principal(principal)
.expectedDisbursementDate(modelData.disbursementDate()).repaymentsStartingFromDate(modelData.scheduleGenerationStartDate())
.daysInMonthType(modelData.daysInMonth()).daysInYearType(modelData.daysInYear()).fixedLength(modelData.fixedLength())
- .inArrearsTolerance(Money.zero(modelData.currency().toData())).disbursementDatas(new ArrayList<>())
- .downPaymentAmount(downPaymentAmount).build();
+ .inArrearsTolerance(Money.zero(modelData.currency().toData(), mc)).disbursementDatas(new ArrayList<>())
+ .downPaymentAmount(downPaymentAmount).submittedOnDate(modelData.scheduleGenerationStartDate()).seedDate(seedDate).build();
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java
index fd848751e..4460cfe8d 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleModelRepaymentPeriod.java
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
@@ -46,18 +47,20 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
private final Set<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new HashSet<>();
private boolean isEMIFixedSpecificToInstallment = false;
BigDecimal rescheduleInterestPortion;
+ private final MathContext mc;
public static LoanScheduleModelRepaymentPeriod repayment(final int periodNumber, final LocalDate startDate,
final LocalDate scheduledDueDate, final Money principalDue, final Money outstandingLoanBalance, final Money interestDue,
- final Money feeChargesDue, final Money penaltyChargesDue, final Money totalDue, boolean recalculatedInterestComponent) {
+ final Money feeChargesDue, final Money penaltyChargesDue, final Money totalDue, boolean recalculatedInterestComponent,
+ final MathContext mc) {
return new LoanScheduleModelRepaymentPeriod(periodNumber, startDate, scheduledDueDate, principalDue, outstandingLoanBalance,
- interestDue, feeChargesDue, penaltyChargesDue, totalDue, recalculatedInterestComponent);
+ interestDue, feeChargesDue, penaltyChargesDue, totalDue, recalculatedInterestComponent, mc);
}
public LoanScheduleModelRepaymentPeriod(final int periodNumber, final LocalDate fromDate, final LocalDate dueDate,
final Money principalDue, final Money outstandingLoanBalance, final Money interestDue, final Money feeChargesDue,
- final Money penaltyChargesDue, final Money totalDue, final boolean recalculatedInterestComponent) {
+ final Money penaltyChargesDue, final Money totalDue, final boolean recalculatedInterestComponent, final MathContext mc) {
this.periodNumber = periodNumber;
this.fromDate = fromDate;
this.dueDate = dueDate;
@@ -68,6 +71,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
this.penaltyChargesDue = penaltyChargesDue;
this.totalDue = totalDue;
this.recalculatedInterestComponent = recalculatedInterestComponent;
+ this.mc = mc;
}
@Override
@@ -144,15 +148,15 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
@Override
public void addLoanCharges(BigDecimal feeCharge, BigDecimal penaltyCharge) {
- this.feeChargesDue = this.feeChargesDue.plus(feeCharge);
- this.penaltyChargesDue = this.penaltyChargesDue.plus(penaltyCharge);
- this.totalDue = this.totalDue.plus(feeCharge).plus(penaltyCharge);
+ this.feeChargesDue = this.feeChargesDue.plus(feeCharge, mc);
+ this.penaltyChargesDue = this.penaltyChargesDue.plus(penaltyCharge, mc);
+ this.totalDue = this.totalDue.plus(feeCharge, mc).plus(penaltyCharge, mc);
}
@Override
public void addPrincipalAmount(final Money principalDue) {
- this.principalDue = this.principalDue.plus(principalDue);
- this.totalDue = this.totalDue.plus(principalDue);
+ this.principalDue = this.principalDue.plus(principalDue, mc);
+ this.totalDue = this.totalDue.plus(principalDue, mc);
}
@Override
@@ -162,8 +166,8 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
@Override
public void addInterestAmount(Money interestDue) {
- this.interestDue = this.interestDue.plus(interestDue);
- this.totalDue = this.totalDue.plus(interestDue);
+ this.interestDue = this.interestDue.plus(interestDue, mc);
+ this.totalDue = this.totalDue.plus(interestDue, mc);
}
public void setPeriodNumber(int periodNumber) {
diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
index fd5e824e8..16ceae371 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ScheduledDateGenerator.java
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
+import java.math.MathContext;
import java.time.LocalDate;
import java.util.List;
import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO;
@@ -27,8 +28,8 @@ import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
public interface ScheduledDateGenerator {
- List<LoanScheduleModelRepaymentPeriod> generateRepaymentPeriods(LocalDate scheduledDueDate, LoanApplicationTerms loanApplicationTerms,
- HolidayDetailDTO holidayDetailDTO);
+ List<LoanScheduleModelRepaymentPeriod> generateRepaymentPeriods(MathContext mc, LocalDate scheduledDueDate,
+ LoanApplicationTerms loanApplicationTerms, HolidayDetailDTO holidayDetailDTO);
LocalDate getLastRepaymentDate(LoanApplicationTerms loanApplicationTerms, HolidayDetailDTO holidayDetailDTO);
diff --git a/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java b/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java
index ada2be619..c1eb1ad8b 100644
--- a/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java
+++ b/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashMap;
@@ -64,6 +65,7 @@ public class SingleLoanChargeRepaymentScheduleProcessingWrapperTest {
@BeforeAll
public static void init() {
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
}
@Test
@@ -142,11 +144,12 @@ public class SingleLoanChargeRepaymentScheduleProcessingWrapperTest {
@NotNull
private LoanRepaymentScheduleInstallment createPeriod(int periodId, LocalDate start, LocalDate end) {
LoanRepaymentScheduleInstallment period = Mockito.mock(LoanRepaymentScheduleInstallment.class);
+ MathContext mc = new MathContext(12, RoundingMode.HALF_EVEN);
Mockito.when(period.getInstallmentNumber()).thenReturn(periodId);
Mockito.when(period.getFromDate()).thenReturn(start);
Mockito.when(period.getDueDate()).thenReturn(end);
- Money principal = Money.of(currency, new BigDecimal("1000.0"));
- Money interest = Money.of(currency, BigDecimal.ZERO);
+ Money principal = Money.of(currency, new BigDecimal("1000.0"), mc);
+ Money interest = Money.of(currency, BigDecimal.ZERO, mc);
Mockito.when(period.getPrincipal(eq(currency))).thenReturn(principal);
Mockito.when(period.getInterestCharged(eq(currency))).thenReturn(interest);
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 7499fccaa..6375353af 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
@@ -176,7 +176,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
final Integer installmentAmountInMultiplesOf = loan.getLoanProduct().getInstallmentAmountInMultiplesOf();
final LoanProductRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
ProgressiveLoanInterestScheduleModel scheduleModel = emiCalculator.generateModel(loanProductRelatedDetail,
- installmentAmountInMultiplesOf, installments);
+ installmentAmountInMultiplesOf, installments, overpaymentHolder.getMoneyObject().getMc());
ProgressiveTransactionCtx ctx = new ProgressiveTransactionCtx(currency, installments, charges, overpaymentHolder,
changedTransactionDetail, scheduleModel);
diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/InterestPeriod.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/InterestPeriod.java
index 85366e602..62c79443d 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/InterestPeriod.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/InterestPeriod.java
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.time.LocalDate;
import java.util.Optional;
import lombok.EqualsAndHashCode;
@@ -44,9 +45,10 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
private Money disbursementAmount;
private Money balanceCorrectionAmount;
private Money outstandingLoanBalance;
+ private final MathContext mc;
public InterestPeriod(RepaymentPeriod repaymentPeriod, LocalDate fromDate, LocalDate dueDate, BigDecimal rateFactor,
- Money disbursementAmount, Money balanceCorrectionAmount, Money outstandingLoanBalance) {
+ Money disbursementAmount, Money balanceCorrectionAmount, Money outstandingLoanBalance, MathContext mc) {
this.repaymentPeriod = repaymentPeriod;
this.fromDate = fromDate;
this.dueDate = dueDate;
@@ -54,12 +56,13 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
this.disbursementAmount = disbursementAmount;
this.balanceCorrectionAmount = balanceCorrectionAmount;
this.outstandingLoanBalance = outstandingLoanBalance;
+ this.mc = mc;
}
- public InterestPeriod(RepaymentPeriod repaymentPeriod, InterestPeriod interestPeriod) {
+ public InterestPeriod(RepaymentPeriod repaymentPeriod, InterestPeriod interestPeriod, MathContext mc) {
this(repaymentPeriod, interestPeriod.getFromDate(), interestPeriod.getDueDate(), interestPeriod.getRateFactor(),
interestPeriod.getDisbursementAmount(), interestPeriod.getBalanceCorrectionAmount(),
- interestPeriod.getOutstandingLoanBalance());
+ interestPeriod.getOutstandingLoanBalance(), mc);
}
@Override
@@ -72,11 +75,11 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
}
public void addDisbursementAmount(final Money disbursementAmount) {
- this.disbursementAmount = MathUtil.plus(this.disbursementAmount, disbursementAmount);
+ this.disbursementAmount = MathUtil.plus(this.disbursementAmount, disbursementAmount, mc);
}
public Money getCalculatedDueInterest() {
- return getOutstandingLoanBalance().multipliedBy(getRateFactor());
+ return getOutstandingLoanBalance().multipliedBy(getRateFactor(), mc);
}
public void updateOutstandingLoanBalance() {
@@ -86,17 +89,17 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
InterestPeriod previousInterestPeriod = previousRepaymentPeriod.get().getInterestPeriods()
.get(previousRepaymentPeriod.get().getInterestPeriods().size() - 1);
this.outstandingLoanBalance = previousInterestPeriod.getOutstandingLoanBalance()//
- .plus(previousInterestPeriod.getDisbursementAmount())//
- .plus(previousInterestPeriod.getBalanceCorrectionAmount())//
- .minus(previousRepaymentPeriod.get().getDuePrincipal())//
- .plus(previousRepaymentPeriod.get().getPaidPrincipal());//
+ .plus(previousInterestPeriod.getDisbursementAmount(), mc)//
+ .plus(previousInterestPeriod.getBalanceCorrectionAmount(), mc)//
+ .minus(previousRepaymentPeriod.get().getDuePrincipal(), mc)//
+ .plus(previousRepaymentPeriod.get().getPaidPrincipal(), mc);//
}
} else {
int index = getRepaymentPeriod().getInterestPeriods().indexOf(this);
InterestPeriod previousInterestPeriod = getRepaymentPeriod().getInterestPeriods().get(index - 1);
this.outstandingLoanBalance = previousInterestPeriod.getOutstandingLoanBalance() //
- .plus(previousInterestPeriod.getBalanceCorrectionAmount()) //
- .plus(previousInterestPeriod.getDisbursementAmount()); //
+ .plus(previousInterestPeriod.getBalanceCorrectionAmount(), mc) //
+ .plus(previousInterestPeriod.getDisbursementAmount(), mc); //
}
}
diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
index 45f61c02f..7f51b9db4 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/ProgressiveLoanInterestScheduleModel.java
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
@@ -38,33 +39,36 @@ public class ProgressiveLoanInterestScheduleModel {
private final List<InterestRate> interestRates;
private final LoanProductRelatedDetail loanProductRelatedDetail;
private final Integer installmentAmountInMultiplesOf;
+ private MathContext mc;
public ProgressiveLoanInterestScheduleModel(List<RepaymentPeriod> repaymentPeriods, LoanProductRelatedDetail loanProductRelatedDetail,
- Integer installmentAmountInMultiplesOf) {
+ Integer installmentAmountInMultiplesOf, MathContext mc) {
this.repaymentPeriods = repaymentPeriods;
this.interestRates = new ArrayList<>();
this.loanProductRelatedDetail = loanProductRelatedDetail;
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
+ this.mc = mc;
}
private ProgressiveLoanInterestScheduleModel(List<RepaymentPeriod> repaymentPeriods, final List<InterestRate> interestRates,
- LoanProductRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf) {
+ LoanProductRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf, MathContext mc) {
+ this.mc = mc;
this.repaymentPeriods = copyRepaymentPeriods(repaymentPeriods);
this.interestRates = new ArrayList<>(interestRates);
this.loanProductRelatedDetail = loanProductRelatedDetail;
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
}
- public ProgressiveLoanInterestScheduleModel deepCopy() {
+ public ProgressiveLoanInterestScheduleModel deepCopy(MathContext mc) {
return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, interestRates, loanProductRelatedDetail,
- installmentAmountInMultiplesOf);
+ installmentAmountInMultiplesOf, mc);
}
private List<RepaymentPeriod> copyRepaymentPeriods(final List<RepaymentPeriod> repaymentPeriods) {
final List<RepaymentPeriod> repaymentCopies = new ArrayList<>(repaymentPeriods.size());
RepaymentPeriod previousPeriod = null;
for (RepaymentPeriod repaymentPeriod : repaymentPeriods) {
- RepaymentPeriod currentPeriod = new RepaymentPeriod(previousPeriod, repaymentPeriod);
+ RepaymentPeriod currentPeriod = new RepaymentPeriod(previousPeriod, repaymentPeriod, mc);
previousPeriod = currentPeriod;
repaymentCopies.add(currentPeriod);
}
@@ -175,11 +179,11 @@ public class ProgressiveLoanInterestScheduleModel {
previousInterestPeriod.addDisbursementAmount(disbursedAmount);
previousInterestPeriod.addBalanceCorrectionAmount(correctionAmount);
final InterestPeriod interestPeriod = new InterestPeriod(repaymentPeriod, previousInterestPeriod.getDueDate(), originalDueDate,
- BigDecimal.ZERO, getZero(), getZero(), getZero());
+ BigDecimal.ZERO, getZero(mc), getZero(mc), getZero(mc), mc);
repaymentPeriod.getInterestPeriods().add(interestPeriod);
}
- private Money getZero() {
- return Money.zero(loanProductRelatedDetail.getCurrency());
+ private Money getZero(MathContext mc) {
+ return Money.zero(loanProductRelatedDetail.getCurrency(), mc);
}
}
diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java
index d9ff4e89f..129433527 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/RepaymentPeriod.java
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@@ -54,20 +55,23 @@ public class RepaymentPeriod {
private Memo<Money> calculatedDueInterestCalculation;
private Memo<Money> dueInterestCalculation;
private Memo<Money> outstandingBalanceCalculation;
+ private final MathContext mc;
- public RepaymentPeriod(RepaymentPeriod previous, LocalDate fromDate, LocalDate dueDate, Money emi) {
+ public RepaymentPeriod(RepaymentPeriod previous, LocalDate fromDate, LocalDate dueDate, Money emi, MathContext mc) {
this.previous = previous;
this.fromDate = fromDate;
this.dueDate = dueDate;
this.emi = emi;
+ this.mc = mc;
this.interestPeriods = new ArrayList<>();
// There is always at least 1 interest period, by default with same from-due date as repayment period
- getInterestPeriods().add(new InterestPeriod(this, getFromDate(), getDueDate(), BigDecimal.ZERO, getZero(), getZero(), getZero()));
- this.paidInterest = getZero();
- this.paidPrincipal = getZero();
+ getInterestPeriods()
+ .add(new InterestPeriod(this, getFromDate(), getDueDate(), BigDecimal.ZERO, getZero(mc), getZero(mc), getZero(mc), mc));
+ this.paidInterest = getZero(mc);
+ this.paidPrincipal = getZero(mc);
}
- public RepaymentPeriod(RepaymentPeriod previous, RepaymentPeriod repaymentPeriod) {
+ public RepaymentPeriod(RepaymentPeriod previous, RepaymentPeriod repaymentPeriod, MathContext mc) {
this.previous = previous;
this.fromDate = repaymentPeriod.fromDate;
this.dueDate = repaymentPeriod.dueDate;
@@ -75,9 +79,10 @@ public class RepaymentPeriod {
this.interestPeriods = new ArrayList<>();
this.paidPrincipal = repaymentPeriod.paidPrincipal;
this.paidInterest = repaymentPeriod.paidInterest;
+ this.mc = mc;
// There is always at least 1 interest period, by default with same from-due date as repayment period
for (InterestPeriod interestPeriod : repaymentPeriod.interestPeriods) {
- interestPeriods.add(new InterestPeriod(this, interestPeriod));
+ interestPeriods.add(new InterestPeriod(this, interestPeriod, mc));
}
}
@@ -105,21 +110,21 @@ public class RepaymentPeriod {
}
private Money calculateCalculatedDueInterest() {
- Money calculatedDueInterest = getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest).reduce(getZero(),
- Money::plus);
+ Money calculatedDueInterest = getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest).reduce(getZero(mc),
+ (m1, m2) -> m1.plus(m2, mc));
if (getPrevious().isPresent()) {
- calculatedDueInterest = calculatedDueInterest.add(getPrevious().get().getUnrecognizedInterest());
+ calculatedDueInterest = calculatedDueInterest.add(getPrevious().get().getUnrecognizedInterest(), mc);
}
return calculatedDueInterest;
}
- private Money getZero() {
+ private Money getZero(MathContext mc) {
// EMI is always initiated
- return this.emi.zero();
+ return this.emi.zero(mc);
}
public Money getCalculatedDuePrincipal() {
- return getEmi().minus(getCalculatedDueInterest());
+ return getEmi().minus(getCalculatedDueInterest(), mc);
}
public boolean isFullyPaid() {
@@ -138,11 +143,11 @@ public class RepaymentPeriod {
public Money getDuePrincipal() {
// Due principal might be the maximum paid if there is pay-off or early repayment
- return MathUtil.max(getEmi().minus(getDueInterest()), getPaidPrincipal(), false);
+ return MathUtil.max(getEmi().minus(getDueInterest(), mc), getPaidPrincipal(), false);
}
public Money getUnrecognizedInterest() {
- return getCalculatedDueInterest().minus(getDueInterest());
+ return getCalculatedDueInterest().minus(getDueInterest(), mc);
}
public Money getOutstandingLoanBalance() {
@@ -150,22 +155,22 @@ public class RepaymentPeriod {
outstandingBalanceCalculation = Memo.of(() -> {
InterestPeriod lastInstallmentPeriod = getInterestPeriods().get(getInterestPeriods().size() - 1);
Money calculatedOutStandingLoanBalance = lastInstallmentPeriod.getOutstandingLoanBalance() //
- .plus(lastInstallmentPeriod.getBalanceCorrectionAmount()) //
- .plus(lastInstallmentPeriod.getDisbursementAmount()) //
- .minus(getDuePrincipal())//
- .plus(getPaidPrincipal());//
- return MathUtil.negativeToZero(calculatedOutStandingLoanBalance);
+ .plus(lastInstallmentPeriod.getBalanceCorrectionAmount(), mc) //
+ .plus(lastInstallmentPeriod.getDisbursementAmount(), mc) //
+ .minus(getDuePrincipal(), mc)//
+ .plus(getPaidPrincipal(), mc);//
+ return MathUtil.negativeToZero(calculatedOutStandingLoanBalance, mc);
}, () -> new Object[] { paidPrincipal, paidInterest, interestPeriods });
}
return outstandingBalanceCalculation.get();
}
public void addPaidPrincipalAmount(Money paidPrincipal) {
- this.paidPrincipal = MathUtil.plus(this.paidPrincipal, paidPrincipal);
+ this.paidPrincipal = MathUtil.plus(this.paidPrincipal, paidPrincipal, mc);
}
public void addPaidInterestAmount(Money paidInterest) {
- this.paidInterest = MathUtil.plus(this.paidInterest, paidInterest);
+ this.paidInterest = MathUtil.plus(this.paidInterest, paidInterest, mc);
}
public Money getInitialBalanceForEmiRecalculation() {
@@ -173,10 +178,10 @@ public class RepaymentPeriod {
if (getPrevious().isPresent()) {
initialBalance = getPrevious().get().getOutstandingLoanBalance();
} else {
- initialBalance = getZero();
+ initialBalance = getZero(mc);
}
- Money totalDisbursedAmount = getInterestPeriods().stream().map(InterestPeriod::getDisbursementAmount).reduce(getZero(),
- Money::plus);
- return initialBalance.add(totalDisbursedAmount);
+ Money totalDisbursedAmount = getInterestPeriods().stream().map(InterestPeriod::getDisbursementAmount).reduce(getZero(mc),
+ (m1, m2) -> m1.plus(m2, mc));
+ return initialBalance.add(totalDisbursedAmount, mc);
}
}
diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
index 2de29d2c9..e4382e54d 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
@@ -87,17 +87,17 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
: loanApplicationTerms.getSubmittedOnDate();
final LoanScheduleParams scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency,
- Money.of(currency, chargesDueAtTimeOfDisbursement), periodStartDate, Money.zero(currency));
+ Money.of(currency, chargesDueAtTimeOfDisbursement, mc), periodStartDate, Money.zero(currency, mc), mc);
// charges which depends on total loan interest will be added to this
// set and handled separately after all installments generated
final Set<LoanCharge> nonCompoundingCharges = separateTotalCompoundingPercentageCharges(loanCharges);
- final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods = scheduledDateGenerator
- .generateRepaymentPeriods(periodStartDate, loanApplicationTerms, holidayDetailDTO);
+ final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods = scheduledDateGenerator.generateRepaymentPeriods(mc,
+ periodStartDate, loanApplicationTerms, holidayDetailDTO);
final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator.generateInterestScheduleModel(
expectedRepaymentPeriods, loanApplicationTerms.toLoanProductRelatedDetail(),
- loanApplicationTerms.getInstallmentAmountInMultiplesOf());
+ loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc);
final List<LoanScheduleModelPeriod> periods = new ArrayList<>(expectedRepaymentPeriods.size());
prepareDisbursementsOnLoanApplicationTerms(loanApplicationTerms);
@@ -110,7 +110,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
scheduleParams.setActualRepaymentDate(repaymentPeriod.getDueDate());
processDisbursements(loanApplicationTerms, disbursementDataList, scheduleParams, interestScheduleModel, periods,
- chargesDueAtTimeOfDisbursement, false);
+ chargesDueAtTimeOfDisbursement, false, mc);
repaymentPeriod.setPeriodNumber(scheduleParams.getInstalmentNumber());
if (loanApplicationTerms.getLoanTermVariations() != null) {
@@ -135,7 +135,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
scheduleParams.addTotalCumulativePrincipal(principalDue);
scheduleParams.addTotalCumulativeInterest(interestDue);
// add everything
- scheduleParams.addTotalRepaymentExpected(principalDue.plus(interestDue));
+ scheduleParams.addTotalRepaymentExpected(principalDue.plus(interestDue, mc));
});
applyChargesForCurrentPeriod(repaymentPeriod, loanCharges, scheduleParams, currency, mc);
@@ -147,7 +147,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
if (loanApplicationTerms.isMultiDisburseLoan()) {
processDisbursements(loanApplicationTerms, disbursementDataList, scheduleParams, interestScheduleModel, periods,
- chargesDueAtTimeOfDisbursement, true);
+ chargesDueAtTimeOfDisbursement, true, mc);
}
// determine fees and penalties for charges which depends on total
@@ -158,8 +158,8 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
final BigDecimal totalOutstanding = BigDecimal.ZERO;
return LoanScheduleModel.from(periods, applicationCurrency, interestScheduleModel.getLoanTermInDays(),
- scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount()),
- scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount()).getAmount(),
+ scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount(), mc),
+ scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount(), mc).getAmount(),
totalPrincipalPaid, scheduleParams.getTotalCumulativeInterest().getAmount(),
scheduleParams.getTotalFeeChargesCharged().getAmount(), scheduleParams.getTotalPenaltyChargesCharged().getAmount(),
scheduleParams.getTotalRepaymentExpected().getAmount(), totalOutstanding);
@@ -167,7 +167,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
public LoanScheduleModel generate(final MathContext mc, final LoanRepaymentScheduleModelData modelData) {
- LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(modelData);
+ LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(modelData, mc);
return generate(mc, loanApplicationTerms, null, null);
}
@@ -184,7 +184,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
private void processDisbursements(final LoanApplicationTerms loanApplicationTerms,
final ArrayList<DisbursementData> disbursementDataList, final LoanScheduleParams scheduleParams,
final ProgressiveLoanInterestScheduleModel interestScheduleModel, final List<LoanScheduleModelPeriod> periods,
- final BigDecimal chargesDueAtTimeOfDisbursement, final boolean includeDisbursementsAfterMaturityDate) {
+ final BigDecimal chargesDueAtTimeOfDisbursement, final boolean includeDisbursementsAfterMaturityDate, final MathContext mc) {
for (DisbursementData disbursementData : disbursementDataList) {
final LocalDate disbursementDate = disbursementData.disbursementDate();
@@ -202,7 +202,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
Money outstandingBalance = emiCalculator.getOutstandingLoanBalance(interestScheduleModel, periodDueDate, disbursementDate);
- final Money disbursedAmount = Money.of(loanApplicationTerms.getCurrency(), disbursementData.getPrincipal());
+ final Money disbursedAmount = Money.of(loanApplicationTerms.getCurrency(), disbursementData.getPrincipal(), mc);
final LoanScheduleModelDisbursementPeriod disbursementPeriod = LoanScheduleModelDisbursementPeriod
.disbursement(disbursementData.disbursementDate(), disbursedAmount, chargesDueAtTimeOfDisbursement);
periods.add(disbursementPeriod);
@@ -218,7 +218,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
}
}
- Money downPaymentAmount = Money.zero(loanApplicationTerms.getCurrency());
+ Money downPaymentAmount = Money.zero(loanApplicationTerms.getCurrency(), mc);
if (loanApplicationTerms.isDownPaymentEnabled()) {
downPaymentAmount = Money.of(loanApplicationTerms.getCurrency(), MathUtil.percentageOf(disbursedAmount.getAmount(),
loanApplicationTerms.getDisbursedAmountPercentageForDownPayment(), 19));
@@ -321,7 +321,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
final MonetaryCurrency monetaryCurrency, final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed,
final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod,
final MathContext mc) {
- Money cumulative = Money.zero(monetaryCurrency);
+ Money cumulative = Money.zero(monetaryCurrency, mc);
if (loanCharges != null) {
for (final LoanCharge loanCharge : loanCharges) {
if (!loanCharge.isDueAtDisbursement() && loanCharge.isFeeCharge()) {
@@ -356,7 +356,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed,
final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod,
final MathContext mc) {
- Money cumulative = Money.zero(monetaryCurrency);
+ Money cumulative = Money.zero(monetaryCurrency, mc);
if (loanCharges != null) {
for (final LoanCharge loanCharge : loanCharges) {
if (loanCharge.isPenaltyCharge()) {
@@ -407,8 +407,8 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
final Collection<LoanScheduleModelPeriod> periods, final Set<LoanCharge> nonCompoundingCharges, MathContext mc) {
for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
if (loanScheduleModelPeriod.isRepaymentPeriod()) {
- PrincipalInterest principalInterest = new PrincipalInterest(Money.of(currency, loanScheduleModelPeriod.principalDue()),
- Money.of(currency, loanScheduleModelPeriod.interestDue()), null);
+ PrincipalInterest principalInterest = new PrincipalInterest(Money.of(currency, loanScheduleModelPeriod.principalDue(), mc),
+ Money.of(currency, loanScheduleModelPeriod.interestDue(), mc), null);
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(loanScheduleModelPeriod.periodFromDate(),
loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest,
scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativeInterest(),
diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java
index 157989912..ac10aeab3 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.loanproduct.calc;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
@@ -33,10 +34,10 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail
public interface EMICalculator {
ProgressiveLoanInterestScheduleModel generateInterestScheduleModel(List<LoanScheduleModelRepaymentPeriod> periods,
- LoanProductRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf);
+ LoanProductRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf, MathContext mc);
ProgressiveLoanInterestScheduleModel generateModel(LoanProductRelatedDetail loanProductRelatedDetail,
- Integer installmentAmountInMultiplesOf, List<LoanRepaymentScheduleInstallment> repaymentPeriods);
+ Integer installmentAmountInMultiplesOf, List<LoanRepaymentScheduleInstallment> repaymentPeriods, MathContext mc);
Optional<RepaymentPeriod> findRepaymentPeriod(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate dueDate);
diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
index c2ab25fa8..c97ef747f 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.loanproduct.calc;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.time.LocalDate;
import java.time.Year;
import java.util.ArrayList;
@@ -29,7 +30,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.organisation.monetary.domain.Money;
-import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
@@ -40,12 +40,10 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLo
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.RepaymentPeriod;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
-import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
-@DependsOn("moneyHelper")
public final class ProgressiveEMICalculator implements EMICalculator {
private static final BigDecimal DIVISOR_100 = new BigDecimal("100");
@@ -53,19 +51,19 @@ public final class ProgressiveEMICalculator implements EMICalculator {
@Override
public ProgressiveLoanInterestScheduleModel generateInterestScheduleModel(final List<LoanScheduleModelRepaymentPeriod> periods,
- final LoanProductRelatedDetail loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf) {
- final Money zeroAmount = Money.zero(loanProductRelatedDetail.getCurrency());
+ final LoanProductRelatedDetail loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf, final MathContext mc) {
+ final Money zeroAmount = Money.zero(loanProductRelatedDetail.getCurrency(), mc);
final ArrayList<RepaymentPeriod> interestRepaymentModelList = new ArrayList<>(periods.size());
RepaymentPeriod previousPeriod = null;
for (final LoanScheduleModelRepaymentPeriod period : periods) {
- RepaymentPeriod currentPeriod = new RepaymentPeriod(previousPeriod, period.periodFromDate(), period.periodDueDate(),
- zeroAmount);
+ RepaymentPeriod currentPeriod = new RepaymentPeriod(previousPeriod, period.periodFromDate(), period.periodDueDate(), zeroAmount,
+ mc);
previousPeriod = currentPeriod;
interestRepaymentModelList.add(currentPeriod);
}
return new ProgressiveLoanInterestScheduleModel(interestRepaymentModelList, loanProductRelatedDetail,
- installmentAmountInMultiplesOf);
+ installmentAmountInMultiplesOf, mc);
}
@Override
@@ -85,7 +83,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
final Money disbursedAmount) {
scheduleModel
.changeOutstandingBalanceAndUpdateInterestPeriods(disbursementDueDate, disbursedAmount,
- Money.zero(disbursedAmount.getCurrency()))
+ Money.zero(disbursedAmount.getCurrency(), scheduleModel.mc()))
.ifPresent((repaymentPeriod) -> calculateEMIValueAndRateFactors(repaymentPeriod.getDueDate(), scheduleModel));
}
@@ -130,7 +128,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
@Override
public PayableDetails getPayableDetails(final ProgressiveLoanInterestScheduleModel scheduleModel,
final LocalDate repaymentPeriodDueDate, final LocalDate targetDate) {
- RepaymentPeriod repaymentPeriod = scheduleModel.deepCopy().repaymentPeriods().stream()
+ MathContext mc = scheduleModel.mc();
+ RepaymentPeriod repaymentPeriod = scheduleModel.deepCopy(mc).repaymentPeriods().stream()
.filter(rp -> rp.getDueDate().equals(repaymentPeriodDueDate)).findFirst().orElseThrow();
LocalDate adjustedTargetDate = targetDate;
InterestPeriod interestPeriod;
@@ -151,19 +150,19 @@ public final class ProgressiveEMICalculator implements EMICalculator {
// TODO: gather all the unrecognized interest from previous periods based on target date
Money payableInterest = targetDate.isBefore(repaymentPeriod.getFromDate())
- ? Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency())
+ ? Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc)
: repaymentPeriod.getDueInterest();
Money outstandingLoanBalance = interestPeriod.getOutstandingLoanBalance().add(interestPeriod.getDisbursementAmount());
- Money calculatedEmi = outstandingLoanBalance.plus(payableInterest);
+ Money calculatedEmi = outstandingLoanBalance.plus(payableInterest, mc);
if (calculatedEmi.isLessThan(repaymentPeriod.getEmi())) {
// Review this logic
- repaymentPeriod.setEmi(outstandingLoanBalance.plus(payableInterest).plus(repaymentPeriod.getPaidInterest())
- .plus(repaymentPeriod.getPaidPrincipal()));
+ repaymentPeriod.setEmi(outstandingLoanBalance.plus(payableInterest).plus(repaymentPeriod.getPaidInterest(), mc)
+ .plus(repaymentPeriod.getPaidPrincipal(), mc));
}
- Money payablePrincipal = repaymentPeriod.getEmi().minus(payableInterest);
+ Money payablePrincipal = repaymentPeriod.getEmi().minus(payableInterest, mc);
return new PayableDetails(repaymentPeriod.getEmi(), payablePrincipal, payableInterest,
- interestPeriod.getOutstandingLoanBalance().add(interestPeriod.getDisbursementAmount()));
+ interestPeriod.getOutstandingLoanBalance().add(interestPeriod.getDisbursementAmount(), mc));
}
@Override
@@ -189,18 +188,19 @@ public final class ProgressiveEMICalculator implements EMICalculator {
}
private void calculateLastUnpaidRepaymentPeriodEMI(ProgressiveLoanInterestScheduleModel scheduleModel) {
+ MathContext mc = scheduleModel.mc();
Money totalDueInterest = scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getDueInterest)
- .reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency()), Money::plus); // 1.46
+ .reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc), (m1, m2) -> m1.plus(m2, mc)); // 1.46
Money totalEMI = scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getEmi)
- .reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency()), Money::plus); // 101.48
+ .reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc), (m1, m2) -> m1.plus(m2, mc)); // 101.48
Money totalDisbursedAmount = scheduleModel.repaymentPeriods().stream()
.flatMap(rp -> rp.getInterestPeriods().stream().map(InterestPeriod::getDisbursementAmount))
- .reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency()), Money::plus); // 100
+ .reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc), (m1, m2) -> m1.plus(m2, mc)); // 100
- Money diff = totalDisbursedAmount.plus(totalDueInterest).minus(totalEMI);
+ Money diff = totalDisbursedAmount.plus(totalDueInterest, mc).minus(totalEMI, mc);
Optional<RepaymentPeriod> findLastUnpaidRepaymentPeriod = scheduleModel.repaymentPeriods().stream().filter(rp -> !rp.isFullyPaid())
.reduce((first, second) -> second);
- findLastUnpaidRepaymentPeriod.ifPresent(repaymentPeriod -> repaymentPeriod.setEmi(repaymentPeriod.getEmi().add(diff)));
+ findLastUnpaidRepaymentPeriod.ifPresent(repaymentPeriod -> repaymentPeriod.setEmi(repaymentPeriod.getEmi().add(diff, mc)));
}
private void calculateOutstandingBalance(ProgressiveLoanInterestScheduleModel scheduleModel) {
@@ -209,24 +209,26 @@ public final class ProgressiveEMICalculator implements EMICalculator {
private void checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(final ProgressiveLoanInterestScheduleModel scheduleModel,
final List<RepaymentPeriod> relatedRepaymentPeriods) {
+ MathContext mc = scheduleModel.mc();
final Money emiDifference = getDifferenceBetweenLastTwoPeriod(relatedRepaymentPeriods, scheduleModel);
final int numberOfRelatedPeriods = relatedRepaymentPeriods.size();
double lowerHalfOfRelatedPeriods = Math.floor(numberOfRelatedPeriods / 2.0);
- if (emiDifference.isZero() || lowerHalfOfRelatedPeriods == 0.0) {
+ if (emiDifference.isZero(mc) || lowerHalfOfRelatedPeriods == 0.0) {
return;
}
final Money originalEmi = relatedRepaymentPeriods.get(numberOfRelatedPeriods - 2).getEmi();
- boolean shouldBeAdjusted = emiDifference.abs().multipliedBy(100)
- .isGreaterThan(Money.of(originalEmi.getCurrency(), BigDecimal.valueOf(lowerHalfOfRelatedPeriods)));
+ boolean shouldBeAdjusted = emiDifference.abs(mc).multipliedBy(100, mc)
+ .isGreaterThan(Money.of(originalEmi.getCurrency(), BigDecimal.valueOf(lowerHalfOfRelatedPeriods), mc));
if (shouldBeAdjusted) {
- Money adjustment = emiDifference.dividedBy(numberOfRelatedPeriods, MoneyHelper.getMathContext().getRoundingMode());
- Money adjustedEqualMonthlyInstallmentValue = applyInstallmentAmountInMultiplesOf(scheduleModel, originalEmi.plus(adjustment));
+ Money adjustment = emiDifference.dividedBy(numberOfRelatedPeriods, mc.getRoundingMode(), mc);
+ Money adjustedEqualMonthlyInstallmentValue = applyInstallmentAmountInMultiplesOf(scheduleModel,
+ originalEmi.plus(adjustment, mc));
if (adjustedEqualMonthlyInstallmentValue.isEqualTo(originalEmi)) {
return;
}
final LocalDate relatedPeriodsFirstDueDate = relatedRepaymentPeriods.get(0).getDueDate();
- final ProgressiveLoanInterestScheduleModel newScheduleModel = scheduleModel.deepCopy();
+ final ProgressiveLoanInterestScheduleModel newScheduleModel = scheduleModel.deepCopy(mc);
newScheduleModel.repaymentPeriods().forEach(period -> {
if (!period.getDueDate().isBefore(relatedPeriodsFirstDueDate)) {
period.setEmi(adjustedEqualMonthlyInstallmentValue);
@@ -235,7 +237,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
calculateOutstandingBalance(newScheduleModel);
calculateLastUnpaidRepaymentPeriodEMI(newScheduleModel);
final Money newEmiDifference = getDifferenceBetweenLastTwoPeriod(newScheduleModel.repaymentPeriods(), scheduleModel);
- final boolean newEmiHasLessDifference = newEmiDifference.abs().isLessThan(emiDifference.abs());
+ final boolean newEmiHasLessDifference = newEmiDifference.abs(mc).isLessThan(emiDifference.abs(mc));
if (!newEmiHasLessDifference) {
return;
}
@@ -263,8 +265,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
*
* @return Rate Interest Rate in fraction format
*/
- BigDecimal calcNominalInterestRatePercentage(final BigDecimal interestRate) {
- return MathUtil.nullToZero(interestRate).divide(DIVISOR_100, MoneyHelper.getMathContext());
+ BigDecimal calcNominalInterestRatePercentage(final BigDecimal interestRate, MathContext mc) {
+ return MathUtil.nullToZero(interestRate).divide(DIVISOR_100, mc);
}
/**
@@ -286,8 +288,10 @@ public final class ProgressiveEMICalculator implements EMICalculator {
*/
BigDecimal calculateRateFactorPerPeriod(final RepaymentPeriod repaymentPeriod, final InterestPeriod interestPeriod,
final ProgressiveLoanInterestScheduleModel scheduleModel) {
+ final MathContext mc = scheduleModel.mc();
final LoanProductRelatedDetail loanProductRelatedDetail = scheduleModel.loanProductRelatedDetail();
- final BigDecimal interestRate = calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriod.getFromDate()));
+ final BigDecimal interestRate = calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriod.getFromDate()),
+ scheduleModel.mc());
final DaysInYearType daysInYearType = DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType());
final DaysInMonthType daysInMonthType = DaysInMonthType.fromInt(loanProductRelatedDetail.getDaysInMonthType());
final PeriodFrequencyType repaymentFrequency = loanProductRelatedDetail.getRepaymentPeriodFrequencyType();
@@ -306,13 +310,13 @@ public final class ProgressiveEMICalculator implements EMICalculator {
// TODO review: (repayment frequency: days, weeks, years; validation day is month fix 30)
// TODO refactor this logic to represent in interest period
if (partialPeriodCalculationNeeded) {
- final BigDecimal cumulatedPeriodFractions = calculatePeriodFractions(interestPeriod);
+ final BigDecimal cumulatedPeriodFractions = calculatePeriodFractions(interestPeriod, mc);
return rateFactorByRepaymentPartialPeriod(interestRate, repaymentEvery, cumulatedPeriodFractions, BigDecimal.ONE,
- BigDecimal.ONE);
+ BigDecimal.ONE, mc);
}
return calculateRateFactorPerPeriodBasedOnRepaymentFrequency(interestRate, repaymentFrequency, repaymentEvery, daysInMonth,
- daysInYear, actualDaysInPeriod, calculatedDaysInPeriod);
+ daysInYear, actualDaysInPeriod, calculatedDaysInPeriod, mc);
}
/**
@@ -321,7 +325,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
* @param interestPeriod
* @return
*/
- BigDecimal calculatePeriodFractions(InterestPeriod interestPeriod) {
+ BigDecimal calculatePeriodFractions(InterestPeriod interestPeriod, MathContext mc) {
BigDecimal cumulatedRateFactor = BigDecimal.ZERO;
int actualYear = interestPeriod.getFromDate().getYear();
int endYear = interestPeriod.getDueDate().getYear();
@@ -332,8 +336,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
endOfActualYear = actualYear == endYear ? interestPeriod.getDueDate() : LocalDate.of(actualYear, 12, 31);
BigDecimal numberOfDaysInYear = BigDecimal.valueOf(Year.of(actualYear).length());
BigDecimal calculatedDaysInActualYear = BigDecimal.valueOf(DateUtils.getDifferenceInDays(actualDate, endOfActualYear));
- cumulatedRateFactor = cumulatedRateFactor
- .add(calculatedDaysInActualYear.divide(numberOfDaysInYear, MoneyHelper.getMathContext()), MoneyHelper.getMathContext());
+ cumulatedRateFactor = cumulatedRateFactor.add(calculatedDaysInActualYear.divide(numberOfDaysInYear, mc), mc);
actualDate = endOfActualYear;
actualYear++;
}
@@ -354,14 +357,15 @@ public final class ProgressiveEMICalculator implements EMICalculator {
*/
BigDecimal calculateRateFactorPerPeriodBasedOnRepaymentFrequency(final BigDecimal interestRate,
final PeriodFrequencyType repaymentFrequency, final BigDecimal repaymentEvery, final BigDecimal daysInMonth,
- final BigDecimal daysInYear, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod) {
+ final BigDecimal daysInYear, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod,
+ final MathContext mc) {
return switch (repaymentFrequency) {
case DAYS ->
- rateFactorByRepaymentEveryDay(interestRate, repaymentEvery, daysInYear, actualDaysInPeriod, calculatedDaysInPeriod);
+ rateFactorByRepaymentEveryDay(interestRate, repaymentEvery, daysInYear, actualDaysInPeriod, calculatedDaysInPeriod, mc);
case WEEKS ->
- rateFactorByRepaymentEveryWeek(interestRate, repaymentEvery, daysInYear, actualDaysInPeriod, calculatedDaysInPeriod);
+ rateFactorByRepaymentEveryWeek(interestRate, repaymentEvery, daysInYear, actualDaysInPeriod, calculatedDaysInPeriod, mc);
case MONTHS -> rateFactorByRepaymentEveryMonth(interestRate, repaymentEvery, daysInMonth, daysInYear, actualDaysInPeriod,
- calculatedDaysInPeriod);
+ calculatedDaysInPeriod, mc);
default -> throw new UnsupportedOperationException("Invalid repayment frequency"); // not supported yet
};
}
@@ -370,14 +374,15 @@ public final class ProgressiveEMICalculator implements EMICalculator {
if (repaymentPeriods.isEmpty()) {
return;
}
- final BigDecimal rateFactorN = MathUtil.stripTrailingZeros(calculateRateFactorPlus1N(repaymentPeriods));
- final BigDecimal fnResult = MathUtil.stripTrailingZeros(calculateFnResult(repaymentPeriods));
+ final MathContext mc = scheduleModel.mc();
+ final BigDecimal rateFactorN = MathUtil.stripTrailingZeros(calculateRateFactorPlus1N(repaymentPeriods, mc));
+ final BigDecimal fnResult = MathUtil.stripTrailingZeros(calculateFnResult(repaymentPeriods, mc));
final RepaymentPeriod startPeriod = repaymentPeriods.get(0);
// TODO: double check
final Money outstandingBalance = startPeriod.getInitialBalanceForEmiRecalculation();
final Money equalMonthlyInstallment = Money.of(outstandingBalance.getCurrency(),
- calculateEMIValue(rateFactorN, outstandingBalance.getAmount(), fnResult));
+ calculateEMIValue(rateFactorN, outstandingBalance.getAmount(), fnResult, mc), mc);
final Money finalEqualMonthlyInstallment = applyInstallmentAmountInMultiplesOf(scheduleModel, equalMonthlyInstallment);
repaymentPeriods.forEach(period -> period.setEmi(finalEqualMonthlyInstallment));
@@ -392,39 +397,40 @@ public final class ProgressiveEMICalculator implements EMICalculator {
Money getDifferenceBetweenLastTwoPeriod(final List<RepaymentPeriod> repaymentPeriods,
final ProgressiveLoanInterestScheduleModel scheduleModel) {
+ MathContext mc = scheduleModel.mc();
int numberOfUpcomingPeriods = repaymentPeriods.size();
if (numberOfUpcomingPeriods < 2) {
- return Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency());
+ return Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc);
}
final RepaymentPeriod lastPeriod = repaymentPeriods.get(numberOfUpcomingPeriods - 1);
final RepaymentPeriod penultimatePeriod = repaymentPeriods.get(numberOfUpcomingPeriods - 2);
- return lastPeriod.getEmi().minus(penultimatePeriod.getEmi());
+ return lastPeriod.getEmi().minus(penultimatePeriod.getEmi(), mc);
}
/**
* Calculate Rate Factor Product from rate factors
*/
- BigDecimal calculateRateFactorPlus1N(final List<RepaymentPeriod> periods) {
+ BigDecimal calculateRateFactorPlus1N(final List<RepaymentPeriod> periods, MathContext mc) {
return periods.stream().map(RepaymentPeriod::getRateFactorPlus1).reduce(BigDecimal.ONE,
- (BigDecimal acc, BigDecimal value) -> acc.multiply(value, MoneyHelper.getMathContext()));
+ (BigDecimal acc, BigDecimal value) -> acc.multiply(value, mc));
}
/**
* Summarize Fn values
*/
- BigDecimal calculateFnResult(final List<RepaymentPeriod> periods) {
+ BigDecimal calculateFnResult(final List<RepaymentPeriod> periods, final MathContext mc) {
return periods.stream()//
.skip(1)//
.map(RepaymentPeriod::getRateFactorPlus1)//
- .reduce(BigDecimal.ONE, this::fnValue);//
+ .reduce(BigDecimal.ONE, (previousFnValue, currentRateFactor) -> fnValue(previousFnValue, currentRateFactor, mc));//
}
/**
* Calculate the EMI (Equal Monthly Installment) value
*/
- BigDecimal calculateEMIValue(final BigDecimal rateFactorPlus1N, final BigDecimal outstandingBalanceForRest, final BigDecimal fnResult) {
- return rateFactorPlus1N.multiply(outstandingBalanceForRest, MoneyHelper.getMathContext()).divide(fnResult,
- MoneyHelper.getMathContext());
+ BigDecimal calculateEMIValue(final BigDecimal rateFactorPlus1N, final BigDecimal outstandingBalanceForRest, final BigDecimal fnResult,
+ MathContext mc) {
+ return rateFactorPlus1N.multiply(outstandingBalanceForRest, mc).divide(fnResult, mc);
}
/**
@@ -452,9 +458,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
* @return Rate Factor for period
*/
BigDecimal rateFactorByRepaymentEveryDay(final BigDecimal interestRate, final BigDecimal repaymentEvery, final BigDecimal daysInYear,
- final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod) {
+ final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod, MathContext mc) {
return rateFactorByRepaymentPeriod(interestRate, BigDecimal.ONE, repaymentEvery, daysInYear, actualDaysInPeriod,
- calculatedDaysInPeriod);
+ calculatedDaysInPeriod, mc);
}
/**
@@ -482,9 +488,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
* @return Rate Factor for period
*/
BigDecimal rateFactorByRepaymentEveryWeek(final BigDecimal interestRate, final BigDecimal repaymentEvery, final BigDecimal daysInYear,
- final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod) {
+ final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod, MathContext mc) {
return rateFactorByRepaymentPeriod(interestRate, ONE_WEEK_IN_DAYS, repaymentEvery, daysInYear, actualDaysInPeriod,
- calculatedDaysInPeriod);
+ calculatedDaysInPeriod, mc);
}
/**
@@ -515,9 +521,10 @@ public final class ProgressiveEMICalculator implements EMICalculator {
* @return Rate Factor for period
*/
BigDecimal rateFactorByRepaymentEveryMonth(final BigDecimal interestRate, final BigDecimal repaymentEvery, final BigDecimal daysInMonth,
- final BigDecimal daysInYear, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod) {
+ final BigDecimal daysInYear, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod,
+ final MathContext mc) {
return rateFactorByRepaymentPeriod(interestRate, daysInMonth, repaymentEvery, daysInYear, actualDaysInPeriod,
- calculatedDaysInPeriod);
+ calculatedDaysInPeriod, mc);
}
/**
@@ -549,14 +556,14 @@ public final class ProgressiveEMICalculator implements EMICalculator {
*/
BigDecimal rateFactorByRepaymentPeriod(final BigDecimal interestRate, final BigDecimal repaymentPeriodMultiplierInDays,
final BigDecimal repaymentEvery, final BigDecimal daysInYear, final BigDecimal actualDaysInPeriod,
- final BigDecimal calculatedDaysInPeriod) {
+ final BigDecimal calculatedDaysInPeriod, final MathContext mc) {
final BigDecimal interestFractionPerPeriod = repaymentPeriodMultiplierInDays//
- .multiply(repaymentEvery, MoneyHelper.getMathContext())//
- .divide(daysInYear, MoneyHelper.getMathContext());//
+ .multiply(repaymentEvery, mc)//
+ .divide(daysInYear, mc);//
return interestRate//
- .multiply(interestFractionPerPeriod, MoneyHelper.getMathContext())//
- .multiply(actualDaysInPeriod, MoneyHelper.getMathContext())//
- .divide(calculatedDaysInPeriod, MoneyHelper.getMathContext());//
+ .multiply(interestFractionPerPeriod, mc)//
+ .multiply(actualDaysInPeriod, mc)//
+ .divide(calculatedDaysInPeriod, mc);//
}
/**
@@ -564,12 +571,13 @@ public final class ProgressiveEMICalculator implements EMICalculator {
*
*/
BigDecimal rateFactorByRepaymentPartialPeriod(final BigDecimal interestRate, final BigDecimal repaymentEvery,
- final BigDecimal cumulatedPeriodRatio, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod) {
+ final BigDecimal cumulatedPeriodRatio, final BigDecimal actualDaysInPeriod, final BigDecimal calculatedDaysInPeriod,
+ final MathContext mc) {
final BigDecimal interestFractionPerPeriod = repaymentEvery.multiply(cumulatedPeriodRatio);
return interestRate//
- .multiply(interestFractionPerPeriod, MoneyHelper.getMathContext())//
- .multiply(actualDaysInPeriod, MoneyHelper.getMathContext())//
- .divide(calculatedDaysInPeriod, MoneyHelper.getMathContext());//
+ .multiply(interestFractionPerPeriod, mc)//
+ .multiply(actualDaysInPeriod, mc)//
+ .divide(calculatedDaysInPeriod, mc);//
}
/**
@@ -582,13 +590,13 @@ public final class ProgressiveEMICalculator implements EMICalculator {
* @param currentRateFactor
*
*/
- BigDecimal fnValue(final BigDecimal previousFnValue, final BigDecimal currentRateFactor) {
- return BigDecimal.ONE.add(previousFnValue.multiply(currentRateFactor, MoneyHelper.getMathContext()), MoneyHelper.getMathContext());
+ BigDecimal fnValue(final BigDecimal previousFnValue, final BigDecimal currentRateFactor, final MathContext mc) {
+ return BigDecimal.ONE.add(previousFnValue.multiply(currentRateFactor, mc), mc);
}
@Override
public ProgressiveLoanInterestScheduleModel generateModel(LoanProductRelatedDetail loanProductRelatedDetail,
- Integer installmentAmountInMultiplesOf, List<LoanRepaymentScheduleInstallment> repaymentPeriods) {
+ Integer installmentAmountInMultiplesOf, List<LoanRepaymentScheduleInstallment> repaymentPeriods, MathContext mc) {
List<LoanRepaymentScheduleInstallment> repaymentModelsWithoutDownPayment = repaymentPeriods.stream()
.filter(period -> !period.isDownPayment() && !period.isAdditional()).toList();
@@ -596,11 +604,11 @@ public final class ProgressiveEMICalculator implements EMICalculator {
RepaymentPeriod previousPeriod = null;
for (LoanRepaymentScheduleInstallment repaymentModel : repaymentModelsWithoutDownPayment) {
RepaymentPeriod currentPeriod = new RepaymentPeriod(previousPeriod, repaymentModel.getFromDate(), repaymentModel.getDueDate(),
- Money.zero(repaymentModel.getLoan().getCurrency()));
+ Money.zero(repaymentModel.getLoan().getCurrency(), mc), mc);
previousPeriod = currentPeriod;
repaymentModels.add(currentPeriod);
}
- return new ProgressiveLoanInterestScheduleModel(repaymentModels, loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ return new ProgressiveLoanInterestScheduleModel(repaymentModels, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
}
}
diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java
index ffef3502a..d1f9de0e0 100644
--- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java
+++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
@@ -90,11 +91,12 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
private static final MonetaryCurrency MONETARY_CURRENCY = new MonetaryCurrency("USD", 2, 1);
private static final MockedStatic<MoneyHelper> MONEY_HELPER = mockStatic(MoneyHelper.class);
private AdvancedPaymentScheduleTransactionProcessor underTest;
- private final EMICalculator emiCalculator = Mockito.mock(EMICalculator.class);
+ private static final EMICalculator emiCalculator = Mockito.mock(EMICalculator.class);
@BeforeAll
public static void init() {
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
}
@AfterAll
diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
index b0015c29c..c5b7f65d1 100644
--- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
+++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
@@ -20,77 +20,36 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
-import java.util.ArrayList;
import java.util.List;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
-import org.apache.fineract.organisation.monetary.domain.Money;
-import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
import org.apache.fineract.portfolio.loanproduct.calc.ProgressiveEMICalculator;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.MockedStatic;
-import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class LoanScheduleGeneratorTest {
private static final ProgressiveEMICalculator emiCalculator = new ProgressiveEMICalculator();
- private static MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
private static final ApplicationCurrency APPLICATION_CURRENCY = new ApplicationCurrency("USD", "USD", 2, 1, "USD", "$");
- private static final MonetaryCurrency MONETARY_CURRENCY = MonetaryCurrency.fromApplicationCurrency(APPLICATION_CURRENCY);
private static final BigDecimal DISBURSEMENT_AMOUNT = BigDecimal.valueOf(192.22);
private static final BigDecimal NOMINAL_INTEREST_RATE = BigDecimal.valueOf(9.99);
private static final int NUMBER_OF_REPAYMENTS = 6;
private static final int REPAYMENT_FREQUENCY = 1;
private static final String REPAYMENT_FREQUENCY_TYPE = "MONTHS";
private static final LocalDate DISBURSEMENT_DATE = LocalDate.of(2024, 1, 15);
-
- @BeforeAll
- public static void init() {
- moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
- moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
- }
-
- @AfterAll
- public static void destruct() {
- moneyHelper.close();
- }
+ private static final MathContext mc = new MathContext(12, RoundingMode.HALF_EVEN);
@Test
void testGenerateLoanSchedule() {
- LoanRepaymentScheduleModelData modelData = new LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), APPLICATION_CURRENCY,
- DISBURSEMENT_AMOUNT, DISBURSEMENT_DATE, NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
- NOMINAL_INTEREST_RATE, true, DaysInMonthType.DAYS_30, DaysInYearType.DAYS_360, null, null, null);
-
- final MathContext mc = MoneyHelper.getMathContext();
- final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods = new ArrayList<>();
-
- expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1)));
- expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1)));
- expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)));
- expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)));
- expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)));
- expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1)));
-
- ScheduledDateGenerator mockScheduledDateGenerator = Mockito.mock(ScheduledDateGenerator.class);
- ProgressiveLoanScheduleGenerator generator = new ProgressiveLoanScheduleGenerator(mockScheduledDateGenerator, emiCalculator);
- when(mockScheduledDateGenerator.generateRepaymentPeriods(any(), any(), any())).thenReturn(expectedRepaymentPeriods);
-
- LoanScheduleModel loanSchedule = generator.generate(mc, modelData);
- List<LoanScheduleModelPeriod> periods = loanSchedule.getPeriods();
+ List<LoanScheduleModelPeriod> periods = getLoanScheduleModelPeriods();
assertEquals(7, periods.size(), "Expected 7 periods including the downpayment period.");
@@ -111,6 +70,18 @@ class LoanScheduleGeneratorTest {
BigDecimal.valueOf(0.27), BigDecimal.valueOf(32.87), BigDecimal.ZERO);
}
+ private static List<LoanScheduleModelPeriod> getLoanScheduleModelPeriods() {
+ LoanRepaymentScheduleModelData modelData = new LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), APPLICATION_CURRENCY,
+ DISBURSEMENT_AMOUNT, DISBURSEMENT_DATE, NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
+ NOMINAL_INTEREST_RATE, true, DaysInMonthType.DAYS_30, DaysInYearType.DAYS_360, null, null, null);
+
+ ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
+ ProgressiveLoanScheduleGenerator generator = new ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator);
+
+ LoanScheduleModel loanSchedule = generator.generate(mc, modelData);
+ return loanSchedule.getPeriods();
+ }
+
private void checkPeriod(LoanScheduleModelPeriod period, int expectedPeriodNumber, LocalDate expectedFromDate,
LocalDate expectedDueDate, BigDecimal expectedPrincipalDue, BigDecimal expectedInterestDue, BigDecimal expectedTotalDue,
BigDecimal expectedOutstandingLoanBalance) {
@@ -123,10 +94,4 @@ class LoanScheduleGeneratorTest {
assertEquals(0, expectedTotalDue.compareTo(repaymentPeriod.getTotalDue().getAmount()));
assertEquals(0, expectedOutstandingLoanBalance.compareTo(repaymentPeriod.getOutstandingLoanBalance().getAmount()));
}
-
- private static LoanScheduleModelRepaymentPeriod repayment(int periodNumber, LocalDate fromDate, LocalDate dueDate) {
- final Money zeroAmount = Money.zero(MONETARY_CURRENCY);
- return LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, dueDate, zeroAmount, zeroAmount, zeroAmount, zeroAmount,
- zeroAmount, zeroAmount, false);
- }
}
diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java
index 1f7b6cb87..1137b2e68 100644
--- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java
+++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java
@@ -59,6 +59,7 @@ class ProgressiveEMICalculatorTest {
private static MockedStatic<ThreadLocalContextUtil> threadLocalContextUtil = Mockito.mockStatic(ThreadLocalContextUtil.class);
private static MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
+ private static MathContext mc = new MathContext(12, RoundingMode.HALF_EVEN);
private static LoanProductRelatedDetail loanProductRelatedDetail = Mockito.mock(LoanProductRelatedDetail.class);
private static final MonetaryCurrency monetaryCurrency = MonetaryCurrency
@@ -95,7 +96,7 @@ class ProgressiveEMICalculatorTest {
final BigDecimal daysInYear = BigDecimal.valueOf(daysInYearType.getNumberOfDays(period.getFromDate()));
final BigDecimal daysInMonth = BigDecimal.valueOf(daysInMonthType.getNumberOfDays(period.getFromDate()));
final BigDecimal rateFactor = emiCalculator.rateFactorByRepaymentEveryMonth(interestRate, BigDecimal.ONE, daysInMonth, daysInYear,
- daysInPeriod, daysInPeriod);
+ daysInPeriod, daysInPeriod, mc);
return rateFactor.setScale(12, MoneyHelper.getRoundingMode());
}
@@ -145,7 +146,7 @@ class ProgressiveEMICalculatorTest {
BigDecimal rateFactorPlus1 = getRateFactorsByMonth(daysInYearType, daysInMonthType, interestRate, period).add(BigDecimal.ONE,
MoneyHelper.getMathContext());
- final BigDecimal currentFnValue = emiCalculator.fnValue(previousFnValue, rateFactorPlus1);
+ final BigDecimal currentFnValue = emiCalculator.fnValue(previousFnValue, rateFactorPlus1, mc);
fnValuesCalculated.add(currentFnValue);
previousFnValue = currentFnValue;
@@ -171,7 +172,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator
- .generateInterestScheduleModel(expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ .generateInterestScheduleModel(expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
Assertions.assertTrue(interestScheduleModel != null);
Assertions.assertTrue(interestScheduleModel.loanProductRelatedDetail() != null);
@@ -211,7 +212,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = toMoney(100.0);
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -256,7 +257,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = toMoney(100.0);
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -293,7 +294,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -330,7 +331,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -370,7 +371,7 @@ class ProgressiveEMICalculatorTest {
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -414,7 +415,7 @@ class ProgressiveEMICalculatorTest {
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -460,7 +461,7 @@ class ProgressiveEMICalculatorTest {
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -577,7 +578,7 @@ class ProgressiveEMICalculatorTest {
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -661,7 +662,7 @@ class ProgressiveEMICalculatorTest {
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = toMoney(100.0);
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -739,7 +740,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -788,7 +789,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -837,7 +838,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 5), disbursedAmount);
@@ -881,7 +882,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2023, 12, 12), disbursedAmount);
@@ -915,7 +916,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(1000));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -948,7 +949,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -981,7 +982,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -1014,7 +1015,7 @@ class ProgressiveEMICalculatorTest {
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generateInterestScheduleModel(expectedRepaymentPeriods,
- loanProductRelatedDetail, installmentAmountInMultiplesOf);
+ loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
final Money disbursedAmount = Money.of(monetaryCurrency, BigDecimal.valueOf(100));
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
@@ -1031,7 +1032,7 @@ class ProgressiveEMICalculatorTest {
private static LoanScheduleModelRepaymentPeriod repayment(int periodNumber, LocalDate fromDate, LocalDate dueDate) {
final Money zeroAmount = Money.zero(monetaryCurrency);
return LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, dueDate, zeroAmount, zeroAmount, zeroAmount, zeroAmount,
- zeroAmount, zeroAmount, false);
+ zeroAmount, zeroAmount, false, mc);
}
@NotNull
diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java
index 345e23c33..b3aad08fb 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
@@ -88,6 +89,7 @@ public class CheckLoanRepaymentOverdueBusinessStepTest {
@BeforeAll
public static void init() {
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
index 3abad3fe7..6299535e9 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
@@ -116,8 +117,12 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
@Mock
private AvroDateTimeMapper mapper;
+ private MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
+
@BeforeEach
public void setUp() {
+ moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
+ moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
ThreadLocalContextUtil
@@ -127,6 +132,7 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
@AfterEach
public void tearDown() {
ThreadLocalContextUtil.reset();
+ moneyHelper.close();
}
@Test
@@ -141,7 +147,6 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
LoanAccountData loanAccountData = mock(LoanAccountData.class);
CollectionData delinquentData = mock(CollectionData.class);
MonetaryCurrency loanCurrency = new MonetaryCurrency("CODE", 1, 1);
- MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
String delinquentDateAsStr = "2022-12-01";
LocalDate delinquentDate = LocalDate.parse(delinquentDateAsStr);
@@ -168,8 +173,6 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
when(loanChargeReadPlatformService.retrieveLoanCharges(anyLong())).thenAnswer(a -> repaymentScheduleInstallments.get(0)
.getInstallmentCharges().stream().map(c -> c.getLoanCharge().toData()).collect(Collectors.toList()));
- moneyHelper.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
-
// when
LoanAccountDelinquencyRangeDataV1 data = (LoanAccountDelinquencyRangeDataV1) serializer.toAvroDTO(event);
@@ -190,8 +193,6 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
assertEquals(0, data.getAmount().getFeeAmount().compareTo(new BigDecimal("5.0")));
assertEquals(0, data.getAmount().getPenaltyAmount().compareTo(new BigDecimal("50.0")));
assertEquals(delinquentDateAsStr, data.getDelinquentDate());
-
- moneyHelper.close();
}
@Test
@@ -206,7 +207,6 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
LoanAccountData loanAccountData = mock(LoanAccountData.class);
CollectionData delinquentData = mock(CollectionData.class);
MonetaryCurrency loanCurrency = new MonetaryCurrency("CODE", 1, 1);
- MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
String delinquentDateAsStr = "2022-12-01";
LocalDate delinquentDate = LocalDate.parse(delinquentDateAsStr);
when(loanForProcessing.getId()).thenReturn(1L);
@@ -263,8 +263,6 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
when(loanForProcessing.getLoanCharges()).thenAnswer(a -> repaymentScheduleInstallments.get(0).getInstallmentCharges().stream()
.map(c -> c.getLoanCharge()).collect(Collectors.toList()));
- moneyHelper.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
-
// when
LoanAccountDelinquencyRangeDataV1 data = (LoanAccountDelinquencyRangeDataV1) serializer.toAvroDTO(event);
@@ -314,7 +312,6 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
assertEquals(0, installmentDelinquencyBucketDataV1_2.getAmount().getFeeAmount().compareTo(new BigDecimal("0.0")));
assertEquals(0, installmentDelinquencyBucketDataV1_2.getAmount().getPenaltyAmount().compareTo(new BigDecimal("0.0")));
assertEquals(0, installmentDelinquencyBucketDataV1_2.getCharges().size());
- moneyHelper.close();
}
@Test
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java
index 3728a6bd9..3ea0da970 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
@@ -85,7 +86,8 @@ public class LoanRepaymentBusinessEventSerializerTest {
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
ThreadLocalContextUtil
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
- moneyHelper.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
+ moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
+ moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
}
@AfterEach
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java
index e4da2691a..037120297 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java
@@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
@@ -104,7 +105,8 @@ public class LoanDelinquencyDomainServiceTest {
currency = new MonetaryCurrency("USD", 2, null);
moneyHelperStatic = Mockito.mockStatic(MoneyHelper.class);
- moneyHelperStatic.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
+ moneyHelperStatic.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
+ moneyHelperStatic.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
}
@AfterEach
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java
index 98034716f..a93177cde 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachineTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanStatusChangedBusinessEvent;
@@ -55,7 +56,8 @@ class DefaultLoanLifecycleStateMachineTest {
public void setUp() {
moneyHelperStatic = Mockito.mockStatic(MoneyHelper.class);
- moneyHelperStatic.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
+ moneyHelperStatic.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
+ moneyHelperStatic.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
underTest = new DefaultLoanLifecycleStateMachine(businessEventNotifierService);
}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java
index 19213fdf1..38f5369ef 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorTest.java
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.refEq;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashMap;
@@ -87,6 +88,7 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
@BeforeAll
public static void init() {
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java
index b566bb29d..6567ae6c5 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorTest.java
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.refEq;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashMap;
@@ -88,6 +89,7 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
@BeforeAll
public static void init() {
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.HALF_EVEN));
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
index 3dc81175d..4a212eee5 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGeneratorTest.java
@@ -37,6 +37,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
@@ -82,6 +84,7 @@ public class DefaultScheduledDateGeneratorTest {
public void test_generateRepaymentPeriods() {
// given
HolidayDetailDTO holidayDetailDTO = createHolidayDTO();
+ MathContext mathContext = new MathContext(12, RoundingMode.HALF_EVEN);
ApplicationCurrency dollarCurrency = new ApplicationCurrency("USD", "US Dollar", 2, 0, "currency.USD", "$");
Money principalAmount = Money.of(fromApplicationCurrency(dollarCurrency), BigDecimal.valueOf(100));
@@ -98,8 +101,8 @@ public class DefaultScheduledDateGeneratorTest {
submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null);
// when
- List<? extends LoanScheduleModelPeriod> result = underTest.generateRepaymentPeriods(expectedDisbursementDate, loanApplicationTerms,
- holidayDetailDTO);
+ List<? extends LoanScheduleModelPeriod> result = underTest.generateRepaymentPeriods(mathContext, expectedDisbursementDate,
+ loanApplicationTerms, holidayDetailDTO);
// then
assertThat(result.size()).isEqualTo(4);
diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java
index def517ca9..599382e15 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/LoanCalculateRepaymentPastDueServiceTest.java
@@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
+import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
@@ -64,7 +65,8 @@ public class LoanCalculateRepaymentPastDueServiceTest {
ThreadLocalContextUtil
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
underTest = new LoanCalculateRepaymentPastDueService();
- moneyHelper.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
+ moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
+ moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
}
@AfterEach
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 0bfa16ad2..5670c7869 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
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.math.MathContext;
import java.math.RoundingMode;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBalanceChangedBusinessEvent;
@@ -75,7 +76,8 @@ public class LoanDownPaymentHandlerServiceImplTest {
@BeforeEach
public void setUp() {
underTest = new LoanDownPaymentHandlerServiceImpl(loanTransactionRepository, businessEventNotifierService);
- moneyHelper.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP);
+ moneyHelper.when(MoneyHelper::getMathContext).thenReturn(new MathContext(12, RoundingMode.UP));
+ moneyHelper.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.UP);
}
@AfterEach