FINERACT-1981: Embeddable Progressive Loan Schedule generator
This commit is contained in:
committed by
Adam Saghy
parent
d0006a2169
commit
bb8480a03d
@@ -0,0 +1,51 @@
|
|||||||
|
name: Fineract Build Progressive Loan Embeddable Jar & Test with a Sample Application
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up JDK 17
|
||||||
|
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'zulu'
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@cc4fc85e6b35bafd578d5ffbc76a5518407e1af0 # v4.2.1
|
||||||
|
- name: Build Embeddable Jar
|
||||||
|
run: ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:shadowJar
|
||||||
|
- name: Pick up the JAR filename
|
||||||
|
run: |
|
||||||
|
EMBEDDABLE_JAR_FILE=(`ls fineract-progressive-loan-embeddable-schedule-generator/build/libs/*-all.jar | head -n 1`)
|
||||||
|
echo "EMBEDDABLE_JAR_FILE=$EMBEDDABLE_JAR_FILE" >> $GITHUB_ENV
|
||||||
|
- name: Build Sample Application
|
||||||
|
run: |
|
||||||
|
mkdir sample-app
|
||||||
|
javac -cp $EMBEDDABLE_JAR_FILE -d sample-app fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
|
||||||
|
env:
|
||||||
|
EMBEDDABLE_JAR_FILE: ${{ env.EMBEDDABLE_JAR_FILE }}
|
||||||
|
|
||||||
|
- name: Run Schedule Generator Sample Application
|
||||||
|
run: |
|
||||||
|
java -cp $EMBEDDABLE_JAR_FILE:sample-app Main
|
||||||
|
java -cp $EMBEDDABLE_JAR_FILE:sample-app Main 25
|
||||||
|
env:
|
||||||
|
EMBEDDABLE_JAR_FILE: ${{ env.EMBEDDABLE_JAR_FILE }}
|
||||||
|
|
||||||
|
- name: Archive test results
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
|
||||||
|
with:
|
||||||
|
name: test-results
|
||||||
|
path: |
|
||||||
|
build/reports/
|
||||||
|
fineract-progressive-loan-embeddable-schedule-generator/build/reports/
|
||||||
+6
-3
@@ -46,7 +46,8 @@ buildscript {
|
|||||||
'fineract-avro-schemas',
|
'fineract-avro-schemas',
|
||||||
'fineract-e2e-tests-core',
|
'fineract-e2e-tests-core',
|
||||||
'fineract-e2e-tests-runner',
|
'fineract-e2e-tests-runner',
|
||||||
'fineract-progressive-loan'
|
'fineract-progressive-loan',
|
||||||
|
'fineract-progressive-loan-embeddable-schedule-generator'
|
||||||
].contains(it.name)
|
].contains(it.name)
|
||||||
}
|
}
|
||||||
fineractPublishProjects = subprojects.findAll{
|
fineractPublishProjects = subprojects.findAll{
|
||||||
@@ -66,7 +67,8 @@ buildscript {
|
|||||||
'fineract-report',
|
'fineract-report',
|
||||||
'fineract-branch',
|
'fineract-branch',
|
||||||
'fineract-document',
|
'fineract-document',
|
||||||
'fineract-progressive-loan'
|
'fineract-progressive-loan',
|
||||||
|
'fineract-progressive-loan-embeddable-schedule-generator'
|
||||||
].contains(it.name)
|
].contains(it.name)
|
||||||
}
|
}
|
||||||
npmRepository = 'https://npm.pkg.github.com'
|
npmRepository = 'https://npm.pkg.github.com'
|
||||||
@@ -109,6 +111,7 @@ plugins {
|
|||||||
id 'se.thinkcode.cucumber-runner' version '0.0.11' apply false
|
id 'se.thinkcode.cucumber-runner' version '0.0.11' apply false
|
||||||
id "com.github.davidmc24.gradle.plugin.avro-base" version "1.9.1" apply false
|
id "com.github.davidmc24.gradle.plugin.avro-base" version "1.9.1" apply false
|
||||||
id 'org.openapi.generator' version '7.8.0' apply false
|
id 'org.openapi.generator' version '7.8.0' apply false
|
||||||
|
id 'com.gradleup.shadow' version '8.3.5' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.release.gradle"
|
apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.release.gradle"
|
||||||
@@ -169,7 +172,7 @@ allprojects {
|
|||||||
|
|
||||||
groovyGradle {
|
groovyGradle {
|
||||||
target '*.gradle', '**/*.gradle'
|
target '*.gradle', '**/*.gradle'
|
||||||
targetExclude '**/build/**'
|
targetExclude '**/build/**', '/**/build.gradle' // TODO: temporary disabled on build.gradle until someone fix this issue: https://github.com/diffplug/spotless/issues/1807
|
||||||
greclipse()
|
greclipse()
|
||||||
indentWithSpaces(4)
|
indentWithSpaces(4)
|
||||||
endWithNewline()
|
endWithNewline()
|
||||||
|
|||||||
+2
-2
@@ -365,12 +365,12 @@ public final class MathUtil {
|
|||||||
|
|
||||||
/** @return parameter value or ZERO if it is negative */
|
/** @return parameter value or ZERO if it is negative */
|
||||||
public static Money negativeToZero(Money value) {
|
public static Money negativeToZero(Money value) {
|
||||||
return value == null || isGreaterThanZero(value) ? value : Money.zero(value.getCurrency());
|
return value == null || isGreaterThanZero(value) ? value : Money.zero(value.getCurrencyData());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return parameter value or ZERO if it is negative */
|
/** @return parameter value or ZERO if it is negative */
|
||||||
public static Money negativeToZero(Money value, MathContext mc) {
|
public static Money negativeToZero(Money value, MathContext mc) {
|
||||||
return value == null || isGreaterThanZero(value, mc) ? value : Money.zero(value.getCurrency(), mc);
|
return value == null || isGreaterThanZero(value, mc) ? value : Money.zero(value.getCurrencyData(), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEmpty(Money value) {
|
public static boolean isEmpty(Money value) {
|
||||||
|
|||||||
-4
@@ -98,10 +98,6 @@ public class ApplicationCurrency extends AbstractPersistableCustom<Long> {
|
|||||||
return new CurrencyData(this.code, this.name, this.decimalPlaces, this.inMultiplesOf, this.displaySymbol, this.nameCode);
|
return new CurrencyData(this.code, this.name, this.decimalPlaces, this.inMultiplesOf, this.displaySymbol, this.nameCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CurrencyData toData(final int digitsAfterDecimalSupported, final Integer inMultiplesOf) {
|
|
||||||
return new CurrencyData(this.code, this.name, digitsAfterDecimalSupported, inMultiplesOf, this.displaySymbol, this.nameCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrganisationCurrency toOrganisationCurrency() {
|
public OrganisationCurrency toOrganisationCurrency() {
|
||||||
return new OrganisationCurrency(this.code, this.name, this.decimalPlaces, this.inMultiplesOf, this.nameCode, this.displaySymbol);
|
return new OrganisationCurrency(this.code, this.name, this.decimalPlaces, this.inMultiplesOf, this.nameCode, this.displaySymbol);
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-1
@@ -34,6 +34,8 @@ public class MonetaryCurrency {
|
|||||||
@Column(name = "currency_multiplesof")
|
@Column(name = "currency_multiplesof")
|
||||||
private Integer inMultiplesOf;
|
private Integer inMultiplesOf;
|
||||||
|
|
||||||
|
private transient CurrencyData currencyData;
|
||||||
|
|
||||||
protected MonetaryCurrency() {
|
protected MonetaryCurrency() {
|
||||||
this.code = null;
|
this.code = null;
|
||||||
this.digitsAfterDecimal = 0;
|
this.digitsAfterDecimal = 0;
|
||||||
@@ -46,6 +48,13 @@ public class MonetaryCurrency {
|
|||||||
this.inMultiplesOf = inMultiplesOf;
|
this.inMultiplesOf = inMultiplesOf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MonetaryCurrency(final CurrencyData currencyData) {
|
||||||
|
this.currencyData = currencyData;
|
||||||
|
this.code = currencyData.getCode();
|
||||||
|
this.digitsAfterDecimal = currencyData.getDecimalPlaces();
|
||||||
|
this.inMultiplesOf = currencyData.getInMultiplesOf();
|
||||||
|
}
|
||||||
|
|
||||||
public MonetaryCurrency copy() {
|
public MonetaryCurrency copy() {
|
||||||
return new MonetaryCurrency(this.code, this.digitsAfterDecimal, this.inMultiplesOf);
|
return new MonetaryCurrency(this.code, this.digitsAfterDecimal, this.inMultiplesOf);
|
||||||
}
|
}
|
||||||
@@ -56,7 +65,14 @@ public class MonetaryCurrency {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static MonetaryCurrency fromCurrencyData(final CurrencyData currencyData) {
|
public static MonetaryCurrency fromCurrencyData(final CurrencyData currencyData) {
|
||||||
return new MonetaryCurrency(currencyData.getCode(), currencyData.getDecimalPlaces(), currencyData.getInMultiplesOf());
|
return new MonetaryCurrency(currencyData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CurrencyData toData() {
|
||||||
|
if (currencyData == null) {
|
||||||
|
currencyData = new CurrencyData(code, digitsAfterDecimal, inMultiplesOf);
|
||||||
|
}
|
||||||
|
return currencyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
|
|||||||
+70
-71
@@ -21,43 +21,59 @@ package org.apache.fineract.organisation.monetary.domain;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import lombok.Getter;
|
|
||||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class Money implements Comparable<Money> {
|
public class Money implements Comparable<Money> {
|
||||||
|
|
||||||
private final String currencyCode;
|
|
||||||
private final int currencyDigitsAfterDecimal;
|
|
||||||
private final Integer inMultiplesOf;
|
|
||||||
private final BigDecimal amount;
|
private final BigDecimal amount;
|
||||||
|
private final CurrencyData currency;
|
||||||
|
|
||||||
private final transient MathContext mc;
|
private final transient MathContext mc;
|
||||||
|
|
||||||
protected Money() {
|
protected Money() {
|
||||||
this.currencyCode = null;
|
this.currency = CurrencyData.blank();
|
||||||
this.currencyDigitsAfterDecimal = 0;
|
this.amount = BigDecimal.ZERO;
|
||||||
this.inMultiplesOf = 0;
|
|
||||||
this.amount = null;
|
|
||||||
this.mc = getMc();
|
this.mc = getMc();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Money(final String currencyCode, final int digitsAfterDecimal, final BigDecimal amount, final Integer inMultiplesOf,
|
private Money(final CurrencyData currency, final BigDecimal amount, final MathContext mc) {
|
||||||
final MathContext mc) {
|
this.currency = currency;
|
||||||
this.currencyCode = currencyCode;
|
|
||||||
this.currencyDigitsAfterDecimal = digitsAfterDecimal;
|
|
||||||
this.inMultiplesOf = inMultiplesOf;
|
|
||||||
this.mc = mc;
|
this.mc = mc;
|
||||||
|
|
||||||
final BigDecimal amountZeroed = defaultToZeroIfNull(amount);
|
final BigDecimal amountZeroed = defaultToZeroIfNull(amount);
|
||||||
BigDecimal amountScaled = amountZeroed.stripTrailingZeros();
|
BigDecimal amountScaled = amountZeroed.stripTrailingZeros();
|
||||||
|
|
||||||
// round monetary amounts into multiples of say 20/50.
|
// round monetary amounts into multiples of say 20/50.
|
||||||
if (inMultiplesOf != null && this.currencyDigitsAfterDecimal == 0 && inMultiplesOf > 0 && amountScaled.doubleValue() > 0) {
|
if (currency.getInMultiplesOf() != null && currency.getDecimalPlaces() == 0 && currency.getInMultiplesOf() > 0
|
||||||
|
&& amountScaled.doubleValue() > 0) {
|
||||||
final double existingVal = amountScaled.doubleValue();
|
final double existingVal = amountScaled.doubleValue();
|
||||||
amountScaled = BigDecimal.valueOf(roundToMultiplesOf(existingVal, inMultiplesOf));
|
amountScaled = BigDecimal.valueOf(roundToMultiplesOf(existingVal, currency.getInMultiplesOf()));
|
||||||
}
|
}
|
||||||
this.amount = amountScaled.setScale(this.currencyDigitsAfterDecimal, getMc().getRoundingMode());
|
this.amount = amountScaled.setScale(currency.getDecimalPlaces(), getMc().getRoundingMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonetaryCurrency getCurrency() {
|
||||||
|
return MonetaryCurrency.fromCurrencyData(currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CurrencyData getCurrencyData() {
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrencyCode() {
|
||||||
|
return currency.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getInMultiplesOf() {
|
||||||
|
return currency.getInMultiplesOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmountDefaultedToNullIfZero() {
|
||||||
|
return defaultToNullIfZero(this.amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Money total(final Money... monies) {
|
public static Money total(final Money... monies) {
|
||||||
@@ -83,21 +99,20 @@ public class Money implements Comparable<Money> {
|
|||||||
return total;
|
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 of(currency, newAmount, MoneyHelper.getMathContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Money of(final CurrencyData currency, final BigDecimal newAmount) {
|
public static Money of(final CurrencyData currency, final BigDecimal newAmount) {
|
||||||
return of(currency, newAmount, MoneyHelper.getMathContext());
|
return of(currency, newAmount, MoneyHelper.getMathContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Money of(final CurrencyData currency, final BigDecimal newAmount, final MathContext mc) {
|
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);
|
return new Money(currency, newAmount, mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Money of(final MonetaryCurrency currency, final BigDecimal newAmount, final MathContext mc) {
|
||||||
|
return new Money(currency.toData(), newAmount, mc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Money of(final MonetaryCurrency currency, final BigDecimal newAmount) {
|
||||||
|
return of(currency, newAmount, MoneyHelper.getMathContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Money zero(final MonetaryCurrency currency) {
|
public static Money zero(final MonetaryCurrency currency) {
|
||||||
@@ -105,11 +120,11 @@ public class Money implements Comparable<Money> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Money zero(final MonetaryCurrency currency, MathContext mc) {
|
public static Money zero(final MonetaryCurrency currency, MathContext mc) {
|
||||||
return new Money(currency.getCode(), currency.getDigitsAfterDecimal(), BigDecimal.ZERO, currency.getCurrencyInMultiplesOf(), mc);
|
return new Money(currency.toData(), BigDecimal.ZERO, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Money zero(final CurrencyData currency, MathContext mc) {
|
public static Money zero(final CurrencyData currency, MathContext mc) {
|
||||||
return new Money(currency.getCode(), currency.getDecimalPlaces(), BigDecimal.ZERO, currency.getInMultiplesOf(), mc);
|
return new Money(currency, BigDecimal.ZERO, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Money zero(final CurrencyData currency) {
|
public static Money zero(final CurrencyData currency) {
|
||||||
@@ -151,7 +166,7 @@ public class Money implements Comparable<Money> {
|
|||||||
if (inMultiplesOfValue.compareTo(BigDecimal.ZERO) > 0) {
|
if (inMultiplesOfValue.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
amountScaled = amountScaled.divide(inMultiplesOfValue, 0, mc.getRoundingMode()).multiply(inMultiplesOfValue);
|
amountScaled = amountScaled.divide(inMultiplesOfValue, 0, mc.getRoundingMode()).multiply(inMultiplesOfValue);
|
||||||
}
|
}
|
||||||
return Money.of(existingVal.getCurrency(), amountScaled);
|
return Money.of(existingVal.getCurrencyData(), amountScaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double ceiling(final double n, final double s) {
|
public static double ceiling(final double n, final double s) {
|
||||||
@@ -195,11 +210,11 @@ public class Money implements Comparable<Money> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Money copy() {
|
public Money copy() {
|
||||||
return new Money(this.currencyCode, this.currencyDigitsAfterDecimal, this.amount.stripTrailingZeros(), this.inMultiplesOf, this.mc);
|
return new Money(this.currency, this.amount, this.mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money copy(final BigDecimal amount) {
|
public Money copy(final BigDecimal amount) {
|
||||||
return new Money(this.currencyCode, this.currencyDigitsAfterDecimal, amount.stripTrailingZeros(), this.inMultiplesOf, this.mc);
|
return new Money(this.currency, amount, this.mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money copy(final double amount) {
|
public Money copy(final double amount) {
|
||||||
@@ -212,7 +227,7 @@ public class Money implements Comparable<Money> {
|
|||||||
final Money money = checkCurrencyEqual(moneyProvider);
|
final Money money = checkCurrencyEqual(moneyProvider);
|
||||||
total = total.add(money.amount);
|
total = total.add(money.amount);
|
||||||
}
|
}
|
||||||
return Money.of(monetaryCurrency(), total);
|
return Money.of(getCurrencyData(), total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money plus(final Money moneyToAdd) {
|
public Money plus(final Money moneyToAdd) {
|
||||||
@@ -233,7 +248,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.add(amountToAdd);
|
final BigDecimal newAmount = this.amount.add(amountToAdd);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money plus(final double amountToAdd) {
|
public Money plus(final double amountToAdd) {
|
||||||
@@ -241,7 +256,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.add(BigDecimal.valueOf(amountToAdd));
|
final BigDecimal newAmount = this.amount.add(BigDecimal.valueOf(amountToAdd));
|
||||||
return Money.of(monetaryCurrency(), newAmount);
|
return Money.of(getCurrencyData(), newAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money minus(final Money moneyToSubtract) {
|
public Money minus(final Money moneyToSubtract) {
|
||||||
@@ -271,7 +286,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.add(amountToAdd);
|
final BigDecimal newAmount = this.amount.add(amountToAdd);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money minus(final BigDecimal amountToSubtract) {
|
public Money minus(final BigDecimal amountToSubtract) {
|
||||||
@@ -283,7 +298,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.subtract(amountToSubtract);
|
final BigDecimal newAmount = this.amount.subtract(amountToSubtract);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Money checkCurrencyEqual(final Money money) {
|
private Money checkCurrencyEqual(final Money money) {
|
||||||
@@ -294,7 +309,7 @@ public class Money implements Comparable<Money> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSameCurrency(final Money money) {
|
public boolean isSameCurrency(final Money money) {
|
||||||
return this.currencyCode.equals(money.getCurrencyCode());
|
return getCurrencyCode().equals(money.getCurrencyCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money dividedBy(final BigDecimal valueToDivideBy, final MathContext mc) {
|
public Money dividedBy(final BigDecimal valueToDivideBy, final MathContext mc) {
|
||||||
@@ -302,7 +317,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.divide(valueToDivideBy, mc);
|
final BigDecimal newAmount = this.amount.divide(valueToDivideBy, mc);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money dividedBy(final double valueToDivideBy, final MathContext mc) {
|
public Money dividedBy(final double valueToDivideBy, final MathContext mc) {
|
||||||
@@ -310,7 +325,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.divide(BigDecimal.valueOf(valueToDivideBy), mc);
|
final BigDecimal newAmount = this.amount.divide(BigDecimal.valueOf(valueToDivideBy), mc);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money dividedBy(final long valueToDivideBy, final MathContext mc) {
|
public Money dividedBy(final long valueToDivideBy, final MathContext mc) {
|
||||||
@@ -318,7 +333,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.divide(BigDecimal.valueOf(valueToDivideBy), mc);
|
final BigDecimal newAmount = this.amount.divide(BigDecimal.valueOf(valueToDivideBy), mc);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money dividedBy(final long valueToDivideBy) {
|
public Money dividedBy(final long valueToDivideBy) {
|
||||||
@@ -326,7 +341,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.divide(BigDecimal.valueOf(valueToDivideBy), getMc());
|
final BigDecimal newAmount = this.amount.divide(BigDecimal.valueOf(valueToDivideBy), getMc());
|
||||||
return Money.of(monetaryCurrency(), newAmount, getMc());
|
return Money.of(getCurrencyData(), newAmount, getMc());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money multipliedBy(final BigDecimal valueToMultiplyBy) {
|
public Money multipliedBy(final BigDecimal valueToMultiplyBy) {
|
||||||
@@ -338,7 +353,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.multiply(valueToMultiplyBy, mc);
|
final BigDecimal newAmount = this.amount.multiply(valueToMultiplyBy, mc);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money multipliedBy(final double valueToMultiplyBy) {
|
public Money multipliedBy(final double valueToMultiplyBy) {
|
||||||
@@ -346,7 +361,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.multiply(BigDecimal.valueOf(valueToMultiplyBy));
|
final BigDecimal newAmount = this.amount.multiply(BigDecimal.valueOf(valueToMultiplyBy));
|
||||||
return Money.of(monetaryCurrency(), newAmount);
|
return Money.of(getCurrencyData(), newAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money multipliedBy(final long valueToMultiplyBy) {
|
public Money multipliedBy(final long valueToMultiplyBy) {
|
||||||
@@ -358,7 +373,7 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
final BigDecimal newAmount = this.amount.multiply(BigDecimal.valueOf(valueToMultiplyBy), mc);
|
final BigDecimal newAmount = this.amount.multiply(BigDecimal.valueOf(valueToMultiplyBy), mc);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money multiplyRetainScale(final BigDecimal valueToMultiplyBy, final MathContext mc) {
|
public Money multiplyRetainScale(final BigDecimal valueToMultiplyBy, final MathContext mc) {
|
||||||
@@ -366,8 +381,8 @@ public class Money implements Comparable<Money> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
BigDecimal newAmount = this.amount.multiply(valueToMultiplyBy, mc);
|
BigDecimal newAmount = this.amount.multiply(valueToMultiplyBy, mc);
|
||||||
newAmount = newAmount.setScale(this.currencyDigitsAfterDecimal, mc.getRoundingMode());
|
newAmount = newAmount.setScale(this.currency.getDecimalPlaces(), mc.getRoundingMode());
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money multiplyRetainScale(final double valueToMultiplyBy, final MathContext mc) {
|
public Money multiplyRetainScale(final double valueToMultiplyBy, final MathContext mc) {
|
||||||
@@ -376,12 +391,12 @@ public class Money implements Comparable<Money> {
|
|||||||
|
|
||||||
public Money percentageOf(BigDecimal percentage, final MathContext mc) {
|
public Money percentageOf(BigDecimal percentage, final MathContext mc) {
|
||||||
final BigDecimal newAmount = this.amount.multiply(percentage).divide(BigDecimal.valueOf(100), mc);
|
final BigDecimal newAmount = this.amount.multiply(percentage).divide(BigDecimal.valueOf(100), mc);
|
||||||
return Money.of(monetaryCurrency(), newAmount, mc);
|
return Money.of(getCurrencyData(), newAmount, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(final Money other) {
|
public int compareTo(final Money other) {
|
||||||
if (!this.currencyCode.equals(other.currencyCode)) {
|
if (!this.getCurrencyCode().equals(other.getCurrencyCode())) {
|
||||||
throw new UnsupportedOperationException("currencies arent different");
|
throw new UnsupportedOperationException("currencies arent different");
|
||||||
}
|
}
|
||||||
return this.amount.compareTo(other.amount);
|
return this.amount.compareTo(other.amount);
|
||||||
@@ -392,7 +407,7 @@ public class Money implements Comparable<Money> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isZero(final MathContext mc) {
|
public boolean isZero(final MathContext mc) {
|
||||||
return isEqualTo(Money.zero(getCurrency(), mc));
|
return isEqualTo(Money.zero(getCurrencyData(), mc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEqualTo(final Money other) {
|
public boolean isEqualTo(final Money other) {
|
||||||
@@ -416,7 +431,7 @@ public class Money implements Comparable<Money> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGreaterThanZero(MathContext mc) {
|
public boolean isGreaterThanZero(MathContext mc) {
|
||||||
return isGreaterThan(Money.zero(getCurrency(), mc));
|
return isGreaterThan(Money.zero(getCurrencyData(), mc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLessThan(final Money other) {
|
public boolean isLessThan(final Money other) {
|
||||||
@@ -428,20 +443,12 @@ public class Money implements Comparable<Money> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLessThanZero(final MathContext mc) {
|
public boolean isLessThanZero(final MathContext mc) {
|
||||||
return isLessThan(Money.zero(getCurrency(), mc));
|
return isLessThan(Money.zero(getCurrencyData(), mc));
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getCurrencyInMultiplesOf() {
|
|
||||||
return this.inMultiplesOf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getAmountDefaultedToNullIfZero() {
|
|
||||||
return defaultToNullIfZero(this.amount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new StringBuilder().append(this.currencyCode).append(' ').append(this.amount.toPlainString()).toString();
|
return this.getCurrencyCode() + ' ' + this.amount.toPlainString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money negated() {
|
public Money negated() {
|
||||||
@@ -452,7 +459,7 @@ public class Money implements Comparable<Money> {
|
|||||||
if (isZero(mc)) {
|
if (isZero(mc)) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return Money.of(monetaryCurrency(), this.amount.negate(), mc);
|
return Money.of(getCurrencyData(), this.amount.negate(), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money abs() {
|
public Money abs() {
|
||||||
@@ -463,20 +470,12 @@ public class Money implements Comparable<Money> {
|
|||||||
return isLessThanZero(mc) ? negated(mc) : this;
|
return isLessThanZero(mc) ? negated(mc) : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonetaryCurrency getCurrency() {
|
|
||||||
return monetaryCurrency();
|
|
||||||
}
|
|
||||||
|
|
||||||
private MonetaryCurrency monetaryCurrency() {
|
|
||||||
return new MonetaryCurrency(this.currencyCode, this.currencyDigitsAfterDecimal, this.inMultiplesOf);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money zero() {
|
public Money zero() {
|
||||||
return zero(getMc());
|
return zero(getMc());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money zero(MathContext mc) {
|
public Money zero(MathContext mc) {
|
||||||
return Money.zero(getCurrency(), mc);
|
return Money.zero(getCurrencyData(), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MathContext getMc() {
|
public MathContext getMc() {
|
||||||
|
|||||||
+5
@@ -22,6 +22,7 @@ import jakarta.persistence.Column;
|
|||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents currencies allowed for this MFI/organisation.
|
* Represents currencies allowed for this MFI/organisation.
|
||||||
@@ -74,4 +75,8 @@ public class OrganisationCurrency extends AbstractPersistableCustom<Long> {
|
|||||||
public final MonetaryCurrency toMonetaryCurrency() {
|
public final MonetaryCurrency toMonetaryCurrency() {
|
||||||
return new MonetaryCurrency(this.code, this.decimalPlaces, this.inMultiplesOf);
|
return new MonetaryCurrency(this.code, this.decimalPlaces, this.inMultiplesOf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final CurrencyData toData() {
|
||||||
|
return new CurrencyData(this.code, this.decimalPlaces, this.inMultiplesOf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -19,7 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.loanaccount.data;
|
package org.apache.fineract.portfolio.loanaccount.data;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||||
@@ -29,7 +29,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
|
|||||||
public class ScheduleGeneratorDTO {
|
public class ScheduleGeneratorDTO {
|
||||||
|
|
||||||
final LoanScheduleGeneratorFactory loanScheduleFactory;
|
final LoanScheduleGeneratorFactory loanScheduleFactory;
|
||||||
final ApplicationCurrency applicationCurrency;
|
final CurrencyData currency;
|
||||||
final LocalDate calculatedRepaymentsStartingFromDate;
|
final LocalDate calculatedRepaymentsStartingFromDate;
|
||||||
final HolidayDetailDTO holidayDetailDTO;
|
final HolidayDetailDTO holidayDetailDTO;
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation;
|
final CalendarInstance calendarInstanceForInterestRecalculation;
|
||||||
@@ -47,7 +47,7 @@ public class ScheduleGeneratorDTO {
|
|||||||
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI;
|
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI;
|
||||||
final boolean isPrincipalCompoundingDisabledForOverdueLoans;
|
final boolean isPrincipalCompoundingDisabledForOverdueLoans;
|
||||||
|
|
||||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final CurrencyData currency,
|
||||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
||||||
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO,
|
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO,
|
||||||
@@ -58,7 +58,7 @@ public class ScheduleGeneratorDTO {
|
|||||||
final boolean isPrincipalCompoundingDisabledForOverdueLoans) {
|
final boolean isPrincipalCompoundingDisabledForOverdueLoans) {
|
||||||
|
|
||||||
this.loanScheduleFactory = loanScheduleFactory;
|
this.loanScheduleFactory = loanScheduleFactory;
|
||||||
this.applicationCurrency = applicationCurrency;
|
this.currency = currency;
|
||||||
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
|
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
|
||||||
this.calendarInstanceForInterestRecalculation = calendarInstanceForInterestRecalculation;
|
this.calendarInstanceForInterestRecalculation = calendarInstanceForInterestRecalculation;
|
||||||
this.compoundingCalendarInstance = compoundingCalendarInstance;
|
this.compoundingCalendarInstance = compoundingCalendarInstance;
|
||||||
@@ -81,8 +81,8 @@ public class ScheduleGeneratorDTO {
|
|||||||
return this.loanScheduleFactory;
|
return this.loanScheduleFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplicationCurrency getApplicationCurrency() {
|
public CurrencyData getCurrency() {
|
||||||
return this.applicationCurrency;
|
return this.currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getCalculatedRepaymentsStartingFromDate() {
|
public LocalDate getCalculatedRepaymentsStartingFromDate() {
|
||||||
|
|||||||
+3
-3
@@ -2781,8 +2781,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
interestChargedFromDate = getDisbursementDate();
|
interestChargedFromDate = getDisbursementDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getApplicationCurrency(), loanTermFrequency,
|
return LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getCurrency(), loanTermFrequency, loanTermPeriodFrequencyType,
|
||||||
loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
|
nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
|
||||||
scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
|
scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
|
||||||
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
|
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
|
||||||
interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
||||||
@@ -3053,7 +3053,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||||
annualNominalInterestRate = constructFloatingInterestRates(annualNominalInterestRate, floatingRateDTO, loanTermVariations);
|
annualNominalInterestRate = constructFloatingInterestRates(annualNominalInterestRate, floatingRateDTO, loanTermVariations);
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
return LoanApplicationTerms.assembleFrom(applicationCurrency.toData(), loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
||||||
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
||||||
maxOutstandingBalance, interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
maxOutstandingBalance, interestChargedFromDate, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
||||||
|
|||||||
+8
-8
@@ -26,7 +26,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||||
@@ -97,7 +97,7 @@ public final class LoanScheduleParams {
|
|||||||
private final LocalDate scheduleTillDate;
|
private final LocalDate scheduleTillDate;
|
||||||
private final boolean partialUpdate;
|
private final boolean partialUpdate;
|
||||||
private int loanTermInDays;
|
private int loanTermInDays;
|
||||||
private final MonetaryCurrency currency;
|
private final CurrencyData currency;
|
||||||
private final boolean applyInterestRecalculation;
|
private final boolean applyInterestRecalculation;
|
||||||
private final MathContext mc;
|
private final MathContext mc;
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ public final class LoanScheduleParams {
|
|||||||
final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
|
final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
|
||||||
final Collection<RecalculationDetail> recalculationDetails,
|
final Collection<RecalculationDetail> recalculationDetails,
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
||||||
final boolean partialUpdate, final MonetaryCurrency currency, final boolean applyInterestRecalculation, final MathContext mc) {
|
final boolean partialUpdate, final CurrencyData currency, final boolean applyInterestRecalculation, final MathContext mc) {
|
||||||
this.periodNumber = periodNumber;
|
this.periodNumber = periodNumber;
|
||||||
this.instalmentNumber = instalmentNumber;
|
this.instalmentNumber = instalmentNumber;
|
||||||
this.loanTermInDays = loanTermInDays;
|
this.loanTermInDays = loanTermInDays;
|
||||||
@@ -153,7 +153,7 @@ public final class LoanScheduleParams {
|
|||||||
final Money principalToBeScheduled, final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
|
final Money principalToBeScheduled, final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
|
final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
||||||
final MonetaryCurrency currency, final boolean applyInterestRecalculation, final MathContext mc) {
|
final CurrencyData currency, final boolean applyInterestRecalculation, final MathContext mc) {
|
||||||
final boolean partialUpdate = true;
|
final boolean partialUpdate = true;
|
||||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||||
@@ -187,7 +187,7 @@ public final class LoanScheduleParams {
|
|||||||
final boolean partialUpdate = false;
|
final boolean partialUpdate = false;
|
||||||
final int loanTermInDays = 0;
|
final int loanTermInDays = 0;
|
||||||
final Money totalOutstandingInterestPaymentDueToGrace = null;
|
final Money totalOutstandingInterestPaymentDueToGrace = null;
|
||||||
final MonetaryCurrency currency = null;
|
final CurrencyData currency = null;
|
||||||
final Money unCompoundedAmount = null;
|
final Money unCompoundedAmount = null;
|
||||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||||
@@ -197,7 +197,7 @@ public final class LoanScheduleParams {
|
|||||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
|
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
|
public static LoanScheduleParams createLoanScheduleParams(final CurrencyData currency, final Money chargesDueAtTimeOfDisbursement,
|
||||||
final LocalDate periodStartDate, final Money principalToBeScheduled, final MathContext mc) {
|
final LocalDate periodStartDate, final Money principalToBeScheduled, final MathContext mc) {
|
||||||
final int loanTermInDays = 0;
|
final int loanTermInDays = 0;
|
||||||
final int periodNumber = 1;
|
final int periodNumber = 1;
|
||||||
@@ -231,7 +231,7 @@ public final class LoanScheduleParams {
|
|||||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
|
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
|
public static LoanScheduleParams createLoanScheduleParams(final CurrencyData currency, final Money chargesDueAtTimeOfDisbursement,
|
||||||
final LocalDate periodStartDate, final Money principalToBeScheduled, final LoanScheduleParams loanScheduleParams,
|
final LocalDate periodStartDate, final Money principalToBeScheduled, final LoanScheduleParams loanScheduleParams,
|
||||||
MathContext mc) {
|
MathContext mc) {
|
||||||
final int loanTermInDays = 0;
|
final int loanTermInDays = 0;
|
||||||
@@ -500,7 +500,7 @@ public final class LoanScheduleParams {
|
|||||||
return this.compoundingDateVariations;
|
return this.compoundingDateVariations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonetaryCurrency getCurrency() {
|
public CurrencyData getCurrency() {
|
||||||
return this.currency;
|
return this.currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-29
@@ -37,7 +37,7 @@ import java.util.Set;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO;
|
import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO;
|
||||||
@@ -74,7 +74,6 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
private LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
private LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
||||||
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, final LoanScheduleParams loanScheduleParams) {
|
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, final LoanScheduleParams loanScheduleParams) {
|
||||||
|
|
||||||
final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency();
|
|
||||||
// generate list of proposed schedule due dates
|
// generate list of proposed schedule due dates
|
||||||
LocalDate loanEndDate = getScheduledDateGenerator().getLastRepaymentDate(loanApplicationTerms, holidayDetailDTO);
|
LocalDate loanEndDate = getScheduledDateGenerator().getLastRepaymentDate(loanApplicationTerms, holidayDetailDTO);
|
||||||
LoanTermVariationsData lastDueDateVariation = loanApplicationTerms.getLoanTermVariations()
|
LoanTermVariationsData lastDueDateVariation = loanApplicationTerms.getLoanTermVariations()
|
||||||
@@ -90,7 +89,8 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
// setup variables for tracking important facts required for loan
|
// setup variables for tracking important facts required for loan
|
||||||
// schedule generation.
|
// schedule generation.
|
||||||
|
|
||||||
final MonetaryCurrency currency = loanApplicationTerms.getCurrency();
|
final CurrencyData currency = loanApplicationTerms.getCurrency();
|
||||||
|
final MonetaryCurrency monetaryCurrency = MonetaryCurrency.fromCurrencyData(currency);
|
||||||
LoanScheduleParams scheduleParams;
|
LoanScheduleParams scheduleParams;
|
||||||
LocalDate periodStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
LocalDate periodStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
||||||
? loanApplicationTerms.getExpectedDisbursementDate()
|
? loanApplicationTerms.getExpectedDisbursementDate()
|
||||||
@@ -252,7 +252,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
|
|
||||||
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
|
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
|
||||||
populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms,
|
populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms,
|
||||||
holidayDetailDTO, scheduleParams, loanCharges, currency, mc);
|
holidayDetailDTO, scheduleParams, loanCharges, monetaryCurrency, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// populates the collection with transactions till the due date of
|
// populates the collection with transactions till the due date of
|
||||||
@@ -330,7 +330,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
}
|
}
|
||||||
|
|
||||||
// applies charges for the period
|
// applies charges for the period
|
||||||
applyChargesForCurrentPeriod(loanCharges, currency, scheduleParams, scheduledDueDate, currentPeriodParams, mc);
|
applyChargesForCurrentPeriod(loanCharges, monetaryCurrency, scheduleParams, scheduledDueDate, currentPeriodParams, mc);
|
||||||
|
|
||||||
// sum up real totalInstallmentDue from components
|
// sum up real totalInstallmentDue from components
|
||||||
final Money totalInstallmentDue = currentPeriodParams.fetchTotalAmountForPeriod();
|
final Money totalInstallmentDue = currentPeriodParams.fetchTotalAmountForPeriod();
|
||||||
@@ -354,7 +354,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
|
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
|
||||||
// apply loan transactions on installments to identify early/late
|
// apply loan transactions on installments to identify early/late
|
||||||
// payments for interest recalculation
|
// payments for interest recalculation
|
||||||
installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, currency, scheduleParams,
|
installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, monetaryCurrency, scheduleParams,
|
||||||
loanRepaymentScheduleTransactionProcessor, loanApplicationTerms.getTotalInterestDue(), lastRestDate, scheduledDueDate,
|
loanRepaymentScheduleTransactionProcessor, loanApplicationTerms.getTotalInterestDue(), lastRestDate, scheduledDueDate,
|
||||||
periodStartDateApplicableForInterest, applicableTransactions, currentPeriodParams,
|
periodStartDateApplicableForInterest, applicableTransactions, currentPeriodParams,
|
||||||
lastTotalOutstandingInterestPaymentDueToGrace, installment, loanCharges);
|
lastTotalOutstandingInterestPaymentDueToGrace, installment, loanCharges);
|
||||||
@@ -398,7 +398,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
|
|
||||||
// determine fees and penalties for charges which depends on total
|
// determine fees and penalties for charges which depends on total
|
||||||
// loan interest
|
// loan interest
|
||||||
updatePeriodsWithCharges(currency, scheduleParams, periods, nonCompoundingCharges, mc);
|
updatePeriodsWithCharges(monetaryCurrency, scheduleParams, periods, nonCompoundingCharges, mc);
|
||||||
|
|
||||||
// this block is to add extra re-payment schedules with interest portion
|
// this block is to add extra re-payment schedules with interest portion
|
||||||
// if the loan not paid with in loan term
|
// if the loan not paid with in loan term
|
||||||
@@ -408,8 +408,9 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
}
|
}
|
||||||
if (scheduleParams.applyInterestRecalculation() && scheduleParams.getLatePaymentMap().size() > 0
|
if (scheduleParams.applyInterestRecalculation() && scheduleParams.getLatePaymentMap().size() > 0
|
||||||
&& DateUtils.isAfter(currentDate, scheduleParams.getPeriodStartDate())) {
|
&& DateUtils.isAfter(currentDate, scheduleParams.getPeriodStartDate())) {
|
||||||
Money totalInterest = addInterestOnlyRepaymentScheduleForCurrentDate(mc, loanApplicationTerms, holidayDetailDTO, currency,
|
Money totalInterest = addInterestOnlyRepaymentScheduleForCurrentDate(mc, loanApplicationTerms, holidayDetailDTO,
|
||||||
periods, currentDate, loanRepaymentScheduleTransactionProcessor, transactions, loanCharges, scheduleParams);
|
monetaryCurrency, periods, currentDate, loanRepaymentScheduleTransactionProcessor, transactions, loanCharges,
|
||||||
|
scheduleParams);
|
||||||
scheduleParams.addTotalCumulativeInterest(totalInterest);
|
scheduleParams.addTotalCumulativeInterest(totalInterest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +419,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
final BigDecimal totalOutstanding = BigDecimal.ZERO;
|
final BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||||
|
|
||||||
updateCompoundingDetails(periods, scheduleParams, loanApplicationTerms);
|
updateCompoundingDetails(periods, scheduleParams, loanApplicationTerms);
|
||||||
return LoanScheduleModel.from(periods, applicationCurrency, scheduleParams.getLoanTermInDays(),
|
return LoanScheduleModel.from(periods, currency, scheduleParams.getLoanTermInDays(),
|
||||||
scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount()),
|
scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount()),
|
||||||
scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount()).getAmount(),
|
scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount()).getAmount(),
|
||||||
totalPrincipalPaid, scheduleParams.getTotalCumulativeInterest().getAmount(),
|
totalPrincipalPaid, scheduleParams.getTotalCumulativeInterest().getAmount(),
|
||||||
@@ -534,7 +535,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
modifiedInstallment = handlePrepaymentOfLoan(mc, loanApplicationTerms, holidayDetailDTO, scheduleParams,
|
modifiedInstallment = handlePrepaymentOfLoan(mc, loanApplicationTerms, holidayDetailDTO, scheduleParams,
|
||||||
totalInterestChargedForFullLoanTerm, scheduledDueDate, periodStartDateApplicableForInterest,
|
totalInterestChargedForFullLoanTerm, scheduledDueDate, periodStartDateApplicableForInterest,
|
||||||
currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), currentPeriodParams,
|
currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), currentPeriodParams,
|
||||||
lastTotalOutstandingInterestPaymentDueToGrace, transactionDate, modifiedInstallment, loanCharges);
|
lastTotalOutstandingInterestPaymentDueToGrace, transactionDate, modifiedInstallment, loanCharges, currency);
|
||||||
|
|
||||||
Money addToPrincipal = Money.zero(currency);
|
Money addToPrincipal = Money.zero(currency);
|
||||||
if (scheduleParams.getOutstandingBalance().isLessThanZero()) {
|
if (scheduleParams.getOutstandingBalance().isLessThanZero()) {
|
||||||
@@ -575,17 +576,18 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
final Money totalInterestChargedForFullLoanTerm, final LocalDate scheduledDueDate,
|
final Money totalInterestChargedForFullLoanTerm, final LocalDate scheduledDueDate,
|
||||||
LocalDate periodStartDateApplicableForInterest, final BigDecimal interestCalculationGraceOnRepaymentPeriodFraction,
|
LocalDate periodStartDateApplicableForInterest, final BigDecimal interestCalculationGraceOnRepaymentPeriodFraction,
|
||||||
final ScheduleCurrentPeriodParams currentPeriodParams, final Money lastTotalOutstandingInterestPaymentDueToGrace,
|
final ScheduleCurrentPeriodParams currentPeriodParams, final Money lastTotalOutstandingInterestPaymentDueToGrace,
|
||||||
final LocalDate transactionDate, final LoanScheduleModelPeriod installment, Set<LoanCharge> loanCharges) {
|
final LocalDate transactionDate, final LoanScheduleModelPeriod installment, Set<LoanCharge> loanCharges,
|
||||||
|
MonetaryCurrency currency) {
|
||||||
LoanScheduleModelPeriod modifiedInstallment = installment;
|
LoanScheduleModelPeriod modifiedInstallment = installment;
|
||||||
Money outstanding = scheduleParams.getOutstandingBalance();
|
Money outstanding = scheduleParams.getOutstandingBalance();
|
||||||
PrincipalInterest tempPrincipalInterest = new PrincipalInterest(currentPeriodParams.getPrincipalForThisPeriod(),
|
PrincipalInterest tempPrincipalInterest = new PrincipalInterest(currentPeriodParams.getPrincipalForThisPeriod(),
|
||||||
currentPeriodParams.getInterestForThisPeriod(), null);
|
currentPeriodParams.getInterestForThisPeriod(), null);
|
||||||
outstanding = outstanding.minus(cumulativeFeeChargesDueWithin(transactionDate, scheduledDueDate, loanCharges,
|
outstanding = outstanding.minus(cumulativeFeeChargesDueWithin(transactionDate, scheduledDueDate, loanCharges, currency,
|
||||||
totalInterestChargedForFullLoanTerm.getCurrency(), tempPrincipalInterest, scheduleParams.getPrincipalToBeScheduled(),
|
tempPrincipalInterest, scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativeInterest(), true,
|
||||||
scheduleParams.getTotalCumulativeInterest(), true, scheduleParams.isFirstPeriod(), mc));
|
scheduleParams.isFirstPeriod(), mc));
|
||||||
outstanding = outstanding.minus(cumulativePenaltyChargesDueWithin(transactionDate, scheduledDueDate, loanCharges,
|
outstanding = outstanding.minus(cumulativePenaltyChargesDueWithin(transactionDate, scheduledDueDate, loanCharges, currency,
|
||||||
totalInterestChargedForFullLoanTerm.getCurrency(), tempPrincipalInterest, scheduleParams.getPrincipalToBeScheduled(),
|
tempPrincipalInterest, scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativeInterest(), true,
|
||||||
scheduleParams.getTotalCumulativeInterest(), true, scheduleParams.isFirstPeriod(), mc));
|
scheduleParams.isFirstPeriod(), mc));
|
||||||
|
|
||||||
if (!outstanding.isGreaterThan(currentPeriodParams.getInterestForThisPeriod()) && !scheduledDueDate.equals(transactionDate)) {
|
if (!outstanding.isGreaterThan(currentPeriodParams.getInterestForThisPeriod()) && !scheduledDueDate.equals(transactionDate)) {
|
||||||
final Collection<LoanTermVariationsData> interestRates = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
|
final Collection<LoanTermVariationsData> interestRates = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
|
||||||
@@ -607,7 +609,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
new TreeMap<>(scheduleParams.getCompoundingMap()));
|
new TreeMap<>(scheduleParams.getCompoundingMap()));
|
||||||
scheduleParams.getCompoundingMap().clear();
|
scheduleParams.getCompoundingMap().clear();
|
||||||
populateCompoundingDatesInPeriod(periodStartDateApplicableForInterest, calculateTill, loanApplicationTerms, holidayDetailDTO,
|
populateCompoundingDatesInPeriod(periodStartDateApplicableForInterest, calculateTill, loanApplicationTerms, holidayDetailDTO,
|
||||||
scheduleParams, loanCharges, totalInterestChargedForFullLoanTerm.getCurrency(), mc);
|
scheduleParams, loanCharges, currency, mc);
|
||||||
|
|
||||||
// this is to make sure we are recalculating using correct interest
|
// this is to make sure we are recalculating using correct interest
|
||||||
// rate
|
// rate
|
||||||
@@ -628,11 +630,10 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
loanApplicationTerms.updateAnnualNominalInterestRate(currentInterestRate);
|
loanApplicationTerms.updateAnnualNominalInterestRate(currentInterestRate);
|
||||||
|
|
||||||
// applies charges for the period
|
// applies charges for the period
|
||||||
final ScheduleCurrentPeriodParams tempPeriod = new ScheduleCurrentPeriodParams(
|
final ScheduleCurrentPeriodParams tempPeriod = new ScheduleCurrentPeriodParams(loanApplicationTerms.getCurrency(),
|
||||||
totalInterestChargedForFullLoanTerm.getCurrency(), interestCalculationGraceOnRepaymentPeriodFraction);
|
interestCalculationGraceOnRepaymentPeriodFraction);
|
||||||
tempPeriod.setInterestForThisPeriod(interestTillDate.interest());
|
tempPeriod.setInterestForThisPeriod(interestTillDate.interest());
|
||||||
applyChargesForCurrentPeriod(loanCharges, totalInterestChargedForFullLoanTerm.getCurrency(), scheduleParams, calculateTill,
|
applyChargesForCurrentPeriod(loanCharges, currency, scheduleParams, calculateTill, tempPeriod, mc);
|
||||||
tempPeriod, mc);
|
|
||||||
Money interestDiff = currentPeriodParams.getInterestForThisPeriod().minus(tempPeriod.getInterestForThisPeriod());
|
Money interestDiff = currentPeriodParams.getInterestForThisPeriod().minus(tempPeriod.getInterestForThisPeriod());
|
||||||
Money chargeDiff = currentPeriodParams.getFeeChargesForInstallment().minus(tempPeriod.getFeeChargesForInstallment());
|
Money chargeDiff = currentPeriodParams.getFeeChargesForInstallment().minus(tempPeriod.getFeeChargesForInstallment());
|
||||||
Money penaltyDiff = currentPeriodParams.getPenaltyChargesForInstallment().minus(tempPeriod.getPenaltyChargesForInstallment());
|
Money penaltyDiff = currentPeriodParams.getPenaltyChargesForInstallment().minus(tempPeriod.getPenaltyChargesForInstallment());
|
||||||
@@ -684,8 +685,8 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
.reduceOutstandingBalance(currentPeriodParams.getPrincipalForThisPeriod().minus(currentPeriodParams.getReducedBalance()));
|
.reduceOutstandingBalance(currentPeriodParams.getPrincipalForThisPeriod().minus(currentPeriodParams.getReducedBalance()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePrincipalPortionBasedOnPreviousEarlyPayments(final MonetaryCurrency currency,
|
private void updatePrincipalPortionBasedOnPreviousEarlyPayments(final CurrencyData currency, final LoanScheduleParams scheduleParams,
|
||||||
final LoanScheduleParams scheduleParams, final ScheduleCurrentPeriodParams currentPeriodParams) {
|
final ScheduleCurrentPeriodParams currentPeriodParams) {
|
||||||
if (currentPeriodParams.getPrincipalForThisPeriod().isGreaterThan(scheduleParams.getReducePrincipal())) {
|
if (currentPeriodParams.getPrincipalForThisPeriod().isGreaterThan(scheduleParams.getReducePrincipal())) {
|
||||||
currentPeriodParams.minusPrincipalForThisPeriod(scheduleParams.getReducePrincipal());
|
currentPeriodParams.minusPrincipalForThisPeriod(scheduleParams.getReducePrincipal());
|
||||||
scheduleParams.setReducePrincipal(Money.zero(currency));
|
scheduleParams.setReducePrincipal(Money.zero(currency));
|
||||||
@@ -711,7 +712,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
final LocalDate scheduledDueDate, final LocalDate periodStartDateForInterest,
|
final LocalDate scheduledDueDate, final LocalDate periodStartDateForInterest,
|
||||||
final Collection<RecalculationDetail> applicableTransactions, final ScheduleCurrentPeriodParams currentPeriodParams) {
|
final Collection<RecalculationDetail> applicableTransactions, final ScheduleCurrentPeriodParams currentPeriodParams) {
|
||||||
if (scheduleParams.applyInterestRecalculation()) {
|
if (scheduleParams.applyInterestRecalculation()) {
|
||||||
final MonetaryCurrency currency = scheduleParams.getCurrency();
|
final MonetaryCurrency currency = MonetaryCurrency.fromCurrencyData(scheduleParams.getCurrency());
|
||||||
final Collection<LoanTermVariationsData> interestRates = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
|
final Collection<LoanTermVariationsData> interestRates = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
|
||||||
boolean checkForOutstanding = true;
|
boolean checkForOutstanding = true;
|
||||||
List<RecalculationDetail> unprocessedTransactions = new ArrayList<>();
|
List<RecalculationDetail> unprocessedTransactions = new ArrayList<>();
|
||||||
@@ -1682,7 +1683,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
final LoanScheduleParams params, final LocalDate lastRestDate, final LocalDate scheduledDueDate) {
|
final LoanScheduleParams params, final LocalDate lastRestDate, final LocalDate scheduledDueDate) {
|
||||||
if (loanApplicationTerms.isInterestRecalculationEnabled()
|
if (loanApplicationTerms.isInterestRecalculationEnabled()
|
||||||
&& loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
&& loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||||
final MonetaryCurrency currency = params.getCurrency();
|
final MonetaryCurrency currency = MonetaryCurrency.fromCurrencyData(params.getCurrency());
|
||||||
Money totalCompoundedAmount = Money.zero(currency);
|
Money totalCompoundedAmount = Money.zero(currency);
|
||||||
boolean lastInstallmentIsPastDate = false;
|
boolean lastInstallmentIsPastDate = false;
|
||||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : params.getInstallments()) {
|
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : params.getInstallments()) {
|
||||||
@@ -1802,7 +1803,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
private void adjustCompoundedAmountWithPaidDetail(final LoanScheduleParams params, final LocalDate lastRestDate,
|
private void adjustCompoundedAmountWithPaidDetail(final LoanScheduleParams params, final LocalDate lastRestDate,
|
||||||
final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms) {
|
final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms) {
|
||||||
adjustCompoundedAmountWithPaidDetail(params.getPrincipalPortionMap(), lastRestDate, amountApplicableDate, transaction,
|
adjustCompoundedAmountWithPaidDetail(params.getPrincipalPortionMap(), lastRestDate, amountApplicableDate, transaction,
|
||||||
loanApplicationTerms, params.getCurrency());
|
loanApplicationTerms, MonetaryCurrency.fromCurrencyData(params.getCurrency()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adjustCompoundedAmountWithPaidDetail(final Map<LocalDate, Money> principalPortionMap, final LocalDate lastRestDate,
|
private void adjustCompoundedAmountWithPaidDetail(final Map<LocalDate, Money> principalPortionMap, final LocalDate lastRestDate,
|
||||||
@@ -2493,7 +2494,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
|||||||
totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap,
|
totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap,
|
||||||
uncompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest,
|
uncompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest,
|
||||||
newRepaymentScheduleInstallments, recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate,
|
newRepaymentScheduleInstallments, recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate,
|
||||||
currency, applyInterestRecalculation, mc);
|
currency.toData(), applyInterestRecalculation, mc);
|
||||||
retainedInstallments.addAll(newRepaymentScheduleInstallments);
|
retainedInstallments.addAll(newRepaymentScheduleInstallments);
|
||||||
loanScheduleParams.getCompoundingDateVariations().putAll(compoundingDateVariations);
|
loanScheduleParams.getCompoundingDateVariations().putAll(compoundingDateVariations);
|
||||||
loanApplicationTerms.updateTotalInterestDue(Money.of(currency, loan.getSummary().getTotalInterestCharged()));
|
loanApplicationTerms.updateTotalInterestDue(Money.of(currency, loan.getSummary().getTotalInterestCharged()));
|
||||||
|
|||||||
+22
-6
@@ -20,10 +20,12 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
|||||||
|
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.YearMonth;
|
||||||
|
import java.time.temporal.ChronoField;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.time.temporal.Temporal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import net.fortuna.ical4j.model.Recur;
|
import net.fortuna.ical4j.model.Recur;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||||
@@ -42,7 +44,6 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
|
||||||
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -121,7 +122,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
|
Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
|
||||||
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
||||||
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate);
|
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate);
|
||||||
dueRepaymentPeriodDate = (LocalDate) CalendarUtils.adjustDate(dueRepaymentPeriodDate, loanApplicationTerms.getSeedDate(),
|
dueRepaymentPeriodDate = (LocalDate) adjustDate(dueRepaymentPeriodDate, loanApplicationTerms.getSeedDate(),
|
||||||
loanApplicationTerms.getRepaymentPeriodFrequencyType());
|
loanApplicationTerms.getRepaymentPeriodFrequencyType());
|
||||||
if (currentCalendar != null) {
|
if (currentCalendar != null) {
|
||||||
// If we have currentCalendar object, this means there is a
|
// If we have currentCalendar object, this means there is a
|
||||||
@@ -154,6 +155,21 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
return dueRepaymentPeriodDate;
|
return dueRepaymentPeriodDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: This method a copy of CalendarUtils.adjustDate() method. Purpose of this method copy here is to eliminate
|
||||||
|
* the whole "ical4j" dependency for the small stateless embeddable progressive loan jar. Registered exception
|
||||||
|
* brings the whole ical4j deps.
|
||||||
|
*/
|
||||||
|
private Temporal adjustDate(final Temporal date, final Temporal seedDate, final PeriodFrequencyType frequencyType) {
|
||||||
|
if (frequencyType.isMonthly() && seedDate.get(ChronoField.DAY_OF_MONTH) > 28 && date.get(ChronoField.DAY_OF_MONTH) >= 28) {
|
||||||
|
int noOfDaysInCurrentMonth = YearMonth.from(date).lengthOfMonth();
|
||||||
|
int seedDay = seedDate.get(ChronoField.DAY_OF_MONTH);
|
||||||
|
int adjustedDay = Math.min(noOfDaysInCurrentMonth, seedDay);
|
||||||
|
return date.with(ChronoField.DAY_OF_MONTH, adjustedDay);
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms,
|
public LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms,
|
||||||
final boolean isFirstRepayment, final Integer periodNumber) {
|
final boolean isFirstRepayment, final Integer periodNumber) {
|
||||||
@@ -305,7 +321,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
case WHOLE_TERM:
|
case WHOLE_TERM:
|
||||||
log.error("TODO Implement getRepaymentPeriodDate for WHOLE_TERM");
|
// TODO: Implement getRepaymentPeriodDate for WHOLE_TERM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return dueRepaymentPeriodDate;
|
return dueRepaymentPeriodDate;
|
||||||
@@ -347,7 +363,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
case WHOLE_TERM:
|
case WHOLE_TERM:
|
||||||
log.error("TODO Implement isDateFallsInSchedule for WHOLE_TERM");
|
// TODO: Implement getRepaymentPeriodDate for WHOLE_TERM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return isScheduledDate;
|
return isScheduledDate;
|
||||||
@@ -384,7 +400,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
|||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
case WHOLE_TERM:
|
case WHOLE_TERM:
|
||||||
log.error("TODO Implement repaymentPeriodFrequencyType for WHOLE_TERM");
|
// TODO: Implement getRepaymentPeriodDate for WHOLE_TERM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+43
-40
@@ -27,11 +27,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||||
@@ -48,21 +46,22 @@ import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsDataWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.data.LoanProductRelatedDetailMinimumData;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanSupportedInterestRefundTypes;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public final class LoanApplicationTerms {
|
public final class LoanApplicationTerms {
|
||||||
|
|
||||||
private ApplicationCurrency currency;
|
private CurrencyData currency;
|
||||||
|
|
||||||
private Calendar loanCalendar;
|
private Calendar loanCalendar;
|
||||||
private Integer loanTermFrequency;
|
private Integer loanTermFrequency;
|
||||||
@@ -268,7 +267,7 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
private ApplicationCurrency currency;
|
private CurrencyData currency;
|
||||||
private Integer loanTermFrequency;
|
private Integer loanTermFrequency;
|
||||||
private PeriodFrequencyType loanTermPeriodFrequencyType;
|
private PeriodFrequencyType loanTermPeriodFrequencyType;
|
||||||
private Integer numberOfRepayments;
|
private Integer numberOfRepayments;
|
||||||
@@ -292,7 +291,7 @@ public final class LoanApplicationTerms {
|
|||||||
private LocalDate seedDate;
|
private LocalDate seedDate;
|
||||||
private MathContext mc;
|
private MathContext mc;
|
||||||
|
|
||||||
public Builder currency(ApplicationCurrency currency) {
|
public Builder currency(CurrencyData currency) {
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -408,7 +407,7 @@ public final class LoanApplicationTerms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(LoanRepaymentScheduleModelData modelData, MathContext mc) {
|
public static LoanApplicationTerms assembleFrom(LoanRepaymentScheduleModelData modelData, MathContext mc) {
|
||||||
Money principal = Money.of(modelData.currency().toData(), modelData.disbursementAmount(), mc);
|
Money principal = Money.of(modelData.currency(), modelData.disbursementAmount(), mc);
|
||||||
BigDecimal downPaymentPercentage = modelData.downPaymentPercentage();
|
BigDecimal downPaymentPercentage = modelData.downPaymentPercentage();
|
||||||
|
|
||||||
LocalDate seedDate;
|
LocalDate seedDate;
|
||||||
@@ -428,12 +427,12 @@ public final class LoanApplicationTerms {
|
|||||||
.annualNominalInterestRate(modelData.annualNominalInterestRate()).principal(principal)
|
.annualNominalInterestRate(modelData.annualNominalInterestRate()).principal(principal)
|
||||||
.expectedDisbursementDate(modelData.disbursementDate()).repaymentsStartingFromDate(modelData.scheduleGenerationStartDate())
|
.expectedDisbursementDate(modelData.disbursementDate()).repaymentsStartingFromDate(modelData.scheduleGenerationStartDate())
|
||||||
.daysInMonthType(modelData.daysInMonth()).daysInYearType(modelData.daysInYear()).fixedLength(modelData.fixedLength())
|
.daysInMonthType(modelData.daysInMonth()).daysInYearType(modelData.daysInYear()).fixedLength(modelData.fixedLength())
|
||||||
.inArrearsTolerance(Money.zero(modelData.currency().toData(), mc)).disbursementDatas(new ArrayList<>())
|
.inArrearsTolerance(Money.zero(modelData.currency(), mc)).disbursementDatas(new ArrayList<>())
|
||||||
.isDownPaymentEnabled(modelData.downPaymentEnabled()).downPaymentPercentage(downPaymentPercentage)
|
.isDownPaymentEnabled(modelData.downPaymentEnabled()).downPaymentPercentage(downPaymentPercentage)
|
||||||
.submittedOnDate(modelData.scheduleGenerationStartDate()).seedDate(seedDate).mc(mc).build();
|
.submittedOnDate(modelData.scheduleGenerationStartDate()).seedDate(seedDate).mc(mc).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final CurrencyData currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
||||||
final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
|
final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
|
||||||
@@ -484,7 +483,7 @@ public final class LoanApplicationTerms {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
public static LoanApplicationTerms assembleFrom(final CurrencyData currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, NthDayType nthDay, DayOfWeekType dayOfWeek,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, NthDayType nthDay, DayOfWeekType dayOfWeek,
|
||||||
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
|
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
|
||||||
final LocalDate calculatedRepaymentsStartingFromDate, final Money inArrearsTolerance,
|
final LocalDate calculatedRepaymentsStartingFromDate, final Money inArrearsTolerance,
|
||||||
@@ -537,27 +536,26 @@ public final class LoanApplicationTerms {
|
|||||||
LoanScheduleType loanScheduleType = loanProductRelatedDetail.getLoanScheduleType();
|
LoanScheduleType loanScheduleType = loanProductRelatedDetail.getLoanScheduleType();
|
||||||
LoanScheduleProcessingType loanScheduleProcessingType = loanProductRelatedDetail.getLoanScheduleProcessingType();
|
LoanScheduleProcessingType loanScheduleProcessingType = loanProductRelatedDetail.getLoanScheduleProcessingType();
|
||||||
final Integer fixedLength = loanProductRelatedDetail.getFixedLength();
|
final Integer fixedLength = loanProductRelatedDetail.getFixedLength();
|
||||||
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
|
||||||
repaymentEvery, repaymentPeriodFrequencyType, ((nthDay != null) ? nthDay.getValue() : null), dayOfWeek, amortizationMethod,
|
repaymentPeriodFrequencyType, ((nthDay != null) ? nthDay.getValue() : null), dayOfWeek, amortizationMethod, interestMethod,
|
||||||
interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate,
|
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
||||||
interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate,
|
allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
|
||||||
repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment,
|
calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods,
|
||||||
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate,
|
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount,
|
||||||
inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance,
|
disbursementDatas, maxOutstandingBalance, loanProductRelatedDetail.getGraceOnArrearsAgeing(), daysInMonthType,
|
||||||
loanProductRelatedDetail.getGraceOnArrearsAgeing(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, compoundingMethod, restCalendarInstance,
|
||||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations,
|
||||||
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations, calendarHistoryDataWrapper,
|
calendarHistoryDataWrapper, isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays,
|
||||||
isInterestChargedFromDateSameAsDisbursalDateEnabled, numberOfDays, isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO,
|
isSkipRepaymentOnFirstDayOfMonth, holidayDetailDTO, allowCompoundingOnEod, isEqualAmortization,
|
||||||
allowCompoundingOnEod, isEqualAmortization, isFirstRepaymentDateAllowedOnHoliday,
|
isFirstRepaymentDateAllowedOnHoliday, isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
||||||
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
|
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
|
||||||
isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled, disbursedAmountPercentageForDownPayment,
|
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
|
||||||
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
|
loanScheduleType, loanScheduleProcessingType, fixedLength, loanProductRelatedDetail.isEnableAccrualActivityPosting(),
|
||||||
fixedLength, loanProductRelatedDetail.isEnableAccrualActivityPosting(),
|
|
||||||
loanProductRelatedDetail.getSupportedInterestRefundTypes(), loanProductRelatedDetail.getChargeOffBehaviour());
|
loanProductRelatedDetail.getSupportedInterestRefundTypes(), loanProductRelatedDetail.getChargeOffBehaviour());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
private LoanApplicationTerms(final CurrencyData currency, final Integer loanTermFrequency,
|
||||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||||
final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer nthDay, final DayOfWeekType weekDayType,
|
final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer nthDay, final DayOfWeekType weekDayType,
|
||||||
final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
|
final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
|
||||||
@@ -830,7 +828,7 @@ public final class LoanApplicationTerms {
|
|||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
case WHOLE_TERM:
|
case WHOLE_TERM:
|
||||||
log.error("TODO Implement getPeriodEndDate for WHOLE_TERM");
|
// TODO: Implement getPeriodEndDate for WHOLE_TERM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return dueRepaymentPeriodDate;
|
return dueRepaymentPeriodDate;
|
||||||
@@ -1249,7 +1247,7 @@ public final class LoanApplicationTerms {
|
|||||||
periodicInterestRate = oneDayOfYearInterestRate.multiply(numberOfDaysInPeriod, mc);
|
periodicInterestRate = oneDayOfYearInterestRate.multiply(numberOfDaysInPeriod, mc);
|
||||||
break;
|
break;
|
||||||
case WHOLE_TERM:
|
case WHOLE_TERM:
|
||||||
log.error("TODO Implement periodicInterestRate for WHOLE_TERM");
|
// TODO: Implement getPeriodEndDate for WHOLE_TERM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1533,8 +1531,8 @@ public final class LoanApplicationTerms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LoanProductRelatedDetail toLoanProductRelatedDetail() {
|
public LoanProductRelatedDetail toLoanProductRelatedDetail() {
|
||||||
final MonetaryCurrency currency = new MonetaryCurrency(this.currency.getCode(), this.currency.getDecimalPlaces(),
|
final CurrencyData currency = new CurrencyData(this.currency.getCode(), this.currency.getDecimalPlaces(),
|
||||||
this.currency.getCurrencyInMultiplesOf());
|
this.currency.getInMultiplesOf());
|
||||||
|
|
||||||
return LoanProductRelatedDetail.createFrom(currency, this.principal.getAmount(), this.interestRatePerPeriod,
|
return LoanProductRelatedDetail.createFrom(currency, this.principal.getAmount(), this.interestRatePerPeriod,
|
||||||
this.interestRatePeriodFrequencyType, this.annualNominalInterestRate, this.interestMethod,
|
this.interestRatePeriodFrequencyType, this.annualNominalInterestRate, this.interestMethod,
|
||||||
@@ -1548,6 +1546,15 @@ public final class LoanApplicationTerms {
|
|||||||
this.chargeOffBehaviour);
|
this.chargeOffBehaviour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanProductMinimumRepaymentScheduleRelatedDetail toLoanProductRelatedDetailMinimumData() {
|
||||||
|
final CurrencyData currency = new CurrencyData(this.currency.getCode(), this.currency.getDecimalPlaces(),
|
||||||
|
this.currency.getInMultiplesOf());
|
||||||
|
return new LoanProductRelatedDetailMinimumData(currency, principal, inArrearsTolerance, interestRatePerPeriod,
|
||||||
|
annualNominalInterestRate, interestChargingGrace, interestPaymentGrace, principalGrace,
|
||||||
|
recurringMoratoriumOnPrincipalPeriods, interestMethod, interestCalculationPeriodMethod, daysInYearType, daysInMonthType,
|
||||||
|
amortizationMethod, repaymentPeriodFrequencyType, repaymentEvery, numberOfRepayments);
|
||||||
|
}
|
||||||
|
|
||||||
public Integer getLoanTermFrequency() {
|
public Integer getLoanTermFrequency() {
|
||||||
return this.loanTermFrequency;
|
return this.loanTermFrequency;
|
||||||
}
|
}
|
||||||
@@ -1592,8 +1599,8 @@ public final class LoanApplicationTerms {
|
|||||||
return this.amortizationMethod;
|
return this.amortizationMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MonetaryCurrency getCurrency() {
|
public CurrencyData getCurrency() {
|
||||||
return this.principal.getCurrency();
|
return currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getNumberOfRepayments() {
|
public Integer getNumberOfRepayments() {
|
||||||
@@ -1787,10 +1794,6 @@ public final class LoanApplicationTerms {
|
|||||||
this.totalInterestDue = totalInterestDue;
|
this.totalInterestDue = totalInterestDue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplicationCurrency getApplicationCurrency() {
|
|
||||||
return this.currency;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
|
public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
|
||||||
return this.interestCalculationPeriodMethod;
|
return this.interestCalculationPeriodMethod;
|
||||||
}
|
}
|
||||||
@@ -2074,7 +2077,7 @@ public final class LoanApplicationTerms {
|
|||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
case WHOLE_TERM:
|
case WHOLE_TERM:
|
||||||
log.error("TODO Implement repaymentPeriodFrequencyType for WHOLE_TERM");
|
// TODO: Implement getPeriodEndDate for WHOLE_TERM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return maxDateForFixedLength;
|
return maxDateForFixedLength;
|
||||||
|
|||||||
+2
-2
@@ -22,11 +22,11 @@ import jakarta.validation.constraints.NotBlank;
|
|||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||||
|
|
||||||
public record LoanRepaymentScheduleModelData(@NotNull LocalDate scheduleGenerationStartDate, @NotNull ApplicationCurrency currency,
|
public record LoanRepaymentScheduleModelData(@NotNull LocalDate scheduleGenerationStartDate, @NotNull CurrencyData currency,
|
||||||
@NotNull BigDecimal disbursementAmount, @NotNull LocalDate disbursementDate, @NotNull int numberOfRepayments,
|
@NotNull BigDecimal disbursementAmount, @NotNull LocalDate disbursementDate, @NotNull int numberOfRepayments,
|
||||||
@NotNull int repaymentFrequency, @NotBlank String repaymentFrequencyType, @NotNull BigDecimal annualNominalInterestRate,
|
@NotNull int repaymentFrequency, @NotBlank String repaymentFrequencyType, @NotNull BigDecimal annualNominalInterestRate,
|
||||||
@NotNull boolean downPaymentEnabled, @NotNull DaysInMonthType daysInMonth, @NotNull DaysInYearType daysInYear,
|
@NotNull boolean downPaymentEnabled, @NotNull DaysInMonthType daysInMonth, @NotNull DaysInYearType daysInYear,
|
||||||
|
|||||||
+14
-21
@@ -23,7 +23,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||||
@@ -36,7 +35,7 @@ public final class LoanScheduleModel {
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final List<LoanScheduleModelPeriod> periods;
|
private final List<LoanScheduleModelPeriod> periods;
|
||||||
private final ApplicationCurrency applicationCurrency;
|
private final CurrencyData currency;
|
||||||
private final int loanTermInDays;
|
private final int loanTermInDays;
|
||||||
private final Money totalPrincipalDisbursed;
|
private final Money totalPrincipalDisbursed;
|
||||||
private final BigDecimal totalPrincipalExpected;
|
private final BigDecimal totalPrincipalExpected;
|
||||||
@@ -49,20 +48,19 @@ public final class LoanScheduleModel {
|
|||||||
private final BigDecimal totalRepaymentExpected;
|
private final BigDecimal totalRepaymentExpected;
|
||||||
private final BigDecimal totalOutstanding;
|
private final BigDecimal totalOutstanding;
|
||||||
|
|
||||||
public static LoanScheduleModel from(final List<LoanScheduleModelPeriod> periods, final ApplicationCurrency applicationCurrency,
|
public static LoanScheduleModel from(final List<LoanScheduleModelPeriod> periods, final CurrencyData currency, final int loanTermInDays,
|
||||||
final int loanTermInDays, final Money principalDisbursed, final BigDecimal totalPrincipalExpected,
|
final Money principalDisbursed, final BigDecimal totalPrincipalExpected, final BigDecimal totalPrincipalPaid,
|
||||||
final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged,
|
final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged,
|
||||||
final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
||||||
|
|
||||||
return new LoanScheduleModel(periods, applicationCurrency, loanTermInDays, principalDisbursed, totalPrincipalExpected,
|
return new LoanScheduleModel(periods, currency, loanTermInDays, principalDisbursed, totalPrincipalExpected, totalPrincipalPaid,
|
||||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
|
totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected, totalOutstanding);
|
||||||
totalOutstanding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanScheduleModel withOverdueChargeUpdation(final List<LoanScheduleModelPeriod> periods,
|
public static LoanScheduleModel withOverdueChargeUpdation(final List<LoanScheduleModelPeriod> periods,
|
||||||
final LoanScheduleModel loanScheduleModel, final BigDecimal totalPenaltyChargesCharged) {
|
final LoanScheduleModel loanScheduleModel, final BigDecimal totalPenaltyChargesCharged) {
|
||||||
|
|
||||||
return new LoanScheduleModel(periods, loanScheduleModel.applicationCurrency, loanScheduleModel.loanTermInDays,
|
return new LoanScheduleModel(periods, loanScheduleModel.currency, loanScheduleModel.loanTermInDays,
|
||||||
loanScheduleModel.totalPrincipalDisbursed, loanScheduleModel.totalPrincipalExpected, loanScheduleModel.totalPrincipalPaid,
|
loanScheduleModel.totalPrincipalDisbursed, loanScheduleModel.totalPrincipalExpected, loanScheduleModel.totalPrincipalPaid,
|
||||||
loanScheduleModel.totalInterestCharged, loanScheduleModel.totalFeeChargesCharged, totalPenaltyChargesCharged,
|
loanScheduleModel.totalInterestCharged, loanScheduleModel.totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||||
loanScheduleModel.totalRepaymentExpected, loanScheduleModel.totalOutstanding);
|
loanScheduleModel.totalRepaymentExpected, loanScheduleModel.totalOutstanding);
|
||||||
@@ -71,18 +69,18 @@ public final class LoanScheduleModel {
|
|||||||
public static LoanScheduleModel withLoanScheduleModelPeriods(final List<LoanScheduleModelPeriod> periods,
|
public static LoanScheduleModel withLoanScheduleModelPeriods(final List<LoanScheduleModelPeriod> periods,
|
||||||
final LoanScheduleModel loanScheduleModel) {
|
final LoanScheduleModel loanScheduleModel) {
|
||||||
|
|
||||||
return new LoanScheduleModel(periods, loanScheduleModel.applicationCurrency, loanScheduleModel.loanTermInDays,
|
return new LoanScheduleModel(periods, loanScheduleModel.currency, loanScheduleModel.loanTermInDays,
|
||||||
loanScheduleModel.totalPrincipalDisbursed, loanScheduleModel.totalPrincipalExpected, loanScheduleModel.totalPrincipalPaid,
|
loanScheduleModel.totalPrincipalDisbursed, loanScheduleModel.totalPrincipalExpected, loanScheduleModel.totalPrincipalPaid,
|
||||||
loanScheduleModel.totalInterestCharged, loanScheduleModel.totalFeeChargesCharged,
|
loanScheduleModel.totalInterestCharged, loanScheduleModel.totalFeeChargesCharged,
|
||||||
loanScheduleModel.totalPenaltyChargesCharged, loanScheduleModel.totalRepaymentExpected, loanScheduleModel.totalOutstanding);
|
loanScheduleModel.totalPenaltyChargesCharged, loanScheduleModel.totalRepaymentExpected, loanScheduleModel.totalOutstanding);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanScheduleModel(final List<LoanScheduleModelPeriod> periods, final ApplicationCurrency applicationCurrency,
|
private LoanScheduleModel(final List<LoanScheduleModelPeriod> periods, final CurrencyData currency, final int loanTermInDays,
|
||||||
final int loanTermInDays, final Money principalDisbursed, final BigDecimal totalPrincipalExpected,
|
final Money principalDisbursed, final BigDecimal totalPrincipalExpected, final BigDecimal totalPrincipalPaid,
|
||||||
final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged,
|
final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged,
|
||||||
final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
||||||
this.periods = periods;
|
this.periods = periods;
|
||||||
this.applicationCurrency = applicationCurrency;
|
this.currency = currency;
|
||||||
this.loanTermInDays = loanTermInDays;
|
this.loanTermInDays = loanTermInDays;
|
||||||
this.totalPrincipalDisbursed = principalDisbursed;
|
this.totalPrincipalDisbursed = principalDisbursed;
|
||||||
this.totalPrincipalExpected = totalPrincipalExpected;
|
this.totalPrincipalExpected = totalPrincipalExpected;
|
||||||
@@ -95,11 +93,6 @@ public final class LoanScheduleModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LoanScheduleData toData() {
|
public LoanScheduleData toData() {
|
||||||
|
|
||||||
final int decimalPlaces = this.totalPrincipalDisbursed.getCurrencyDigitsAfterDecimal();
|
|
||||||
final Integer inMultiplesOf = this.totalPrincipalDisbursed.getCurrencyInMultiplesOf();
|
|
||||||
final CurrencyData currency = this.applicationCurrency.toData(decimalPlaces, inMultiplesOf);
|
|
||||||
|
|
||||||
final BigDecimal totalCredits = BigDecimal.ZERO;
|
final BigDecimal totalCredits = BigDecimal.ZERO;
|
||||||
|
|
||||||
final List<LoanSchedulePeriodData> periodsData = new ArrayList<>();
|
final List<LoanSchedulePeriodData> periodsData = new ArrayList<>();
|
||||||
|
|||||||
+3
-3
@@ -19,7 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
|
|
||||||
public class ScheduleCurrentPeriodParams {
|
public class ScheduleCurrentPeriodParams {
|
||||||
@@ -36,11 +36,11 @@ public class ScheduleCurrentPeriodParams {
|
|||||||
boolean isEmiAmountChanged;
|
boolean isEmiAmountChanged;
|
||||||
BigDecimal interestCalculationGraceOnRepaymentPeriodFraction;
|
BigDecimal interestCalculationGraceOnRepaymentPeriodFraction;
|
||||||
|
|
||||||
ScheduleCurrentPeriodParams(final MonetaryCurrency currency) {
|
ScheduleCurrentPeriodParams(final CurrencyData currency) {
|
||||||
this(currency, BigDecimal.ZERO);
|
this(currency, BigDecimal.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleCurrentPeriodParams(final MonetaryCurrency currency, BigDecimal interestCalculationGraceOnRepaymentPeriodFraction) {
|
ScheduleCurrentPeriodParams(final CurrencyData currency, BigDecimal interestCalculationGraceOnRepaymentPeriodFraction) {
|
||||||
this.earlyPaidAmount = Money.zero(currency);
|
this.earlyPaidAmount = Money.zero(currency);
|
||||||
this.lastInstallment = null;
|
this.lastInstallment = null;
|
||||||
this.skipCurrentLoop = false;
|
this.skipCurrentLoop = false;
|
||||||
|
|||||||
-118
@@ -1,118 +0,0 @@
|
|||||||
/**
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
|
||||||
|
|
||||||
public final class LoanRescheduleModel {
|
|
||||||
|
|
||||||
private final Collection<LoanRescheduleModelRepaymentPeriod> periods;
|
|
||||||
private final Collection<LoanRepaymentScheduleHistory> oldPeriods;
|
|
||||||
private final ApplicationCurrency applicationCurrency;
|
|
||||||
private final int loanTermInDays;
|
|
||||||
private final Money totalPrincipalDisbursed;
|
|
||||||
private final BigDecimal totalPrincipalExpected;
|
|
||||||
private final BigDecimal totalPrincipalPaid;
|
|
||||||
private final BigDecimal totalInterestCharged;
|
|
||||||
private final BigDecimal totalFeeChargesCharged;
|
|
||||||
private final BigDecimal totalPenaltyChargesCharged;
|
|
||||||
private final BigDecimal totalRepaymentExpected;
|
|
||||||
private final BigDecimal totalOutstanding;
|
|
||||||
|
|
||||||
private LoanRescheduleModel(final Collection<LoanRescheduleModelRepaymentPeriod> periods,
|
|
||||||
final Collection<LoanRepaymentScheduleHistory> oldPeriods, final ApplicationCurrency applicationCurrency,
|
|
||||||
final int loanTermInDays, final Money principalDisbursed, final BigDecimal totalPrincipalExpected,
|
|
||||||
final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged,
|
|
||||||
final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
|
||||||
this.periods = periods;
|
|
||||||
this.oldPeriods = oldPeriods;
|
|
||||||
this.applicationCurrency = applicationCurrency;
|
|
||||||
this.loanTermInDays = loanTermInDays;
|
|
||||||
this.totalPrincipalDisbursed = principalDisbursed;
|
|
||||||
this.totalPrincipalExpected = totalPrincipalExpected;
|
|
||||||
this.totalPrincipalPaid = totalPrincipalPaid;
|
|
||||||
this.totalInterestCharged = totalInterestCharged;
|
|
||||||
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
|
||||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
|
||||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
|
||||||
this.totalOutstanding = totalOutstanding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LoanRescheduleModel instance(final Collection<LoanRescheduleModelRepaymentPeriod> periods,
|
|
||||||
final Collection<LoanRepaymentScheduleHistory> oldPeriods, final ApplicationCurrency applicationCurrency,
|
|
||||||
final int loanTermInDays, final Money principalDisbursed, final BigDecimal totalPrincipalExpected,
|
|
||||||
final BigDecimal totalPrincipalPaid, final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged,
|
|
||||||
final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected, final BigDecimal totalOutstanding) {
|
|
||||||
|
|
||||||
return new LoanRescheduleModel(periods, oldPeriods, applicationCurrency, loanTermInDays, principalDisbursed, totalPrincipalExpected,
|
|
||||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
|
|
||||||
totalOutstanding);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LoanRescheduleModel createWithSchedulehistory(LoanRescheduleModel loanRescheduleModel,
|
|
||||||
final Collection<LoanRepaymentScheduleHistory> oldPeriods) {
|
|
||||||
|
|
||||||
return new LoanRescheduleModel(loanRescheduleModel.periods, oldPeriods, loanRescheduleModel.applicationCurrency,
|
|
||||||
loanRescheduleModel.loanTermInDays, loanRescheduleModel.totalPrincipalDisbursed, loanRescheduleModel.totalPrincipalExpected,
|
|
||||||
loanRescheduleModel.totalPrincipalPaid, loanRescheduleModel.totalInterestCharged,
|
|
||||||
loanRescheduleModel.totalFeeChargesCharged, loanRescheduleModel.totalPenaltyChargesCharged,
|
|
||||||
loanRescheduleModel.totalRepaymentExpected, loanRescheduleModel.totalOutstanding);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanScheduleData toData() {
|
|
||||||
|
|
||||||
final int decimalPlaces = this.totalPrincipalDisbursed.getCurrencyDigitsAfterDecimal();
|
|
||||||
final Integer inMultiplesOf = this.totalPrincipalDisbursed.getCurrencyInMultiplesOf();
|
|
||||||
final CurrencyData currency = this.applicationCurrency.toData(decimalPlaces, inMultiplesOf);
|
|
||||||
|
|
||||||
final BigDecimal totalCredits = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
final Collection<LoanSchedulePeriodData> periodsData = new ArrayList<>();
|
|
||||||
for (final LoanRescheduleModalPeriod modelPeriod : this.periods) {
|
|
||||||
periodsData.add(modelPeriod.toData());
|
|
||||||
}
|
|
||||||
|
|
||||||
final BigDecimal totalWaived = null;
|
|
||||||
final BigDecimal totalWrittenOff = null;
|
|
||||||
final BigDecimal totalRepayment = null;
|
|
||||||
final BigDecimal totalPaidInAdvance = null;
|
|
||||||
final BigDecimal totalPaidLate = null;
|
|
||||||
|
|
||||||
return new LoanScheduleData(currency, periodsData, this.loanTermInDays, this.totalPrincipalDisbursed.getAmount(),
|
|
||||||
this.totalPrincipalExpected, this.totalPrincipalPaid, this.totalInterestCharged, this.totalFeeChargesCharged,
|
|
||||||
this.totalPenaltyChargesCharged, totalWaived, totalWrittenOff, this.totalRepaymentExpected, totalRepayment,
|
|
||||||
totalPaidInAdvance, totalPaidLate, this.totalOutstanding, totalCredits);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<LoanRescheduleModelRepaymentPeriod> getPeriods() {
|
|
||||||
return this.periods;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<LoanRepaymentScheduleHistory> getOldPeriods() {
|
|
||||||
return this.oldPeriods;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+186
@@ -0,0 +1,186 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.loanproduct.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
|
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||||
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
|
|
||||||
|
public class LoanProductRelatedDetailMinimumData implements LoanProductMinimumRepaymentScheduleRelatedDetail {
|
||||||
|
|
||||||
|
private final CurrencyData currency;
|
||||||
|
|
||||||
|
private final Money principal;
|
||||||
|
private final Money inArrearsTolerance;
|
||||||
|
|
||||||
|
private final BigDecimal interestRatePerPeriod;
|
||||||
|
private final BigDecimal annualNominalInterestRate;
|
||||||
|
|
||||||
|
private final Integer interestChargingGrace;
|
||||||
|
private final Integer interestPaymentGrace;
|
||||||
|
private final Integer principalGrace;
|
||||||
|
private final Integer recurringMoratoriumOnPrincipalPeriods;
|
||||||
|
|
||||||
|
private final InterestMethod interestMethod;
|
||||||
|
private final InterestCalculationPeriodMethod interestCalculationPeriodMethod;
|
||||||
|
|
||||||
|
private final DaysInYearType daysInYearType;
|
||||||
|
private final DaysInMonthType daysInMonthType;
|
||||||
|
|
||||||
|
private final AmortizationMethod amortizationMethod;
|
||||||
|
|
||||||
|
private final PeriodFrequencyType repaymentPeriodFrequencyType;
|
||||||
|
private final Integer repaymentEvery;
|
||||||
|
private final Integer numberOfRepayments;
|
||||||
|
|
||||||
|
public LoanProductRelatedDetailMinimumData(CurrencyData currency, Money principal, Money inArrearsTolerance,
|
||||||
|
BigDecimal interestRatePerPeriod, BigDecimal annualNominalInterestRate, Integer interestChargingGrace,
|
||||||
|
Integer interestPaymentGrace, Integer principalGrace, Integer recurringMoratoriumOnPrincipalPeriods,
|
||||||
|
InterestMethod interestMethod, InterestCalculationPeriodMethod interestCalculationPeriodMethod, DaysInYearType daysInYearType,
|
||||||
|
DaysInMonthType daysInMonthType, AmortizationMethod amortizationMethod, PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||||
|
Integer repaymentEvery, Integer numberOfRepayments) {
|
||||||
|
this.currency = currency;
|
||||||
|
this.principal = principal;
|
||||||
|
this.inArrearsTolerance = inArrearsTolerance;
|
||||||
|
this.interestRatePerPeriod = interestRatePerPeriod;
|
||||||
|
this.annualNominalInterestRate = annualNominalInterestRate;
|
||||||
|
this.interestChargingGrace = defaultToNullIfZero(interestChargingGrace);
|
||||||
|
this.interestPaymentGrace = defaultToNullIfZero(interestPaymentGrace);
|
||||||
|
this.principalGrace = defaultToNullIfZero(principalGrace);
|
||||||
|
this.recurringMoratoriumOnPrincipalPeriods = recurringMoratoriumOnPrincipalPeriods;
|
||||||
|
this.interestMethod = interestMethod;
|
||||||
|
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
|
||||||
|
this.daysInYearType = daysInYearType;
|
||||||
|
this.daysInMonthType = daysInMonthType;
|
||||||
|
this.amortizationMethod = amortizationMethod;
|
||||||
|
this.repaymentPeriodFrequencyType = repaymentPeriodFrequencyType;
|
||||||
|
this.repaymentEvery = repaymentEvery;
|
||||||
|
this.numberOfRepayments = numberOfRepayments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer defaultToNullIfZero(final Integer value) {
|
||||||
|
Integer defaultTo = value;
|
||||||
|
if (Integer.valueOf(0).equals(value)) {
|
||||||
|
defaultTo = null;
|
||||||
|
}
|
||||||
|
return defaultTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CurrencyData getCurrencyData() {
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Money getPrincipal() {
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getGraceOnInterestCharged() {
|
||||||
|
return interestChargingGrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getGraceOnInterestPayment() {
|
||||||
|
return interestPaymentGrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getGraceOnPrincipalPayment() {
|
||||||
|
return principalGrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getRecurringMoratoriumOnPrincipalPeriods() {
|
||||||
|
return recurringMoratoriumOnPrincipalPeriods;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Money getInArrearsTolerance() {
|
||||||
|
return inArrearsTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getNominalInterestRatePerPeriod() {
|
||||||
|
return interestRatePerPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeriodFrequencyType getInterestPeriodFrequencyType() {
|
||||||
|
return repaymentPeriodFrequencyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getAnnualNominalInterestRate() {
|
||||||
|
return annualNominalInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InterestMethod getInterestMethod() {
|
||||||
|
return interestMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
|
||||||
|
return interestCalculationPeriodMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getRepayEvery() {
|
||||||
|
return repaymentEvery;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeriodFrequencyType getRepaymentPeriodFrequencyType() {
|
||||||
|
return repaymentPeriodFrequencyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getNumberOfRepayments() {
|
||||||
|
return numberOfRepayments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AmortizationMethod getAmortizationMethod() {
|
||||||
|
return amortizationMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getGraceOnArrearsAgeing() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getDaysInMonthType() {
|
||||||
|
return daysInMonthType.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getDaysInYearType() {
|
||||||
|
return daysInYearType.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-2
@@ -19,7 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
|||||||
*/
|
*/
|
||||||
public interface LoanProductMinimumRepaymentScheduleRelatedDetail {
|
public interface LoanProductMinimumRepaymentScheduleRelatedDetail {
|
||||||
|
|
||||||
MonetaryCurrency getCurrency();
|
CurrencyData getCurrencyData();
|
||||||
|
|
||||||
Money getPrincipal();
|
Money getPrincipal();
|
||||||
|
|
||||||
@@ -61,4 +61,8 @@ public interface LoanProductMinimumRepaymentScheduleRelatedDetail {
|
|||||||
AmortizationMethod getAmortizationMethod();
|
AmortizationMethod getAmortizationMethod();
|
||||||
|
|
||||||
Integer getGraceOnArrearsAgeing();
|
Integer getGraceOnArrearsAgeing();
|
||||||
|
|
||||||
|
Integer getDaysInMonthType();
|
||||||
|
|
||||||
|
Integer getDaysInYearType();
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -31,6 +31,7 @@ import java.util.Map;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
@@ -164,7 +165,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private LoanChargeOffBehaviour chargeOffBehaviour;
|
private LoanChargeOffBehaviour chargeOffBehaviour;
|
||||||
|
|
||||||
public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal,
|
public static LoanProductRelatedDetail createFrom(final CurrencyData currencyData, final BigDecimal principal,
|
||||||
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
|
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
|
||||||
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
|
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
|
||||||
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion,
|
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion,
|
||||||
@@ -179,6 +180,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
final boolean enableAccrualActivityPosting, final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
|
final boolean enableAccrualActivityPosting, final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
|
||||||
final LoanChargeOffBehaviour chargeOffBehaviour) {
|
final LoanChargeOffBehaviour chargeOffBehaviour) {
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = MonetaryCurrency.fromCurrencyData(currencyData);
|
||||||
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
|
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
|
||||||
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
|
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
|
||||||
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, graceOnPrincipalPayment,
|
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, graceOnPrincipalPayment,
|
||||||
@@ -252,19 +254,23 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
|||||||
return defaultTo;
|
return defaultTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public MonetaryCurrency getCurrency() {
|
public MonetaryCurrency getCurrency() {
|
||||||
return this.currency.copy();
|
return this.currency.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CurrencyData getCurrencyData() {
|
||||||
|
return currency.toData();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Money getPrincipal() {
|
public Money getPrincipal() {
|
||||||
return Money.of(this.currency, this.principal);
|
return Money.of(getCurrencyData(), this.principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Money getInArrearsTolerance() {
|
public Money getInArrearsTolerance() {
|
||||||
return Money.of(this.currency, this.inArrearsTolerance);
|
return Money.of(getCurrencyData(), this.inArrearsTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: REVIEW
|
// TODO: REVIEW
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# Fineract Progressive Loan Embeddable Schedule Generator
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
- Generate Embeddable Progressive Schedule Generator Jar
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./gradlew :fineract-progressive-loan-embeddable-schedule-generator:shadowJar
|
||||||
|
```
|
||||||
|
|
||||||
|
- Copy Jar from `fineract-progressive-loan-embeddable-schedule-generator/build/libs/fineract-progressive-loan-embeddable-schedule-generator-*-SNAPSHOT-all.jar` to Your class path.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
There is no extra dependency.
|
||||||
|
|
||||||
|
|
||||||
|
## Sample Application
|
||||||
|
|
||||||
|
Copy a [Main.java](misc/Main.java) file from the `misc` directory into the working directory:
|
||||||
|
|
||||||
|
The project directory structure:
|
||||||
|
|
||||||
|
- `Main.java`
|
||||||
|
- `fineract-embeddable-calculator-1.11.0-SNAPSHOT-all.jar`
|
||||||
|
|
||||||
|
|
||||||
|
- Check Java minimum version
|
||||||
|
|
||||||
|
```shell
|
||||||
|
java -version # openjdk version "17.0.3" 2022-04-19 LTS
|
||||||
|
```
|
||||||
|
|
||||||
|
- Compile the source
|
||||||
|
|
||||||
|
```shell
|
||||||
|
javac -cp fineract-progressive-loan-embeddable-schedule-generator-1.11.0-SNAPSHOT-all.jar Main.java
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run with dependencies:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
java -cp fineract-progressive-loan-embeddable-schedule-generator-1.11.0-SNAPSHOT-all.jar:. Main
|
||||||
|
```
|
||||||
|
|
||||||
|
This code has the following output:
|
||||||
|
|
||||||
|
```
|
||||||
|
#------ Loan Schedule -----------------#
|
||||||
|
Number of Periods: 6
|
||||||
|
Loan Term in Days: 182
|
||||||
|
Total Disbursed Amount: 100.00
|
||||||
|
Total Interest Amount: 2.05
|
||||||
|
Total Repayment Amount: 102.05
|
||||||
|
#------ Repayment Schedule ------------#
|
||||||
|
Disbursement - Date: 2024-01-01, Amount: 100.00
|
||||||
|
Repayment Period: #1, Due Date: 2024-02-01, Balance: 83.57, Principal: 16.43, Interest: 0.58, Total: 17.01
|
||||||
|
Repayment Period: #2, Due Date: 2024-03-01, Balance: 67.05, Principal: 16.52, Interest: 0.49, Total: 17.01
|
||||||
|
Repayment Period: #3, Due Date: 2024-04-01, Balance: 50.43, Principal: 16.62, Interest: 0.39, Total: 17.01
|
||||||
|
Repayment Period: #4, Due Date: 2024-05-01, Balance: 33.71, Principal: 16.72, Interest: 0.29, Total: 17.01
|
||||||
|
Repayment Period: #5, Due Date: 2024-06-01, Balance: 16.90, Principal: 16.81, Interest: 0.20, Total: 17.01
|
||||||
|
Repayment Period: #6, Due Date: 2024-07-01, Balance: 0.00, Principal: 16.90, Interest: 0.10, Total: 17.00
|
||||||
|
```
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
description = 'Fineract Progressive Loan Embeddable Schedule Generator'
|
||||||
|
|
||||||
|
apply plugin: 'com.gradleup.shadow'
|
||||||
|
apply plugin: 'java'
|
||||||
|
apply from: 'dependencies.gradle'
|
||||||
|
|
||||||
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
|
|
||||||
|
var requiredModuleNames = [
|
||||||
|
'fineract-core',
|
||||||
|
'fineract-loan',
|
||||||
|
'fineract-progressive-loan',
|
||||||
|
]
|
||||||
|
|
||||||
|
tasks.named('shadowJar', ShadowJar) {
|
||||||
|
dependencies {
|
||||||
|
exclude((dep) -> !requiredModuleNames.any( (reqModName) -> dep.moduleName.contains(reqModName)))
|
||||||
|
}
|
||||||
|
minimize() {
|
||||||
|
exclude("*.xml")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(path: ':fineract-progressive-loan'))
|
||||||
|
implementation(project(path: ':fineract-loan'))
|
||||||
|
|
||||||
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
|
annotationProcessor 'org.mapstruct:mapstruct-processor'
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
|
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlanDisbursementPeriod;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlanDownPaymentPeriod;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlanPeriod;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlanRepaymentPeriod;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.EmbeddableProgressiveLoanScheduleGenerator;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleModelData;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.MathContext;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: This file used by a CI job to test Progressive Loan Embedded Jar compiled successfully and runs smoothly.
|
||||||
|
*/
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
MathContext mc = new MathContext(12, RoundingMode.HALF_UP);
|
||||||
|
EmbeddableProgressiveLoanScheduleGenerator calculator = new EmbeddableProgressiveLoanScheduleGenerator();
|
||||||
|
|
||||||
|
final CurrencyData currency = new CurrencyData("usd", "US Dollar", 2, null, "usd", "$");
|
||||||
|
final LocalDate startDate = LocalDate.of(2024, 1, 1);
|
||||||
|
final LocalDate disbursementDate = LocalDate.of(2024, 1, 1);
|
||||||
|
final BigDecimal disbursedAmount = BigDecimal.valueOf(100);
|
||||||
|
|
||||||
|
final int noRepayments = 6;
|
||||||
|
final int repaymentFrequency = 1;
|
||||||
|
final String repaymentFrequencyType = "MONTHS";
|
||||||
|
final BigDecimal downPaymentPercentage = args.length > 0 ? new BigDecimal(args[0]) : BigDecimal.ZERO;
|
||||||
|
final boolean isDownPaymentEnabled = BigDecimal.ZERO.compareTo(downPaymentPercentage) != 0;
|
||||||
|
final BigDecimal annualNominalInterestRate = BigDecimal.valueOf(7.0);
|
||||||
|
final DaysInMonthType daysInMonthType = DaysInMonthType.DAYS_30;
|
||||||
|
final DaysInYearType daysInYearType = DaysInYearType.DAYS_360;
|
||||||
|
final Integer installmentAmountInMultiplesOf = null;
|
||||||
|
final Integer fixedLength = null;
|
||||||
|
|
||||||
|
var config = new LoanRepaymentScheduleModelData(startDate, currency, disbursedAmount, disbursementDate, noRepayments, repaymentFrequency, repaymentFrequencyType, annualNominalInterestRate, isDownPaymentEnabled, daysInMonthType, daysInYearType, downPaymentPercentage, installmentAmountInMultiplesOf, fixedLength);
|
||||||
|
|
||||||
|
final LoanSchedulePlan plan = calculator.generate(mc, config);
|
||||||
|
printPlan(plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printPlan(final LoanSchedulePlan plan) throws InterruptedException {
|
||||||
|
System.out.println("#------ Loan Schedule -----------------#");
|
||||||
|
System.out.printf(" Number of Periods: %d%n", plan.getPeriods().stream().filter(period -> !(period instanceof LoanSchedulePlanDisbursementPeriod)).count());
|
||||||
|
System.out.printf(" Loan Term in Days: %d%n", plan.getLoanTermInDays());
|
||||||
|
System.out.printf(" Total Disbursed Amount: %s%n", plan.getTotalDisbursedAmount());
|
||||||
|
System.out.printf(" Total Interest Amount: %s%n", plan.getTotalInterestAmount());
|
||||||
|
System.out.printf(" Total Repayment Amount: %s%n", plan.getTotalRepaymentAmount());
|
||||||
|
System.out.println("#------ Repayment Schedule ------------#");
|
||||||
|
|
||||||
|
for (LoanSchedulePlanPeriod period : plan.getPeriods()) {
|
||||||
|
if (period instanceof LoanSchedulePlanDisbursementPeriod dp) {
|
||||||
|
System.out.printf(" Disbursement - Date: %s, Amount: %s%n", dp.periodDueDate(), dp.getPrincipalAmount());
|
||||||
|
} if (period instanceof LoanSchedulePlanDownPaymentPeriod rp) {
|
||||||
|
System.out.printf(" Down payment Period: #%d, Due Date: %s, Balance: %s, Principal: %s, Total: %s%n", rp.periodNumber(), rp.periodDueDate(), rp.getOutstandingLoanBalance(), rp.getPrincipalAmount(), rp.getTotalDueAmount());
|
||||||
|
} if (period instanceof LoanSchedulePlanRepaymentPeriod rp) {
|
||||||
|
System.out.printf(" Repayment Period: #%d, Due Date: %s, Balance: %s, Principal: %s, Interest: %s, Total: %s%n", rp.periodNumber(), rp.periodDueDate(), rp.getOutstandingLoanBalance(), rp.getPrincipalAmount(), rp.getInterestAmount(), rp.getTotalDueAmount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||||
|
|
||||||
|
import java.math.MathContext;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlan;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.calc.ProgressiveEMICalculator;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class EmbeddableProgressiveLoanScheduleGenerator {
|
||||||
|
|
||||||
|
private final ProgressiveLoanScheduleGenerator scheduleGenerator;
|
||||||
|
private final ScheduledDateGenerator scheduledDateGenerator;
|
||||||
|
private final EMICalculator emiCalculator;
|
||||||
|
|
||||||
|
public EmbeddableProgressiveLoanScheduleGenerator() {
|
||||||
|
this.emiCalculator = new ProgressiveEMICalculator();
|
||||||
|
this.scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
||||||
|
this.scheduleGenerator = new ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanSchedulePlan generate(final MathContext mc, final LoanRepaymentScheduleModelData modelData) {
|
||||||
|
return scheduleGenerator.generate(mc, modelData);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -48,7 +48,7 @@ public class ProgressiveTransactionCtx extends TransactionCtx {
|
|||||||
Set<LoanCharge> charges, MoneyHolder overpaymentHolder, ChangedTransactionDetail changedTransactionDetail,
|
Set<LoanCharge> charges, MoneyHolder overpaymentHolder, ChangedTransactionDetail changedTransactionDetail,
|
||||||
ProgressiveLoanInterestScheduleModel model) {
|
ProgressiveLoanInterestScheduleModel model) {
|
||||||
super(currency, installments, charges, overpaymentHolder, changedTransactionDetail);
|
super(currency, installments, charges, overpaymentHolder, changedTransactionDetail);
|
||||||
sumOfInterestRefundAmount = model.getZero();
|
sumOfInterestRefundAmount = model.zero();
|
||||||
this.model = model;
|
this.model = model;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -91,7 +91,7 @@ public class InterestPeriod implements Comparable<InterestPeriod> {
|
|||||||
.multipliedBy(getRateFactorTillPeriodDueDate(), mc).getAmount() //
|
.multipliedBy(getRateFactorTillPeriodDueDate(), mc).getAmount() //
|
||||||
.divide(BigDecimal.valueOf(lengthTillPeriodDueDate), mc) //
|
.divide(BigDecimal.valueOf(lengthTillPeriodDueDate), mc) //
|
||||||
.multiply(BigDecimal.valueOf(getLength()), mc); //
|
.multiply(BigDecimal.valueOf(getLength()), mc); //
|
||||||
return Money.of(outstandingLoanBalance.getCurrency(), interestDueTillRepaymentDueDate, mc);
|
return Money.of(outstandingLoanBalance.getCurrencyData(), interestDueTillRepaymentDueDate, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLength() {
|
public long getLength() {
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ public class LoanSchedulePlan {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return new LoanSchedulePlan(periods, //
|
return new LoanSchedulePlan(periods, //
|
||||||
model.getApplicationCurrency().toData(), //
|
model.getCurrency(), //
|
||||||
model.getLoanTermInDays(), //
|
model.getLoanTermInDays(), //
|
||||||
model.getTotalPrincipalDisbursed().getAmount(), //
|
model.getTotalPrincipalDisbursed().getAmount(), //
|
||||||
model.getTotalPrincipalExpected(), //
|
model.getTotalPrincipalExpected(), //
|
||||||
|
|||||||
+17
-16
@@ -34,7 +34,7 @@ import lombok.Data;
|
|||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Accessors(fluent = true)
|
@Accessors(fluent = true)
|
||||||
@@ -42,26 +42,31 @@ public class ProgressiveLoanInterestScheduleModel {
|
|||||||
|
|
||||||
private final List<RepaymentPeriod> repaymentPeriods;
|
private final List<RepaymentPeriod> repaymentPeriods;
|
||||||
private final TreeSet<InterestRate> interestRates;
|
private final TreeSet<InterestRate> interestRates;
|
||||||
private final LoanProductRelatedDetail loanProductRelatedDetail;
|
private final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail;
|
||||||
private final Integer installmentAmountInMultiplesOf;
|
private final Integer installmentAmountInMultiplesOf;
|
||||||
private MathContext mc;
|
private final MathContext mc;
|
||||||
|
private final Money zero;
|
||||||
|
|
||||||
public ProgressiveLoanInterestScheduleModel(List<RepaymentPeriod> repaymentPeriods, LoanProductRelatedDetail loanProductRelatedDetail,
|
public ProgressiveLoanInterestScheduleModel(final List<RepaymentPeriod> repaymentPeriods,
|
||||||
Integer installmentAmountInMultiplesOf, MathContext mc) {
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf,
|
||||||
|
final MathContext mc) {
|
||||||
this.repaymentPeriods = repaymentPeriods;
|
this.repaymentPeriods = repaymentPeriods;
|
||||||
this.interestRates = new TreeSet<>(Collections.reverseOrder());
|
this.interestRates = new TreeSet<>(Collections.reverseOrder());
|
||||||
this.loanProductRelatedDetail = loanProductRelatedDetail;
|
this.loanProductRelatedDetail = loanProductRelatedDetail;
|
||||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||||
this.mc = mc;
|
this.mc = mc;
|
||||||
|
this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProgressiveLoanInterestScheduleModel(List<RepaymentPeriod> repaymentPeriods, final TreeSet<InterestRate> interestRates,
|
private ProgressiveLoanInterestScheduleModel(final List<RepaymentPeriod> repaymentPeriods, final TreeSet<InterestRate> interestRates,
|
||||||
LoanProductRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf, MathContext mc) {
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf,
|
||||||
|
final MathContext mc) {
|
||||||
this.mc = mc;
|
this.mc = mc;
|
||||||
this.repaymentPeriods = copyRepaymentPeriods(repaymentPeriods);
|
this.repaymentPeriods = copyRepaymentPeriods(repaymentPeriods);
|
||||||
this.interestRates = new TreeSet<>(interestRates);
|
this.interestRates = new TreeSet<>(interestRates);
|
||||||
this.loanProductRelatedDetail = loanProductRelatedDetail;
|
this.loanProductRelatedDetail = loanProductRelatedDetail;
|
||||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||||
|
this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgressiveLoanInterestScheduleModel deepCopy(MathContext mc) {
|
public ProgressiveLoanInterestScheduleModel deepCopy(MathContext mc) {
|
||||||
@@ -197,30 +202,26 @@ public class ProgressiveLoanInterestScheduleModel {
|
|||||||
previousInterestPeriod.addDisbursementAmount(disbursedAmount);
|
previousInterestPeriod.addDisbursementAmount(disbursedAmount);
|
||||||
previousInterestPeriod.addBalanceCorrectionAmount(correctionAmount);
|
previousInterestPeriod.addBalanceCorrectionAmount(correctionAmount);
|
||||||
final InterestPeriod interestPeriod = new InterestPeriod(repaymentPeriod, previousInterestPeriod.getDueDate(), originalDueDate,
|
final InterestPeriod interestPeriod = new InterestPeriod(repaymentPeriod, previousInterestPeriod.getDueDate(), originalDueDate,
|
||||||
BigDecimal.ZERO, BigDecimal.ZERO, getZero(), getZero(), getZero(), mc);
|
BigDecimal.ZERO, BigDecimal.ZERO, zero, zero, zero, mc);
|
||||||
repaymentPeriod.getInterestPeriods().add(interestPeriod);
|
repaymentPeriod.getInterestPeriods().add(interestPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getZero() {
|
|
||||||
return Money.zero(loanProductRelatedDetail.getCurrency(), mc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getTotalDueInterest() {
|
public Money getTotalDueInterest() {
|
||||||
return repaymentPeriods().stream().flatMap(rp -> rp.getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest))
|
return repaymentPeriods().stream().flatMap(rp -> rp.getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest))
|
||||||
.reduce(getZero(), Money::plus);
|
.reduce(zero(), Money::plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getTotalDuePrincipal() {
|
public Money getTotalDuePrincipal() {
|
||||||
return repaymentPeriods.stream().flatMap(rp -> rp.getInterestPeriods().stream().map(InterestPeriod::getDisbursementAmount))
|
return repaymentPeriods.stream().flatMap(rp -> rp.getInterestPeriods().stream().map(InterestPeriod::getDisbursementAmount))
|
||||||
.reduce(getZero(), Money::plus);
|
.reduce(zero(), Money::plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getTotalPaidInterest() {
|
public Money getTotalPaidInterest() {
|
||||||
return repaymentPeriods().stream().map(RepaymentPeriod::getPaidInterest).reduce(getZero(), Money::plus);
|
return repaymentPeriods().stream().map(RepaymentPeriod::getPaidInterest).reduce(zero, Money::plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getTotalPaidPrincipal() {
|
public Money getTotalPaidPrincipal() {
|
||||||
return repaymentPeriods().stream().map(RepaymentPeriod::getPaidPrincipal).reduce(getZero(), Money::plus);
|
return repaymentPeriods().stream().map(RepaymentPeriod::getPaidPrincipal).reduce(zero, Money::plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<RepaymentPeriod> findRepaymentPeriod(@NotNull LocalDate transactionDate) {
|
public Optional<RepaymentPeriod> findRepaymentPeriod(@NotNull LocalDate transactionDate) {
|
||||||
|
|||||||
+12
-16
@@ -31,9 +31,8 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||||
@@ -55,7 +54,6 @@ import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RepaymentStartDateType;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||||
@@ -72,11 +70,10 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
|||||||
public LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
public LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
||||||
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO) {
|
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO) {
|
||||||
|
|
||||||
final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency();
|
|
||||||
// determine the total charges due at time of disbursement
|
// determine the total charges due at time of disbursement
|
||||||
final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loanCharges);
|
final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loanCharges);
|
||||||
|
|
||||||
final MonetaryCurrency currency = loanApplicationTerms.getCurrency();
|
final CurrencyData currency = loanApplicationTerms.getCurrency();
|
||||||
LocalDate periodStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
LocalDate periodStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
||||||
? loanApplicationTerms.getExpectedDisbursementDate()
|
? loanApplicationTerms.getExpectedDisbursementDate()
|
||||||
: loanApplicationTerms.getSubmittedOnDate();
|
: loanApplicationTerms.getSubmittedOnDate();
|
||||||
@@ -92,7 +89,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
|||||||
final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods = scheduledDateGenerator.generateRepaymentPeriods(mc,
|
final List<LoanScheduleModelRepaymentPeriod> expectedRepaymentPeriods = scheduledDateGenerator.generateRepaymentPeriods(mc,
|
||||||
periodStartDate, loanApplicationTerms, holidayDetailDTO);
|
periodStartDate, loanApplicationTerms, holidayDetailDTO);
|
||||||
final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanApplicationTerms.toLoanProductRelatedDetail(),
|
expectedRepaymentPeriods, loanApplicationTerms.toLoanProductRelatedDetailMinimumData(),
|
||||||
loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc);
|
loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc);
|
||||||
final List<LoanScheduleModelPeriod> periods = new ArrayList<>(expectedRepaymentPeriods.size());
|
final List<LoanScheduleModelPeriod> periods = new ArrayList<>(expectedRepaymentPeriods.size());
|
||||||
|
|
||||||
@@ -141,7 +138,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
|||||||
final BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
|
final BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
|
||||||
final BigDecimal totalOutstanding = BigDecimal.ZERO;
|
final BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||||
|
|
||||||
return LoanScheduleModel.from(periods, applicationCurrency, interestScheduleModel.getLoanTermInDays(),
|
return LoanScheduleModel.from(periods, currency, interestScheduleModel.getLoanTermInDays(),
|
||||||
scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount(), mc),
|
scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount(), mc),
|
||||||
scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount(), mc).getAmount(),
|
scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount(), mc).getAmount(),
|
||||||
totalPrincipalPaid, scheduleParams.getTotalCumulativeInterest().getAmount(),
|
totalPrincipalPaid, scheduleParams.getTotalCumulativeInterest().getAmount(),
|
||||||
@@ -308,7 +305,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void applyChargesForCurrentPeriod(final LoanScheduleModelRepaymentPeriod repaymentPeriod, final Set<LoanCharge> loanCharges,
|
private void applyChargesForCurrentPeriod(final LoanScheduleModelRepaymentPeriod repaymentPeriod, final Set<LoanCharge> loanCharges,
|
||||||
final LoanScheduleParams scheduleParams, final MonetaryCurrency currency, final MathContext mc) {
|
final LoanScheduleParams scheduleParams, final CurrencyData currency, final MathContext mc) {
|
||||||
final PrincipalInterest principalInterest = new PrincipalInterest(repaymentPeriod.getPrincipalDue(),
|
final PrincipalInterest principalInterest = new PrincipalInterest(repaymentPeriod.getPrincipalDue(),
|
||||||
repaymentPeriod.getInterestDue(), null);
|
repaymentPeriod.getInterestDue(), null);
|
||||||
|
|
||||||
@@ -325,10 +322,10 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
|
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
|
||||||
final MonetaryCurrency monetaryCurrency, final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed,
|
final CurrencyData currency, final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed,
|
||||||
final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod,
|
final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod,
|
||||||
final MathContext mc) {
|
final MathContext mc) {
|
||||||
Money cumulative = Money.zero(monetaryCurrency, mc);
|
Money cumulative = Money.zero(currency, mc);
|
||||||
if (loanCharges != null) {
|
if (loanCharges != null) {
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
if (!loanCharge.isDueAtDisbursement() && loanCharge.isFeeCharge()) {
|
if (!loanCharge.isDueAtDisbursement() && loanCharge.isFeeCharge()) {
|
||||||
@@ -358,11 +355,10 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency monetaryCurrency,
|
final Set<LoanCharge> loanCharges, final CurrencyData currency, final PrincipalInterest principalInterestForThisPeriod,
|
||||||
final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed,
|
final Money principalDisbursed, final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable,
|
||||||
final Money totalInterestChargedForFullLoanTerm, boolean isInstallmentChargeApplicable, final boolean isFirstPeriod,
|
final boolean isFirstPeriod, final MathContext mc) {
|
||||||
final MathContext mc) {
|
Money cumulative = Money.zero(currency, mc);
|
||||||
Money cumulative = Money.zero(monetaryCurrency, mc);
|
|
||||||
if (loanCharges != null) {
|
if (loanCharges != null) {
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
if (loanCharge.isPenaltyCharge()) {
|
if (loanCharge.isPenaltyCharge()) {
|
||||||
@@ -409,7 +405,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
|||||||
return cumulative;
|
return cumulative;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePeriodsWithCharges(final MonetaryCurrency currency, LoanScheduleParams scheduleParams,
|
private void updatePeriodsWithCharges(final CurrencyData currency, LoanScheduleParams scheduleParams,
|
||||||
final Collection<LoanScheduleModelPeriod> periods, final Set<LoanCharge> nonCompoundingCharges, MathContext mc) {
|
final Collection<LoanScheduleModelPeriod> periods, final Set<LoanCharge> nonCompoundingCharges, MathContext mc) {
|
||||||
for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
|
for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
|
||||||
if (loanScheduleModelPeriod.isRepaymentPeriod()) {
|
if (loanScheduleModelPeriod.isRepaymentPeriod()) {
|
||||||
|
|||||||
+6
-4
@@ -31,18 +31,20 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.PeriodDueDeta
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.RepaymentPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.RepaymentPeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
|
|
||||||
public interface EMICalculator {
|
public interface EMICalculator {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
ProgressiveLoanInterestScheduleModel generatePeriodInterestScheduleModel(@NotNull List<LoanScheduleModelRepaymentPeriod> periods,
|
ProgressiveLoanInterestScheduleModel generatePeriodInterestScheduleModel(@NotNull List<LoanScheduleModelRepaymentPeriod> periods,
|
||||||
@NotNull LoanProductRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf, MathContext mc);
|
@NotNull LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf,
|
||||||
|
MathContext mc);
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
ProgressiveLoanInterestScheduleModel generateInstallmentInterestScheduleModel(
|
ProgressiveLoanInterestScheduleModel generateInstallmentInterestScheduleModel(
|
||||||
@NotNull List<LoanRepaymentScheduleInstallment> installments, @NotNull LoanProductRelatedDetail loanProductRelatedDetail,
|
@NotNull List<LoanRepaymentScheduleInstallment> installments,
|
||||||
Integer installmentAmountInMultiplesOf, MathContext mc);
|
@NotNull LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail, Integer installmentAmountInMultiplesOf,
|
||||||
|
MathContext mc);
|
||||||
|
|
||||||
Optional<RepaymentPeriod> findRepaymentPeriod(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate dueDate);
|
Optional<RepaymentPeriod> findRepaymentPeriod(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate dueDate);
|
||||||
|
|
||||||
|
|||||||
+19
-19
@@ -43,7 +43,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.PeriodDueDeta
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.RepaymentPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.RepaymentPeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -56,8 +56,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public ProgressiveLoanInterestScheduleModel generatePeriodInterestScheduleModel(@NotNull List<LoanScheduleModelRepaymentPeriod> periods,
|
public ProgressiveLoanInterestScheduleModel generatePeriodInterestScheduleModel(@NotNull List<LoanScheduleModelRepaymentPeriod> periods,
|
||||||
@NotNull LoanProductRelatedDetail loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf,
|
@NotNull LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail,
|
||||||
final MathContext mc) {
|
final Integer installmentAmountInMultiplesOf, final MathContext mc) {
|
||||||
return generateInterestScheduleModel(periods, LoanScheduleModelRepaymentPeriod::periodFromDate,
|
return generateInterestScheduleModel(periods, LoanScheduleModelRepaymentPeriod::periodFromDate,
|
||||||
LoanScheduleModelRepaymentPeriod::periodDueDate, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
LoanScheduleModelRepaymentPeriod::periodDueDate, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public ProgressiveLoanInterestScheduleModel generateInstallmentInterestScheduleModel(
|
public ProgressiveLoanInterestScheduleModel generateInstallmentInterestScheduleModel(
|
||||||
@NotNull List<LoanRepaymentScheduleInstallment> installments, @NotNull LoanProductRelatedDetail loanProductRelatedDetail,
|
@NotNull List<LoanRepaymentScheduleInstallment> installments,
|
||||||
|
@NotNull LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail,
|
||||||
final Integer installmentAmountInMultiplesOf, final MathContext mc) {
|
final Integer installmentAmountInMultiplesOf, final MathContext mc) {
|
||||||
installments = installments.stream().filter(installment -> !installment.isDownPayment() && !installment.isAdditional()).toList();
|
installments = installments.stream().filter(installment -> !installment.isDownPayment() && !installment.isAdditional()).toList();
|
||||||
return generateInterestScheduleModel(installments, LoanRepaymentScheduleInstallment::getFromDate,
|
return generateInterestScheduleModel(installments, LoanRepaymentScheduleInstallment::getFromDate,
|
||||||
@@ -74,9 +75,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private <T> ProgressiveLoanInterestScheduleModel generateInterestScheduleModel(@NotNull List<T> periods, Function<T, LocalDate> from,
|
private <T> ProgressiveLoanInterestScheduleModel generateInterestScheduleModel(@NotNull List<T> periods, Function<T, LocalDate> from,
|
||||||
Function<T, LocalDate> to, @NotNull LoanProductRelatedDetail loanProductRelatedDetail,
|
Function<T, LocalDate> to, @NotNull LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail,
|
||||||
final Integer installmentAmountInMultiplesOf, final MathContext mc) {
|
final Integer installmentAmountInMultiplesOf, final MathContext mc) {
|
||||||
final Money zero = Money.zero(loanProductRelatedDetail.getCurrency(), mc);
|
final Money zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
|
||||||
final AtomicReference<RepaymentPeriod> prev = new AtomicReference<>();
|
final AtomicReference<RepaymentPeriod> prev = new AtomicReference<>();
|
||||||
List<RepaymentPeriod> repaymentPeriods = periods.stream().map(e -> {
|
List<RepaymentPeriod> repaymentPeriods = periods.stream().map(e -> {
|
||||||
RepaymentPeriod rp = new RepaymentPeriod(prev.get(), from.apply(e), to.apply(e), zero, mc);
|
RepaymentPeriod rp = new RepaymentPeriod(prev.get(), from.apply(e), to.apply(e), zero, mc);
|
||||||
@@ -101,7 +102,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
@Override
|
@Override
|
||||||
public void addDisbursement(final ProgressiveLoanInterestScheduleModel scheduleModel, final LocalDate disbursementDueDate,
|
public void addDisbursement(final ProgressiveLoanInterestScheduleModel scheduleModel, final LocalDate disbursementDueDate,
|
||||||
final Money disbursedAmount) {
|
final Money disbursedAmount) {
|
||||||
scheduleModel.changeOutstandingBalanceAndUpdateInterestPeriods(disbursementDueDate, disbursedAmount, scheduleModel.getZero())
|
scheduleModel.changeOutstandingBalanceAndUpdateInterestPeriods(disbursementDueDate, disbursedAmount, scheduleModel.zero())
|
||||||
.ifPresent((repaymentPeriod) -> calculateEMIValueAndRateFactors(
|
.ifPresent((repaymentPeriod) -> calculateEMIValueAndRateFactors(
|
||||||
getEffectiveRepaymentDueDate(scheduleModel, repaymentPeriod, disbursementDueDate), scheduleModel));
|
getEffectiveRepaymentDueDate(scheduleModel, repaymentPeriod, disbursementDueDate), scheduleModel));
|
||||||
}
|
}
|
||||||
@@ -127,8 +128,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
final LocalDate interestRateChangeEffectiveDate = newInterestSubmittedOnDate.minusDays(1);
|
final LocalDate interestRateChangeEffectiveDate = newInterestSubmittedOnDate.minusDays(1);
|
||||||
scheduleModel.addInterestRate(interestRateChangeEffectiveDate, newInterestRate);
|
scheduleModel.addInterestRate(interestRateChangeEffectiveDate, newInterestRate);
|
||||||
scheduleModel
|
scheduleModel
|
||||||
.changeOutstandingBalanceAndUpdateInterestPeriods(interestRateChangeEffectiveDate, scheduleModel.getZero(),
|
.changeOutstandingBalanceAndUpdateInterestPeriods(interestRateChangeEffectiveDate, scheduleModel.zero(),
|
||||||
scheduleModel.getZero())
|
scheduleModel.zero())
|
||||||
.ifPresent(repaymentPeriod -> calculateEMIValueAndRateFactors(
|
.ifPresent(repaymentPeriod -> calculateEMIValueAndRateFactors(
|
||||||
getEffectiveRepaymentDueDate(scheduleModel, repaymentPeriod, interestRateChangeEffectiveDate), scheduleModel));
|
getEffectiveRepaymentDueDate(scheduleModel, repaymentPeriod, interestRateChangeEffectiveDate), scheduleModel));
|
||||||
}
|
}
|
||||||
@@ -136,8 +137,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
@Override
|
@Override
|
||||||
public void addBalanceCorrection(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate balanceCorrectionDate,
|
public void addBalanceCorrection(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate balanceCorrectionDate,
|
||||||
Money balanceCorrectionAmount) {
|
Money balanceCorrectionAmount) {
|
||||||
scheduleModel
|
scheduleModel.changeOutstandingBalanceAndUpdateInterestPeriods(balanceCorrectionDate, scheduleModel.zero(), balanceCorrectionAmount)
|
||||||
.changeOutstandingBalanceAndUpdateInterestPeriods(balanceCorrectionDate, scheduleModel.getZero(), balanceCorrectionAmount)
|
|
||||||
.ifPresent(repaymentPeriod -> {
|
.ifPresent(repaymentPeriod -> {
|
||||||
calculateRateFactorForRepaymentPeriod(repaymentPeriod, scheduleModel);
|
calculateRateFactorForRepaymentPeriod(repaymentPeriod, scheduleModel);
|
||||||
calculateOutstandingBalance(scheduleModel);
|
calculateOutstandingBalance(scheduleModel);
|
||||||
@@ -296,13 +296,13 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
|
|
||||||
private void calculateLastUnpaidRepaymentPeriodEMI(ProgressiveLoanInterestScheduleModel scheduleModel) {
|
private void calculateLastUnpaidRepaymentPeriodEMI(ProgressiveLoanInterestScheduleModel scheduleModel) {
|
||||||
MathContext mc = scheduleModel.mc();
|
MathContext mc = scheduleModel.mc();
|
||||||
Money totalDueInterest = scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getDueInterest)
|
Money totalDueInterest = scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getDueInterest).reduce(scheduleModel.zero(),
|
||||||
.reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc), (m1, m2) -> m1.plus(m2, mc)); // 1.46
|
(m1, m2) -> m1.plus(m2, mc)); // 1.46
|
||||||
Money totalEMI = scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getEmi)
|
Money totalEMI = scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getEmi).reduce(scheduleModel.zero(),
|
||||||
.reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc), (m1, m2) -> m1.plus(m2, mc)); // 101.48
|
(m1, m2) -> m1.plus(m2, mc)); // 101.48
|
||||||
Money totalDisbursedAmount = scheduleModel.repaymentPeriods().stream()
|
Money totalDisbursedAmount = scheduleModel.repaymentPeriods().stream()
|
||||||
.flatMap(rp -> rp.getInterestPeriods().stream().map(InterestPeriod::getDisbursementAmount))
|
.flatMap(rp -> rp.getInterestPeriods().stream().map(InterestPeriod::getDisbursementAmount))
|
||||||
.reduce(Money.zero(scheduleModel.loanProductRelatedDetail().getCurrency(), mc), (m1, m2) -> m1.plus(m2, mc)); // 100
|
.reduce(scheduleModel.zero(), (m1, m2) -> m1.plus(m2, mc)); // 100
|
||||||
|
|
||||||
Money diff = totalDisbursedAmount.plus(totalDueInterest, mc).minus(totalEMI, mc);
|
Money diff = totalDisbursedAmount.plus(totalDueInterest, mc).minus(totalEMI, mc);
|
||||||
Optional<RepaymentPeriod> findLastUnpaidRepaymentPeriod = scheduleModel.repaymentPeriods().stream().filter(rp -> !rp.isFullyPaid())
|
Optional<RepaymentPeriod> findLastUnpaidRepaymentPeriod = scheduleModel.repaymentPeriods().stream().filter(rp -> !rp.isFullyPaid())
|
||||||
@@ -400,7 +400,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
BigDecimal calculateRateFactorPerPeriod(final ProgressiveLoanInterestScheduleModel scheduleModel, final RepaymentPeriod repaymentPeriod,
|
BigDecimal calculateRateFactorPerPeriod(final ProgressiveLoanInterestScheduleModel scheduleModel, final RepaymentPeriod repaymentPeriod,
|
||||||
final LocalDate interestPeriodFromDate, final LocalDate interestPeriodDueDate) {
|
final LocalDate interestPeriodFromDate, final LocalDate interestPeriodDueDate) {
|
||||||
final MathContext mc = scheduleModel.mc();
|
final MathContext mc = scheduleModel.mc();
|
||||||
final LoanProductRelatedDetail loanProductRelatedDetail = scheduleModel.loanProductRelatedDetail();
|
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = scheduleModel.loanProductRelatedDetail();
|
||||||
final BigDecimal interestRate = calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriodFromDate),
|
final BigDecimal interestRate = calcNominalInterestRatePercentage(scheduleModel.getInterestRate(interestPeriodFromDate),
|
||||||
scheduleModel.mc());
|
scheduleModel.mc());
|
||||||
final DaysInYearType daysInYearType = DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType());
|
final DaysInYearType daysInYearType = DaysInYearType.fromInt(loanProductRelatedDetail.getDaysInYearType());
|
||||||
@@ -493,7 +493,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
// TODO: double check
|
// TODO: double check
|
||||||
final Money outstandingBalance = startPeriod.getInitialBalanceForEmiRecalculation();
|
final Money outstandingBalance = startPeriod.getInitialBalanceForEmiRecalculation();
|
||||||
|
|
||||||
final Money equalMonthlyInstallment = Money.of(outstandingBalance.getCurrency(),
|
final Money equalMonthlyInstallment = Money.of(outstandingBalance.getCurrencyData(),
|
||||||
calculateEMIValue(rateFactorN, outstandingBalance.getAmount(), fnResult, mc), mc);
|
calculateEMIValue(rateFactorN, outstandingBalance.getAmount(), fnResult, mc), mc);
|
||||||
final Money finalEqualMonthlyInstallment = applyInstallmentAmountInMultiplesOf(scheduleModel, equalMonthlyInstallment);
|
final Money finalEqualMonthlyInstallment = applyInstallmentAmountInMultiplesOf(scheduleModel, equalMonthlyInstallment);
|
||||||
|
|
||||||
@@ -732,7 +732,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
|||||||
return scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getDueDate) //
|
return scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getDueDate) //
|
||||||
.map(repaymentPeriodDueDate -> getDueAmounts(scheduleModel, repaymentPeriodDueDate, subjectDate) //
|
.map(repaymentPeriodDueDate -> getDueAmounts(scheduleModel, repaymentPeriodDueDate, subjectDate) //
|
||||||
.getDueInterest()) //
|
.getDueInterest()) //
|
||||||
.reduce(scheduleModel.getZero(), Money::add); //
|
.reduce(scheduleModel.zero(), Money::add); //
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getUncountablePeriods(final List<RepaymentPeriod> relatedRepaymentPeriods, final Money originalEmi) {
|
private long getUncountablePeriods(final List<RepaymentPeriod> relatedRepaymentPeriods, final Money originalEmi) {
|
||||||
|
|||||||
+1
-1
@@ -561,7 +561,7 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void calculateChargebackAllocationMap() {
|
public void calculateChargebackAllocationMap() {
|
||||||
Map<AllocationType, Money> result;
|
Map<AllocationType, Money> result;
|
||||||
MonetaryCurrency currency = mock(MonetaryCurrency.class);
|
MonetaryCurrency currency = new MonetaryCurrency("usd", 2, null);
|
||||||
|
|
||||||
result = underTest.calculateChargebackAllocationMap(allocationMap(50.0, 100.0, 200.0, 12.0, currency), BigDecimal.valueOf(50.0),
|
result = underTest.calculateChargebackAllocationMap(allocationMap(50.0, 100.0, 200.0, 12.0, currency), BigDecimal.valueOf(50.0),
|
||||||
List.of(PRINCIPAL, INTEREST, FEE, PENALTY), currency);
|
List.of(PRINCIPAL, INTEREST, FEE, PENALTY), currency);
|
||||||
|
|||||||
+4
-2
@@ -24,6 +24,7 @@ import java.math.BigDecimal;
|
|||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||||
@@ -38,6 +39,7 @@ class LoanScheduleGeneratorTest {
|
|||||||
|
|
||||||
private static final ProgressiveEMICalculator emiCalculator = new ProgressiveEMICalculator();
|
private static final ProgressiveEMICalculator emiCalculator = new ProgressiveEMICalculator();
|
||||||
private static final ApplicationCurrency APPLICATION_CURRENCY = new ApplicationCurrency("USD", "USD", 2, 1, "USD", "$");
|
private static final ApplicationCurrency APPLICATION_CURRENCY = new ApplicationCurrency("USD", "USD", 2, 1, "USD", "$");
|
||||||
|
private static final CurrencyData CURRENCY = APPLICATION_CURRENCY.toData();
|
||||||
private static final BigDecimal DISBURSEMENT_AMOUNT = BigDecimal.valueOf(192.22);
|
private static final BigDecimal DISBURSEMENT_AMOUNT = BigDecimal.valueOf(192.22);
|
||||||
private static final BigDecimal DISBURSEMENT_AMOUNT_100 = BigDecimal.valueOf(100);
|
private static final BigDecimal DISBURSEMENT_AMOUNT_100 = BigDecimal.valueOf(100);
|
||||||
private static final BigDecimal NOMINAL_INTEREST_RATE = BigDecimal.valueOf(9.99);
|
private static final BigDecimal NOMINAL_INTEREST_RATE = BigDecimal.valueOf(9.99);
|
||||||
@@ -50,7 +52,7 @@ class LoanScheduleGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGenerateLoanSchedule() {
|
void testGenerateLoanSchedule() {
|
||||||
LoanRepaymentScheduleModelData modelData = new LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), APPLICATION_CURRENCY,
|
LoanRepaymentScheduleModelData modelData = new LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), CURRENCY,
|
||||||
DISBURSEMENT_AMOUNT, DISBURSEMENT_DATE, NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
|
DISBURSEMENT_AMOUNT, DISBURSEMENT_DATE, NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
|
||||||
NOMINAL_INTEREST_RATE, false, DaysInMonthType.DAYS_30, DaysInYearType.DAYS_360, null, null, null);
|
NOMINAL_INTEREST_RATE, false, DaysInMonthType.DAYS_30, DaysInYearType.DAYS_360, null, null, null);
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ class LoanScheduleGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGenerateLoanScheduleWithDownPayment() {
|
void testGenerateLoanScheduleWithDownPayment() {
|
||||||
LoanRepaymentScheduleModelData modelData = new LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), APPLICATION_CURRENCY,
|
LoanRepaymentScheduleModelData modelData = new LoanRepaymentScheduleModelData(LocalDate.of(2024, 1, 1), CURRENCY,
|
||||||
DISBURSEMENT_AMOUNT_100, LocalDate.of(2024, 1, 1), NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
|
DISBURSEMENT_AMOUNT_100, LocalDate.of(2024, 1, 1), NUMBER_OF_REPAYMENTS, REPAYMENT_FREQUENCY, REPAYMENT_FREQUENCY_TYPE,
|
||||||
NOMINAL_INTEREST_RATE, true, DaysInMonthType.DAYS_30, DaysInYearType.DAYS_360, DOWN_PAYMENT_PORTION, null, null);
|
NOMINAL_INTEREST_RATE, true, DaysInMonthType.DAYS_30, DaysInYearType.DAYS_360, DOWN_PAYMENT_PORTION, null, null);
|
||||||
|
|
||||||
|
|||||||
+31
-32
@@ -26,8 +26,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
@@ -39,7 +38,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.PeriodDueDeta
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.ProgressiveLoanInterestScheduleModel;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.RepaymentPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.RepaymentPeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
@@ -59,10 +58,10 @@ class ProgressiveEMICalculatorTest {
|
|||||||
private static MockedStatic<ThreadLocalContextUtil> threadLocalContextUtil = Mockito.mockStatic(ThreadLocalContextUtil.class);
|
private static MockedStatic<ThreadLocalContextUtil> threadLocalContextUtil = Mockito.mockStatic(ThreadLocalContextUtil.class);
|
||||||
private static MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
|
private static MockedStatic<MoneyHelper> moneyHelper = Mockito.mockStatic(MoneyHelper.class);
|
||||||
private static MathContext mc = new MathContext(12, RoundingMode.HALF_EVEN);
|
private static MathContext mc = new MathContext(12, RoundingMode.HALF_EVEN);
|
||||||
private static LoanProductRelatedDetail loanProductRelatedDetail = Mockito.mock(LoanProductRelatedDetail.class);
|
private static LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = Mockito
|
||||||
|
.mock(LoanProductMinimumRepaymentScheduleRelatedDetail.class);
|
||||||
|
|
||||||
private static final MonetaryCurrency monetaryCurrency = MonetaryCurrency
|
private static final CurrencyData currency = new CurrencyData("USD", "USD", 2, 1, "$", "USD");
|
||||||
.fromApplicationCurrency(new ApplicationCurrency("USD", "USD", 2, 1, "USD", "$"));
|
|
||||||
|
|
||||||
private static List<LoanRepaymentScheduleInstallment> periods;
|
private static List<LoanRepaymentScheduleInstallment> periods;
|
||||||
private final BigDecimal interestRate = BigDecimal.valueOf(0.094822);
|
private final BigDecimal interestRate = BigDecimal.valueOf(0.094822);
|
||||||
@@ -166,7 +165,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 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(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)));
|
||||||
|
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -205,7 +204,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -249,7 +248,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -285,7 +284,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -321,7 +320,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -367,7 +366,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -403,7 +402,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
||||||
|
|
||||||
@@ -445,7 +444,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
||||||
|
|
||||||
@@ -492,7 +491,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
||||||
|
|
||||||
@@ -538,7 +537,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14));
|
||||||
|
|
||||||
@@ -584,7 +583,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
|
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
|
||||||
|
|
||||||
@@ -663,7 +662,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Assertions.assertEquals(0.1, toDouble(repaymentDetails4th.getDueInterest()));
|
Assertions.assertEquals(0.1, toDouble(repaymentDetails4th.getDueInterest()));
|
||||||
|
|
||||||
// balance update on the last period, check the right interest interval split
|
// balance update on the last period, check the right interest interval split
|
||||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 6, 10), Money.of(monetaryCurrency, BigDecimal.ZERO));
|
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 6, 10), Money.of(currency, BigDecimal.ZERO));
|
||||||
final RepaymentPeriod lastRepaymentPeriod = interestSchedule.repaymentPeriods().get(interestSchedule.repaymentPeriods().size() - 1);
|
final RepaymentPeriod lastRepaymentPeriod = interestSchedule.repaymentPeriods().get(interestSchedule.repaymentPeriods().size() - 1);
|
||||||
Assertions.assertEquals(2, lastRepaymentPeriod.getInterestPeriods().size());
|
Assertions.assertEquals(2, lastRepaymentPeriod.getInterestPeriods().size());
|
||||||
Assertions.assertEquals(LocalDate.of(2024, 6, 1), lastRepaymentPeriod.getInterestPeriods().get(0).getFromDate());
|
Assertions.assertEquals(LocalDate.of(2024, 6, 1), lastRepaymentPeriod.getInterestPeriods().get(0).getFromDate());
|
||||||
@@ -691,7 +690,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
|
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
|
||||||
|
|
||||||
@@ -762,7 +761,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
|
threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15));
|
||||||
|
|
||||||
@@ -841,7 +840,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -890,7 +889,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -939,7 +938,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -983,7 +982,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -1017,7 +1016,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -1050,7 +1049,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -1083,7 +1082,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.WEEKS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(2);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(2);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -1116,7 +1115,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.INVALID.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.DAYS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.DAYS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(15);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(15);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -1148,7 +1147,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -1210,7 +1209,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue());
|
||||||
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS);
|
||||||
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1);
|
||||||
Mockito.when(loanProductRelatedDetail.getCurrency()).thenReturn(monetaryCurrency);
|
Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency);
|
||||||
|
|
||||||
final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel(
|
final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel(
|
||||||
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc);
|
||||||
@@ -1266,7 +1265,7 @@ class ProgressiveEMICalculatorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static LoanScheduleModelRepaymentPeriod repayment(int periodNumber, LocalDate fromDate, LocalDate dueDate) {
|
private static LoanScheduleModelRepaymentPeriod repayment(int periodNumber, LocalDate fromDate, LocalDate dueDate) {
|
||||||
final Money zeroAmount = Money.zero(monetaryCurrency);
|
final Money zeroAmount = Money.zero(currency);
|
||||||
return LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, dueDate, zeroAmount, zeroAmount, zeroAmount, zeroAmount,
|
return LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, dueDate, zeroAmount, zeroAmount, zeroAmount, zeroAmount,
|
||||||
zeroAmount, zeroAmount, false, mc);
|
zeroAmount, zeroAmount, false, mc);
|
||||||
}
|
}
|
||||||
@@ -1326,6 +1325,6 @@ class ProgressiveEMICalculatorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Money toMoney(final double value) {
|
private static Money toMoney(final double value) {
|
||||||
return Money.of(monetaryCurrency, BigDecimal.valueOf(value));
|
return Money.of(currency, BigDecimal.valueOf(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -518,8 +518,8 @@ public class LoanScheduleAssembler {
|
|||||||
fixedLength = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.FIXED_LENGTH, element);
|
fixedLength = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.FIXED_LENGTH, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
return LoanApplicationTerms.assembleFrom(applicationCurrency.toData(), loanTermFrequency, loanTermPeriodFrequencyType,
|
||||||
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
||||||
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
||||||
allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
|
allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
|
||||||
calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods,
|
calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods,
|
||||||
|
|||||||
+1
-1
@@ -122,7 +122,7 @@ public class LoanUtilService {
|
|||||||
boolean isPrincipalCompoundingDisabledForOverdueLoans = this.configurationDomainService
|
boolean isPrincipalCompoundingDisabledForOverdueLoans = this.configurationDomainService
|
||||||
.isPrincipalCompoundingDisabledForOverdueLoans();
|
.isPrincipalCompoundingDisabledForOverdueLoans();
|
||||||
|
|
||||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency.toData(),
|
||||||
calculatedRepaymentsStartingFromDate, holidayDetails, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
calculatedRepaymentsStartingFromDate, holidayDetails, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||||
overdurPenaltyWaitPeriod, floatingRateDTO, calendar, calendarHistoryDataWrapper,
|
overdurPenaltyWaitPeriod, floatingRateDTO, calendar, calendarHistoryDataWrapper,
|
||||||
isInterestChargedFromDateAsDisbursementDateEnabled, numberOfDays, isSkipRepaymentOnFirstMonth,
|
isInterestChargedFromDateAsDisbursementDateEnabled, numberOfDays, isSkipRepaymentOnFirstMonth,
|
||||||
|
|||||||
+2
-8
@@ -106,7 +106,7 @@ public class LoanRepaymentBusinessEventSerializerTest {
|
|||||||
|
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
|
LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
|
||||||
MonetaryCurrency loanCurrency = Mockito.mock(MonetaryCurrency.class);
|
MonetaryCurrency loanCurrency = new MonetaryCurrency("CODE", 1, 1);
|
||||||
|
|
||||||
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
||||||
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
@@ -122,9 +122,6 @@ public class LoanRepaymentBusinessEventSerializerTest {
|
|||||||
when(loanForProcessing.getSummary()).thenReturn(loanSummary);
|
when(loanForProcessing.getSummary()).thenReturn(loanSummary);
|
||||||
when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.valueOf(0.0));
|
when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.valueOf(0.0));
|
||||||
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
|
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
|
||||||
when(loanCurrency.getCode()).thenReturn("CODE");
|
|
||||||
when(loanCurrency.getCurrencyInMultiplesOf()).thenReturn(1);
|
|
||||||
when(loanCurrency.getDigitsAfterDecimal()).thenReturn(1);
|
|
||||||
when(mapper.mapLocalDate(any())).thenReturn(loanInstallmentRepaymentDueDate.format(DateTimeFormatter.ISO_DATE));
|
when(mapper.mapLocalDate(any())).thenReturn(loanInstallmentRepaymentDueDate.format(DateTimeFormatter.ISO_DATE));
|
||||||
when(pastDueDataMapper.map(any())).thenReturn(pastDueAmount);
|
when(pastDueDataMapper.map(any())).thenReturn(pastDueAmount);
|
||||||
when(pastDueService.retrieveLoanRepaymentPastDueAmountTillDate(loanForProcessing)).thenReturn(null);
|
when(pastDueService.retrieveLoanRepaymentPastDueAmountTillDate(loanForProcessing)).thenReturn(null);
|
||||||
@@ -156,7 +153,7 @@ public class LoanRepaymentBusinessEventSerializerTest {
|
|||||||
|
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
|
LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
|
||||||
MonetaryCurrency loanCurrency = Mockito.mock(MonetaryCurrency.class);
|
MonetaryCurrency loanCurrency = new MonetaryCurrency("CODE", 1, 1);
|
||||||
|
|
||||||
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1,
|
||||||
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0),
|
||||||
@@ -173,9 +170,6 @@ public class LoanRepaymentBusinessEventSerializerTest {
|
|||||||
when(loanForProcessing.getSummary()).thenReturn(loanSummary);
|
when(loanForProcessing.getSummary()).thenReturn(loanSummary);
|
||||||
when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.valueOf(0.0));
|
when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.valueOf(0.0));
|
||||||
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
|
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
|
||||||
when(loanCurrency.getCode()).thenReturn("CODE");
|
|
||||||
when(loanCurrency.getCurrencyInMultiplesOf()).thenReturn(1);
|
|
||||||
when(loanCurrency.getDigitsAfterDecimal()).thenReturn(1);
|
|
||||||
when(mapper.mapLocalDate(any())).thenReturn(loanInstallmentRepaymentDueDate.format(DateTimeFormatter.ISO_DATE));
|
when(mapper.mapLocalDate(any())).thenReturn(loanInstallmentRepaymentDueDate.format(DateTimeFormatter.ISO_DATE));
|
||||||
when(pastDueDataMapper.map(any())).thenReturn(pastDueAmount);
|
when(pastDueDataMapper.map(any())).thenReturn(pastDueAmount);
|
||||||
when(pastDueService.retrieveLoanRepaymentPastDueAmountTillDate(loanForProcessing)).thenReturn(null);
|
when(pastDueService.retrieveLoanRepaymentPastDueAmountTillDate(loanForProcessing)).thenReturn(null);
|
||||||
|
|||||||
+9
-8
@@ -92,8 +92,8 @@ public class DefaultScheduledDateGeneratorTest {
|
|||||||
LocalDate dueRepaymentPeriodDate = LocalDate.of(2024, 2, 1);
|
LocalDate dueRepaymentPeriodDate = LocalDate.of(2024, 2, 1);
|
||||||
|
|
||||||
LocalDate submittedOnDate = LocalDate.of(2024, 1, 1);
|
LocalDate submittedOnDate = LocalDate.of(2024, 1, 1);
|
||||||
LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(dollarCurrency, 1, MONTHS, 4, 1, MONTHS, null,
|
LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(dollarCurrency.toData(), 1, MONTHS, 4, 1, MONTHS,
|
||||||
INVALID, EQUAL_PRINCIPAL, FLAT, ZERO, MONTHS, ZERO, SAME_AS_REPAYMENT_PERIOD, false, principalAmount,
|
null, INVALID, EQUAL_PRINCIPAL, FLAT, ZERO, MONTHS, ZERO, SAME_AS_REPAYMENT_PERIOD, false, principalAmount,
|
||||||
expectedDisbursementDate, null, dueRepaymentPeriodDate, null, null, null, null, null,
|
expectedDisbursementDate, null, dueRepaymentPeriodDate, null, null, null, null, null,
|
||||||
Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null, EMPTY_LIST, BigDecimal.valueOf(36_000L), null,
|
Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null, EMPTY_LIST, BigDecimal.valueOf(36_000L), null,
|
||||||
DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO, null, NONE, null, ZERO,
|
DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO, null, NONE, null, ZERO,
|
||||||
@@ -164,12 +164,13 @@ public class DefaultScheduledDateGeneratorTest {
|
|||||||
LocalDate expectedDisbursementDate = LocalDate.of(2023, 10, 26);
|
LocalDate expectedDisbursementDate = LocalDate.of(2023, 10, 26);
|
||||||
|
|
||||||
LocalDate submittedOnDate = LocalDate.of(2023, 10, 24);
|
LocalDate submittedOnDate = LocalDate.of(2023, 10, 24);
|
||||||
return LoanApplicationTerms.assembleFrom(dollarCurrency, 1, MONTHS, 1, 1, MONTHS, null, INVALID, EQUAL_PRINCIPAL, FLAT, ZERO,
|
return LoanApplicationTerms.assembleFrom(dollarCurrency.toData(), 1, MONTHS, 1, 1, MONTHS, null, INVALID, EQUAL_PRINCIPAL, FLAT,
|
||||||
MONTHS, ZERO, SAME_AS_REPAYMENT_PERIOD, false, principalAmount, expectedDisbursementDate, null, dueRepaymentPeriodDate,
|
ZERO, MONTHS, ZERO, SAME_AS_REPAYMENT_PERIOD, false, principalAmount, expectedDisbursementDate, null,
|
||||||
null, null, null, null, null, Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null, EMPTY_LIST,
|
dueRepaymentPeriodDate, null, null, null, null, null, Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null,
|
||||||
BigDecimal.valueOf(36_000L), null, DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO,
|
EMPTY_LIST, BigDecimal.valueOf(36_000L), null, DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null,
|
||||||
null, NONE, null, ZERO, EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false, null, false,
|
null, ZERO, null, NONE, null, ZERO, EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false,
|
||||||
DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null, null);
|
null, false, DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HolidayDetailDTO createHolidayDTO() {
|
private HolidayDetailDTO createHolidayDTO() {
|
||||||
|
|||||||
+1
-4
@@ -80,7 +80,7 @@ public class LoanCalculateRepaymentPastDueServiceTest {
|
|||||||
// given
|
// given
|
||||||
LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
MonetaryCurrency loanCurrency = Mockito.mock(MonetaryCurrency.class);
|
MonetaryCurrency loanCurrency = new MonetaryCurrency("CODE", 1, 1);
|
||||||
// repayments
|
// repayments
|
||||||
|
|
||||||
// closed repayment
|
// closed repayment
|
||||||
@@ -111,9 +111,6 @@ public class LoanCalculateRepaymentPastDueServiceTest {
|
|||||||
repaymentInstallment_2, repaymentInstallment_upcoming);
|
repaymentInstallment_2, repaymentInstallment_upcoming);
|
||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepayments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepayments);
|
||||||
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
|
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
|
||||||
when(loanCurrency.getCode()).thenReturn("CODE");
|
|
||||||
when(loanCurrency.getCurrencyInMultiplesOf()).thenReturn(1);
|
|
||||||
when(loanCurrency.getDigitsAfterDecimal()).thenReturn(1);
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
LoanRepaymentPastDueData pastDueAmount = underTest.retrieveLoanRepaymentPastDueAmountTillDate(loanForProcessing);
|
LoanRepaymentPastDueData pastDueAmount = underTest.retrieveLoanRepaymentPastDueAmountTillDate(loanForProcessing);
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ include ':fineract-avro-schemas'
|
|||||||
include ':fineract-e2e-tests-core'
|
include ':fineract-e2e-tests-core'
|
||||||
include ':fineract-e2e-tests-runner'
|
include ':fineract-e2e-tests-runner'
|
||||||
include 'fineract-progressive-loan'
|
include 'fineract-progressive-loan'
|
||||||
|
include 'fineract-progressive-loan-embeddable-schedule-generator'
|
||||||
// NOTE: custom Docker image with all custom modules included
|
// NOTE: custom Docker image with all custom modules included
|
||||||
include ':custom:docker'
|
include ':custom:docker'
|
||||||
// NOTE: dynamically load custom modules with pattern "custom -> company -> category -> module"
|
// NOTE: dynamically load custom modules with pattern "custom -> company -> category -> module"
|
||||||
|
|||||||
Reference in New Issue
Block a user