FINERACT-1932: Add loan module (WIP)
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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 Loan'
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
check.dependsOn('cucumber')
|
||||
|
||||
compileJava.doLast {
|
||||
def mainSS = sourceSets.main
|
||||
def source = mainSS.java.classesDirectory.get()
|
||||
copy {
|
||||
from file("src/main/resources/jpa/loan/persistence.xml")
|
||||
into "${source}/META-INF/"
|
||||
}
|
||||
javaexec {
|
||||
description = 'Performs EclipseLink static weaving of entity classes'
|
||||
def target = source
|
||||
main 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave'
|
||||
args '-persistenceinfo', source, '-classpath', sourceSets.main.runtimeClasspath, source, target
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
}
|
||||
delete {
|
||||
delete "${source}/META-INF/persistence.xml"
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration for Swagger documentation generation task
|
||||
// https://github.com/swagger-api/swagger-core/tree/master/modules/swagger-gradle-plugin
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
|
||||
|
||||
configurations {
|
||||
providedRuntime // needed for Spring Boot executable WAR
|
||||
providedCompile
|
||||
compile() {
|
||||
exclude module: 'hibernate-entitymanager'
|
||||
exclude module: 'hibernate-validator'
|
||||
exclude module: 'activation'
|
||||
exclude module: 'bcmail-jdk14'
|
||||
exclude module: 'bcprov-jdk14'
|
||||
exclude module: 'bctsp-jdk14'
|
||||
exclude module: 'c3p0'
|
||||
exclude module: 'stax-api'
|
||||
exclude module: 'jaxb-api'
|
||||
exclude module: 'jaxb-impl'
|
||||
exclude module: 'jboss-logging'
|
||||
exclude module: 'itext-rtf'
|
||||
exclude module: 'classworlds'
|
||||
}
|
||||
runtime
|
||||
}
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
|
||||
// Configuration for the modernizer plugin
|
||||
// https://github.com/andygoossens/gradle-modernizer-plugin
|
||||
modernizer {
|
||||
ignoreClassNamePatterns = [
|
||||
'.*AbstractPersistableCustom',
|
||||
'.*EntityTables',
|
||||
'.*domain.*'
|
||||
]
|
||||
}
|
||||
|
||||
// If we are running Gradle within Eclipse to enhance classes with OpenJPA,
|
||||
// set the classes directory to point to Eclipse's default build directory
|
||||
if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') {
|
||||
sourceSets.main.java.outputDir = new File(rootProject.projectDir, "fineract-loan/bin/main")
|
||||
}
|
||||
|
||||
eclipse {
|
||||
project {
|
||||
buildCommand([ LaunchConfigHandle: "<project>/.externalToolBuilders/OpenJPA Enhance Builder.launch" ], 'org.eclipse.ui.externaltools.ExternalToolBuilder')
|
||||
}
|
||||
}
|
||||
|
||||
/* http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle */
|
||||
sourceSets.main.output.resourcesDir = sourceSets.main.java.outputDir
|
||||
sourceSets.test.output.resourcesDir = sourceSets.test.java.outputDir
|
||||
|
||||
if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
|
||||
sourceSets {
|
||||
test {
|
||||
java {
|
||||
exclude '**/core/boot/tests/**'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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 {
|
||||
// Never use "compile" scope, but make all dependencies either 'implementation', 'runtimeOnly' or 'testCompile'.
|
||||
// Note that we never use 'api', because Fineract at least currently is a simple monolithic application ("WAR"), not a library.
|
||||
// We also (normally should have) no need to ever use 'compileOnly'.
|
||||
|
||||
// implementation dependencies are directly used (compiled against) in src/main (and src/test)
|
||||
//
|
||||
implementation(project(path: ':fineract-core'))
|
||||
|
||||
implementation(
|
||||
'org.springframework.boot:spring-boot-starter-web',
|
||||
'org.springframework.boot:spring-boot-starter-security',
|
||||
'jakarta.ws.rs:jakarta.ws.rs-api',
|
||||
'org.glassfish.jersey.media:jersey-media-multipart',
|
||||
|
||||
'com.google.guava:guava',
|
||||
'com.google.code.gson:gson',
|
||||
|
||||
'org.apache.commons:commons-lang3',
|
||||
|
||||
'com.jayway.jsonpath:json-path',
|
||||
|
||||
'com.github.spotbugs:spotbugs-annotations',
|
||||
'io.swagger.core.v3:swagger-annotations',
|
||||
|
||||
'com.squareup.retrofit2:converter-gson',
|
||||
|
||||
'org.springdoc:springdoc-openapi-security',
|
||||
'org.mapstruct:mapstruct',
|
||||
|
||||
'io.github.resilience4j:resilience4j-spring-boot2',
|
||||
)
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.mapstruct:mapstruct-processor'
|
||||
implementation ('org.springframework.boot:spring-boot-starter-data-jpa') {
|
||||
exclude group: 'org.hibernate'
|
||||
}
|
||||
implementation('org.eclipse.persistence:org.eclipse.persistence.jpa') {
|
||||
exclude group: 'org.eclipse.persistence', module: 'jakarta.persistence'
|
||||
}
|
||||
// testCompile dependencies are ONLY used in src/test, not src/main.
|
||||
// Do NOT repeat dependencies which are ALREADY in implementation or runtimeOnly!
|
||||
//
|
||||
testImplementation( 'io.cucumber:cucumber-spring',
|
||||
'io.github.classgraph:classgraph',
|
||||
)
|
||||
testImplementation ('org.springframework.boot:spring-boot-starter-test') {
|
||||
exclude group: 'com.jayway.jsonpath', module: 'json-path'
|
||||
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
|
||||
exclude group: 'jakarta.activation'
|
||||
exclude group: 'javax.activation'
|
||||
exclude group: 'org.skyscreamer'
|
||||
}
|
||||
testImplementation ('org.mockito:mockito-inline')
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
package org.apache.fineract.cob.loan;
|
||||
|
||||
import org.apache.fineract.cob.COBBusinessStep;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
public interface LoanCOBBusinessStep extends COBBusinessStep<Loan> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
/**
|
||||
* 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.interoperation.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
|
||||
public final class MathUtil {
|
||||
|
||||
private MathUtil() {
|
||||
|
||||
}
|
||||
|
||||
public static Long nullToZero(Long value) {
|
||||
return nullToDefault(value, 0L);
|
||||
}
|
||||
|
||||
public static Long nullToDefault(Long value, Long def) {
|
||||
return value == null ? def : value;
|
||||
}
|
||||
|
||||
public static Long zeroToNull(Long value) {
|
||||
return isEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
/** @return parameter value or ZERO if it is negative */
|
||||
public static Long negativeToZero(Long value) {
|
||||
return isGreaterThanZero(value) ? value : 0L;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(Long value) {
|
||||
return value == null || value.equals(0L);
|
||||
}
|
||||
|
||||
public static boolean isGreaterThanZero(Long value) {
|
||||
return value != null && value > 0L;
|
||||
}
|
||||
|
||||
public static boolean isLessThanZero(Long value) {
|
||||
return value != null && value < 0L;
|
||||
}
|
||||
|
||||
public static boolean isZero(Long value) {
|
||||
return value != null && value.equals(0L);
|
||||
}
|
||||
|
||||
public static boolean isEqualTo(Long first, Long second) {
|
||||
return nullToZero(first).equals(nullToZero(second));
|
||||
}
|
||||
|
||||
public static boolean isGreaterThan(Long first, Long second) {
|
||||
return nullToZero(first) > nullToZero(second);
|
||||
}
|
||||
|
||||
public static boolean isLessThan(Long first, Long second) {
|
||||
return nullToZero(first) < nullToZero(second);
|
||||
}
|
||||
|
||||
public static boolean isGreaterThanOrEqualTo(Long first, Long second) {
|
||||
return nullToZero(first) >= nullToZero(second);
|
||||
}
|
||||
|
||||
public static boolean isLessThanOrEqualZero(Long value) {
|
||||
return nullToZero(value) <= 0L;
|
||||
}
|
||||
|
||||
/** @return parameter value or negated value to positive */
|
||||
public static Long abs(Long value) {
|
||||
return value == null ? 0L : Math.abs(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return calculates minimum of the two values considering null values
|
||||
* @param notNull
|
||||
* if true then null parameter is omitted, otherwise returns null
|
||||
*/
|
||||
public static Long min(Long first, Long second, boolean notNull) {
|
||||
if (first == null) {
|
||||
return notNull ? second : null;
|
||||
}
|
||||
if (second == null) {
|
||||
return notNull ? first : null;
|
||||
}
|
||||
return Math.min(first, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return calculates minimum of the values considering null values
|
||||
* @param notNull
|
||||
* if true then null parameter is omitted, otherwise returns null
|
||||
*/
|
||||
public static Long min(Long first, Long second, Long third, boolean notNull) {
|
||||
return min(min(first, second, notNull), third, notNull);
|
||||
}
|
||||
|
||||
/** @return sum the two values considering null values */
|
||||
public static Long add(Long first, Long second) {
|
||||
return first == null ? second : second == null ? first : Math.addExact(first, second);
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static Long add(Long first, Long second, Long third) {
|
||||
return add(add(first, second), third);
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static Long add(Long first, Long second, Long third, Long fourth) {
|
||||
return add(add(add(first, second), third), fourth);
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static Long add(Long first, Long second, Long third, Long fourth, Long fifth) {
|
||||
return add(add(add(add(first, second), third), fourth), fifth);
|
||||
}
|
||||
|
||||
/** @return first minus second considering null values, maybe negative */
|
||||
public static Long subtract(Long first, Long second) {
|
||||
return first == null ? null : second == null ? first : Math.subtractExact(first, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first minus the others considering null values, maybe negative
|
||||
*/
|
||||
public static Long subtractToZero(Long first, Long second, Long third) {
|
||||
return subtractToZero(subtract(first, second), third);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first minus the others considering null values, maybe negative
|
||||
*/
|
||||
public static Long subtractToZero(Long first, Long second, Long third, Long fourth) {
|
||||
return subtractToZero(subtract(subtract(first, second), third), fourth);
|
||||
}
|
||||
|
||||
/** @return NONE negative first minus second considering null values */
|
||||
public static Long subtractToZero(Long first, Long second) {
|
||||
return negativeToZero(subtract(first, second));
|
||||
}
|
||||
|
||||
/** @return BigDecimal null safe negate */
|
||||
public static Long negate(Long amount) {
|
||||
return isEmpty(amount) ? amount : Math.negateExact(amount);
|
||||
}
|
||||
|
||||
// ----------------- BigDecimal -----------------
|
||||
|
||||
public static BigDecimal nullToZero(BigDecimal value) {
|
||||
return nullToDefault(value, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
public static BigDecimal nullToDefault(BigDecimal value, BigDecimal def) {
|
||||
return value == null ? def : value;
|
||||
}
|
||||
|
||||
public static BigDecimal zeroToNull(BigDecimal value) {
|
||||
return isEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
/** @return parameter value or ZERO if it is negative */
|
||||
public static BigDecimal negativeToZero(BigDecimal value) {
|
||||
return isGreaterThanZero(value) ? value : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(BigDecimal value) {
|
||||
return value == null || BigDecimal.ZERO.compareTo(value) == 0;
|
||||
}
|
||||
|
||||
public static boolean isGreaterThanZero(BigDecimal value) {
|
||||
return value != null && value.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
public static boolean isLessThanZero(BigDecimal value) {
|
||||
return value != null && value.compareTo(BigDecimal.ZERO) < 0;
|
||||
}
|
||||
|
||||
public static boolean isZero(BigDecimal value) {
|
||||
return value != null && value.compareTo(BigDecimal.ZERO) == 0;
|
||||
}
|
||||
|
||||
public static boolean isEqualTo(BigDecimal first, BigDecimal second) {
|
||||
return nullToZero(first).compareTo(nullToZero(second)) == 0;
|
||||
}
|
||||
|
||||
public static boolean isGreaterThan(BigDecimal first, BigDecimal second) {
|
||||
return nullToZero(first).compareTo(nullToZero(second)) > 0;
|
||||
}
|
||||
|
||||
public static boolean isLessThan(BigDecimal first, BigDecimal second) {
|
||||
return nullToZero(first).compareTo(nullToZero(second)) < 0;
|
||||
}
|
||||
|
||||
public static boolean isGreaterThanOrEqualTo(BigDecimal first, BigDecimal second) {
|
||||
return nullToZero(first).compareTo(nullToZero(second)) >= 0;
|
||||
}
|
||||
|
||||
public static boolean isLessThanOrEqualZero(BigDecimal value) {
|
||||
return nullToZero(value).compareTo(BigDecimal.ZERO) <= 0;
|
||||
}
|
||||
|
||||
/** @return parameter value or negated value to positive */
|
||||
public static BigDecimal abs(BigDecimal value) {
|
||||
return value == null ? BigDecimal.ZERO : value.abs();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return calculates minimum of the two values considering null values
|
||||
* @param notNull
|
||||
* if true then null parameter is omitted, otherwise returns null
|
||||
*/
|
||||
public static BigDecimal min(BigDecimal first, BigDecimal second, boolean notNull) {
|
||||
return notNull ? first == null ? second : second == null ? first : min(first, second, false)
|
||||
: isLessThan(first, second) ? first : second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return calculates minimum of the values considering null values
|
||||
* @param notNull
|
||||
* if true then null parameter is omitted, otherwise returns null
|
||||
*/
|
||||
public static BigDecimal min(BigDecimal first, BigDecimal second, BigDecimal third, boolean notNull) {
|
||||
return min(min(first, second, notNull), third, notNull);
|
||||
}
|
||||
|
||||
/** @return sum the two values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second) {
|
||||
return add(first, second, MoneyHelper.getMathContext());
|
||||
}
|
||||
|
||||
/** @return sum the two values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second, MathContext mc) {
|
||||
return first == null ? second : second == null ? first : first.add(second, mc);
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third) {
|
||||
return add(first, second, third, MoneyHelper.getMathContext());
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, MathContext mc) {
|
||||
return add(add(first, second, mc), third, mc);
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
|
||||
return add(first, second, third, fourth, MoneyHelper.getMathContext());
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, MathContext mc) {
|
||||
return add(add(add(first, second, mc), third, mc), fourth, mc);
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth) {
|
||||
return add(first, second, third, fourth, fifth, MoneyHelper.getMathContext());
|
||||
}
|
||||
|
||||
/** @return sum the values considering null values */
|
||||
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth,
|
||||
MathContext mc) {
|
||||
return add(add(add(add(first, second, mc), third, mc), fourth, mc), fifth, mc);
|
||||
}
|
||||
|
||||
/** @return first minus second considering null values, maybe negative */
|
||||
public static BigDecimal subtract(BigDecimal first, BigDecimal second) {
|
||||
return subtract(first, second, MoneyHelper.getMathContext());
|
||||
}
|
||||
|
||||
/** @return first minus second considering null values, maybe negative */
|
||||
public static BigDecimal subtract(BigDecimal first, BigDecimal second, MathContext mc) {
|
||||
return first == null ? null : second == null ? first : first.subtract(second, mc);
|
||||
}
|
||||
|
||||
/** @return NONE negative first minus second considering null values */
|
||||
public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second) {
|
||||
return negativeToZero(subtract(first, second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first minus the others considering null values, maybe negative
|
||||
*/
|
||||
public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third) {
|
||||
return subtractToZero(subtract(first, second), third);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first minus the others considering null values, maybe negative
|
||||
*/
|
||||
public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
|
||||
return subtractToZero(subtract(subtract(first, second), third), fourth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency
|
||||
*/
|
||||
public static BigDecimal normalizeAmount(BigDecimal amount, @NotNull MonetaryCurrency currency) {
|
||||
return amount == null ? null : amount.setScale(currency.getDigitsAfterDecimal(), MoneyHelper.getRoundingMode());
|
||||
}
|
||||
|
||||
/** @return BigDecimal null safe negate */
|
||||
public static BigDecimal negate(BigDecimal amount) {
|
||||
return negate(amount, MoneyHelper.getMathContext());
|
||||
}
|
||||
|
||||
/** @return BigDecimal null safe negate */
|
||||
public static BigDecimal negate(BigDecimal amount, MathContext mc) {
|
||||
return isEmpty(amount) ? amount : amount.negate(mc);
|
||||
}
|
||||
|
||||
// ----------------- Money -----------------
|
||||
|
||||
public static Money nullToZero(Money value, @NotNull MonetaryCurrency currency) {
|
||||
return nullToDefault(value, Money.zero(currency));
|
||||
}
|
||||
|
||||
public static Money nullToDefault(Money value, Money def) {
|
||||
return value == null ? def : value;
|
||||
}
|
||||
|
||||
public static Money zeroToNull(Money value) {
|
||||
return isEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
/** @return parameter value or ZERO if it is negative */
|
||||
public static Money negativeToZero(Money value) {
|
||||
return value == null || isGreaterThanZero(value) ? value : Money.zero(value.getCurrency());
|
||||
}
|
||||
|
||||
public static boolean isEmpty(Money value) {
|
||||
return value == null || value.isZero();
|
||||
}
|
||||
|
||||
public static boolean isGreaterThanZero(Money value) {
|
||||
return value != null && value.isGreaterThanZero();
|
||||
}
|
||||
|
||||
public static boolean isLessThanZero(Money value) {
|
||||
return value != null && value.isLessThanZero();
|
||||
}
|
||||
|
||||
public static boolean isEqualTo(Money first, Money second) {
|
||||
return first == null ? second == null : (second != null && first.isEqualTo(second));
|
||||
}
|
||||
|
||||
public static boolean isGreaterThan(Money first, Money second) {
|
||||
return second == null || (first != null && first.isGreaterThan(second));
|
||||
}
|
||||
|
||||
public static boolean isLessThan(Money first, Money second) {
|
||||
return first == null || (second != null && first.isLessThan(second));
|
||||
}
|
||||
|
||||
public static Money plus(Money first, Money second) {
|
||||
return first == null ? second : second == null ? first : first.plus(second);
|
||||
}
|
||||
|
||||
public static Money plus(Money first, Money second, Money third) {
|
||||
return plus(plus(first, second), third);
|
||||
}
|
||||
|
||||
public static Money plus(Money first, Money second, Money third, Money fourth) {
|
||||
return plus(plus(plus(first, second), third), fourth);
|
||||
}
|
||||
|
||||
public static Money minus(Money first, Money second) {
|
||||
return first == null ? null : second == null ? first : first.minus(second);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first minus the others considering null values, maybe negative
|
||||
*/
|
||||
public static Money minusToZero(Money first, Money second, Money third) {
|
||||
return minusToZero(minus(first, second), third);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return first minus the others considering null values, maybe negative
|
||||
*/
|
||||
public static Money minusToZero(Money first, Money second, Money third, Money fourth) {
|
||||
return minusToZero(minus(minus(first, second), third), fourth);
|
||||
}
|
||||
|
||||
/** @return NONE negative first minus second considering null values */
|
||||
public static Money minusToZero(Money first, Money second) {
|
||||
return negativeToZero(minus(first, second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return calculates minimum of the two values considering null values
|
||||
* @param notNull
|
||||
* if true then null parameter is omitted, otherwise returns null
|
||||
*/
|
||||
public static Money min(Money first, Money second, boolean notNull) {
|
||||
return notNull ? first == null ? second : second == null ? first : min(first, second, false)
|
||||
: isLessThan(first, second) ? first : second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return calculates minimum of the values considering null values
|
||||
* @param notNull
|
||||
* if true then null parameter is omitted, otherwise returns null
|
||||
*/
|
||||
public static Money min(Money first, Money second, Money third, boolean notNull) {
|
||||
return min(min(first, second, notNull), third, notNull);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.charge.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* {@link AbstractPlatformDomainRuleException} thrown when currency mismatch occurs
|
||||
*/
|
||||
public class LoanChargeWithoutMandatoryFieldException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanChargeWithoutMandatoryFieldException(final String entity, final String postFix, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg." + entity + "." + postFix + ".cannot.be.blank", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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.collateral.api;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class CollateralApiConstants {
|
||||
|
||||
private CollateralApiConstants() {
|
||||
|
||||
}
|
||||
|
||||
public static final String COLLATERAL_CODE_NAME = "LoanCollateral";
|
||||
|
||||
/***
|
||||
* Enum of all parameters passed in while creating/updating a collateral
|
||||
***/
|
||||
public enum CollateralJSONinputParams {
|
||||
|
||||
LOAN_ID("loanId"), COLLATERAL_ID("collateralId"), COLLATERAL_TYPE_ID("collateralTypeId"), VALUE("value"), DESCRIPTION(
|
||||
"description");
|
||||
|
||||
private final String value;
|
||||
|
||||
CollateralJSONinputParams(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<>();
|
||||
|
||||
static {
|
||||
for (final CollateralJSONinputParams type : CollateralJSONinputParams.values()) {
|
||||
values.add(type.value);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getAllValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.collateral.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
|
||||
/**
|
||||
* Immutable data object for Collateral data.
|
||||
*/
|
||||
public final class CollateralData {
|
||||
|
||||
private final Long id;
|
||||
private final CodeValueData type;
|
||||
private final BigDecimal value;
|
||||
private final String description;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<CodeValueData> allowedCollateralTypes;
|
||||
private final CurrencyData currency;
|
||||
|
||||
public static CollateralData instance(final Long id, final CodeValueData type, final BigDecimal value, final String description,
|
||||
final CurrencyData currencyData) {
|
||||
return new CollateralData(id, type, value, description, currencyData);
|
||||
}
|
||||
|
||||
public static CollateralData template(final Collection<CodeValueData> codeValues) {
|
||||
return new CollateralData(null, null, null, null, null, codeValues);
|
||||
}
|
||||
|
||||
private CollateralData(final Long id, final CodeValueData type, final BigDecimal value, final String description,
|
||||
final CurrencyData currencyData) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.currency = currencyData;
|
||||
this.allowedCollateralTypes = null;
|
||||
}
|
||||
|
||||
private CollateralData(final Long id, final CodeValueData type, final BigDecimal value, final String description,
|
||||
final CurrencyData currencyData, final Collection<CodeValueData> allowedCollateralTypes) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.currency = currencyData;
|
||||
this.allowedCollateralTypes = allowedCollateralTypes;
|
||||
}
|
||||
|
||||
public CollateralData template(final CollateralData collateralData, final Collection<CodeValueData> codeValues) {
|
||||
return new CollateralData(collateralData.id, collateralData.type, collateralData.value, collateralData.description,
|
||||
collateralData.currency, codeValues);
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* 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.collateral.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.collateral.api.CollateralApiConstants.CollateralJSONinputParams;
|
||||
import org.apache.fineract.portfolio.collateral.data.CollateralData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_collateral")
|
||||
public class LoanCollateral extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "type_cv_id", nullable = false)
|
||||
private CodeValue type;
|
||||
|
||||
@Column(name = "value", scale = 6, precision = 19)
|
||||
private BigDecimal value;
|
||||
|
||||
@Column(name = "description", length = 500)
|
||||
private String description;
|
||||
|
||||
public static LoanCollateral from(final CodeValue collateralType, final BigDecimal value, final String description) {
|
||||
return new LoanCollateral(null, collateralType, value, description);
|
||||
}
|
||||
|
||||
protected LoanCollateral() {
|
||||
//
|
||||
}
|
||||
|
||||
private LoanCollateral(final Loan loan, final CodeValue collateralType, final BigDecimal value, final String description) {
|
||||
this.loan = loan;
|
||||
this.type = collateralType;
|
||||
this.value = value;
|
||||
this.description = StringUtils.defaultIfEmpty(description, null);
|
||||
}
|
||||
|
||||
public void assembleFrom(final CodeValue collateralType, final BigDecimal value, final String description) {
|
||||
this.type = collateralType;
|
||||
this.description = description;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void associateWith(final Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
public static LoanCollateral fromJson(final Loan loan, final CodeValue collateralType, final JsonCommand command) {
|
||||
final String description = command.stringValueOfParameterNamed(CollateralJSONinputParams.DESCRIPTION.getValue());
|
||||
final BigDecimal value = command.bigDecimalValueOfParameterNamed(CollateralJSONinputParams.VALUE.getValue());
|
||||
return new LoanCollateral(loan, collateralType, value, description);
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
|
||||
|
||||
final String collateralTypeIdParamName = CollateralJSONinputParams.COLLATERAL_TYPE_ID.getValue();
|
||||
if (command.isChangeInLongParameterNamed(collateralTypeIdParamName, this.type.getId())) {
|
||||
final Long newValue = command.longValueOfParameterNamed(collateralTypeIdParamName);
|
||||
actualChanges.put(collateralTypeIdParamName, newValue);
|
||||
}
|
||||
|
||||
final String descriptionParamName = CollateralJSONinputParams.DESCRIPTION.getValue();
|
||||
if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
|
||||
actualChanges.put(descriptionParamName, newValue);
|
||||
this.description = StringUtils.defaultIfEmpty(newValue, null);
|
||||
}
|
||||
|
||||
final String valueParamName = CollateralJSONinputParams.VALUE.getValue();
|
||||
if (command.isChangeInBigDecimalParameterNamed(valueParamName, this.value)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(valueParamName);
|
||||
actualChanges.put(valueParamName, newValue);
|
||||
this.value = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public CollateralData toData() {
|
||||
final CodeValueData typeData = this.type.toData();
|
||||
return CollateralData.instance(getId(), typeData, this.value, this.description, null);
|
||||
}
|
||||
|
||||
public void setCollateralType(final CodeValue type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
* @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (obj == this) { return
|
||||
* true; } if (obj.getClass() != getClass()) { return false; } final LoanCollateral rhs = (LoanCollateral) obj;
|
||||
* return new EqualsBuilder().appendSuper(super.equals(obj)) // .append(getId(), rhs.getId()) //
|
||||
* .append(this.type.getId(), rhs.type.getId()) // .append(this.description, rhs.description) // .append(this.value,
|
||||
* this.value)// .isEquals(); }
|
||||
*
|
||||
* @Override public int hashCode() { return new HashCodeBuilder(3, 5) // .append(getId()) //
|
||||
* .append(this.type.getId()) // .append(this.description) // .append(this.value)// .toHashCode(); }
|
||||
*/
|
||||
}
|
||||
+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.collateralmanagement.api;
|
||||
|
||||
public enum CollateralManagementJsonInputParams {
|
||||
|
||||
NAME("name"), QUALITY("quality"), BASE_PRICE("basePrice"), UNIT_TYPE("unitType"), PCT_TO_BASE("pctToBase"), CURRENCY(
|
||||
"currency"), COLLATERAL_PRODUCT_READ_PERMISSION("COLLATERAL_PRODUCT"), CLIENT_COLLATERAL_PRODUCT_READ_PERMISSION(
|
||||
"CLIENT_COLLATERAL_PRODUCT"), QUANTITY("quantity"), TOTAL_COLLATERAL_VALUE("totalCollateralValue");
|
||||
|
||||
private final String value;
|
||||
|
||||
CollateralManagementJsonInputParams(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* 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.collateralmanagement.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.collateralmanagement.api.CollateralManagementJsonInputParams;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_client_collateral_management")
|
||||
public class ClientCollateralManagement extends AbstractPersistableCustom {
|
||||
|
||||
@Column(name = "quantity", nullable = false, scale = 5, precision = 20)
|
||||
private BigDecimal quantity;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "client_id", nullable = false)
|
||||
private Client client;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "collateral_id", nullable = false)
|
||||
private CollateralManagementDomain collateral;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "clientCollateralManagement", fetch = FetchType.EAGER)
|
||||
private Set<LoanCollateralManagement> loanCollateralManagementSet = new HashSet<>();
|
||||
|
||||
public ClientCollateralManagement() {
|
||||
|
||||
}
|
||||
|
||||
public ClientCollateralManagement(final BigDecimal quantity, final Client client) {
|
||||
this.client = client;
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public ClientCollateralManagement(final BigDecimal quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
private ClientCollateralManagement(final BigDecimal quantity, final Client client,
|
||||
final CollateralManagementDomain collateralManagementData) {
|
||||
this.quantity = quantity;
|
||||
this.client = client;
|
||||
this.collateral = collateralManagementData;
|
||||
}
|
||||
|
||||
public ClientCollateralManagement createNew(JsonCommand jsonCommand) {
|
||||
BigDecimal quantity = jsonCommand.bigDecimalValueOfParameterNamed("quantity");
|
||||
return new ClientCollateralManagement(quantity);
|
||||
}
|
||||
|
||||
public static ClientCollateralManagement createNew(final BigDecimal quantity, final Client client,
|
||||
final CollateralManagementDomain collateral) {
|
||||
return new ClientCollateralManagement(quantity, client, collateral);
|
||||
}
|
||||
|
||||
public Map<String, Object> update(JsonCommand command) {
|
||||
final Map<String, Object> changes = new LinkedHashMap<>(3);
|
||||
final String quantity = CollateralManagementJsonInputParams.QUANTITY.getValue();
|
||||
if (command.isChangeInBigDecimalParameterNamed(quantity, this.quantity)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(quantity);
|
||||
this.quantity = newValue;
|
||||
changes.put(quantity, this.quantity);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
public BigDecimal getTotal() {
|
||||
if (BigDecimal.ZERO.compareTo(this.quantity) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return this.quantity.multiply(getCollaterals().getBasePrice());
|
||||
}
|
||||
|
||||
public BigDecimal getTotalCollateral(BigDecimal total) {
|
||||
if (BigDecimal.ZERO.compareTo(total) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return total.multiply(getCollaterals().getPctToBase().divide(BigDecimal.valueOf(100)));
|
||||
}
|
||||
|
||||
public void updateQuantity(BigDecimal quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public void updateQuantityAfterLoanClosed(BigDecimal quantity) {
|
||||
this.quantity = this.quantity.add(quantity);
|
||||
}
|
||||
|
||||
public BigDecimal getQuantity() {
|
||||
return this.quantity;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
public CollateralManagementDomain getCollaterals() {
|
||||
return this.collateral;
|
||||
}
|
||||
|
||||
public Set<LoanCollateralManagement> getLoanCollateralManagementSet() {
|
||||
return this.loanCollateralManagementSet;
|
||||
}
|
||||
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* 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.collateralmanagement.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.apache.fineract.portfolio.collateralmanagement.api.CollateralManagementJsonInputParams;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_collateral_management")
|
||||
public class CollateralManagementDomain extends AbstractPersistableCustom {
|
||||
|
||||
@Column(name = "name", length = 20, columnDefinition = " ")
|
||||
private String name;
|
||||
|
||||
@Column(name = "quality", nullable = false, length = 40)
|
||||
private String quality;
|
||||
|
||||
@Column(name = "base_price", nullable = false, scale = 5, precision = 20)
|
||||
private BigDecimal basePrice;
|
||||
|
||||
@Column(name = "unit_type", nullable = false, length = 10)
|
||||
private String unitType;
|
||||
|
||||
@Column(name = "pct_to_base", nullable = false, scale = 5, precision = 20)
|
||||
private BigDecimal pctToBase;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "currency")
|
||||
private ApplicationCurrency currency;
|
||||
|
||||
@OneToMany(mappedBy = "collateral", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<ClientCollateralManagement> clientCollateralManagements = new HashSet<>();
|
||||
|
||||
public CollateralManagementDomain() {
|
||||
|
||||
}
|
||||
|
||||
private CollateralManagementDomain(final String quality, final BigDecimal basePrice, final String unitType, final BigDecimal pctToBase,
|
||||
final ApplicationCurrency currency, final String name) {
|
||||
this.basePrice = basePrice;
|
||||
this.currency = currency;
|
||||
this.pctToBase = pctToBase;
|
||||
this.unitType = unitType;
|
||||
this.quality = quality;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static CollateralManagementDomain createNew(JsonCommand jsonCommand, final ApplicationCurrency applicationCurrency) {
|
||||
String quality = jsonCommand.stringValueOfParameterNamed("quality");
|
||||
BigDecimal basePrice = jsonCommand.bigDecimalValueOfParameterNamed("basePrice");
|
||||
BigDecimal pctToBase = jsonCommand.bigDecimalValueOfParameterNamedDefaultToNullIfZero("pctToBase");
|
||||
String unitType = jsonCommand.stringValueOfParameterNamed("unitType");
|
||||
String name = jsonCommand.stringValueOfParameterNamed("name");
|
||||
return new CollateralManagementDomain(quality, basePrice, unitType, pctToBase, applicationCurrency, name);
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command, final ApplicationCurrency applicationCurrency) {
|
||||
final Map<String, Object> changes = new LinkedHashMap<>(5);
|
||||
final String nameParamName = CollateralManagementJsonInputParams.NAME.getValue();
|
||||
|
||||
if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(nameParamName);
|
||||
this.name = StringUtils.defaultIfEmpty(newValue, null);
|
||||
changes.put(nameParamName, this.name);
|
||||
}
|
||||
|
||||
final String qualityParamName = CollateralManagementJsonInputParams.QUALITY.getValue();
|
||||
if (command.isChangeInStringParameterNamed(qualityParamName, this.quality)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(qualityParamName);
|
||||
this.quality = newValue;
|
||||
changes.put(qualityParamName, this.quality);
|
||||
}
|
||||
|
||||
final String unitTypeParamName = CollateralManagementJsonInputParams.UNIT_TYPE.getValue();
|
||||
if (command.isChangeInStringParameterNamed(unitTypeParamName, this.unitType)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(unitTypeParamName);
|
||||
this.unitType = newValue;
|
||||
changes.put(unitTypeParamName, this.unitType);
|
||||
}
|
||||
|
||||
this.currency = applicationCurrency;
|
||||
|
||||
final String basePriceParamName = CollateralManagementJsonInputParams.BASE_PRICE.getValue();
|
||||
if (command.isChangeInBigDecimalParameterNamed(basePriceParamName, this.basePrice)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(basePriceParamName);
|
||||
this.basePrice = newValue;
|
||||
changes.put(basePriceParamName, this.basePrice);
|
||||
}
|
||||
|
||||
final String pctToBaseParamName = CollateralManagementJsonInputParams.PCT_TO_BASE.getValue();
|
||||
if (command.isChangeInBigDecimalParameterNamed(pctToBaseParamName, this.pctToBase)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(pctToBaseParamName);
|
||||
this.pctToBase = newValue;
|
||||
changes.put(pctToBaseParamName, this.pctToBase);
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
public String getQuality() {
|
||||
return this.quality;
|
||||
}
|
||||
|
||||
public String getUnitType() {
|
||||
return this.unitType;
|
||||
}
|
||||
|
||||
public ApplicationCurrency getCurrency() {
|
||||
return this.currency;
|
||||
}
|
||||
|
||||
public BigDecimal getBasePrice() {
|
||||
return this.basePrice;
|
||||
}
|
||||
|
||||
public BigDecimal getPctToBase() {
|
||||
return this.pctToBase;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Set<ClientCollateralManagement> getClientCollateralManagements() {
|
||||
return this.clientCollateralManagements;
|
||||
}
|
||||
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* 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.api;
|
||||
|
||||
public interface LoanApiConstants {
|
||||
|
||||
String emiAmountParameterName = "fixedEmiAmount";
|
||||
String maxOutstandingBalanceParameterName = "maxOutstandingLoanBalance";
|
||||
String disbursementDataParameterName = "disbursementData";
|
||||
String expectedDisbursementDateParameterName = "expectedDisbursementDate";
|
||||
String disbursementPrincipalParameterName = "principal";
|
||||
String principalParameterName = "principal";
|
||||
String disbursementReversedParameterName = "reversed";
|
||||
String disbursementNetDisbursalAmountParameterName = "netDisbursalAmount";
|
||||
String updatedDisbursementDateParameterName = "updatedExpectedDisbursementDate";
|
||||
String updatedDisbursementPrincipalParameterName = "updatedPrincipal";
|
||||
String disbursementIdParameterName = "id";
|
||||
String loanChargeIdParameterName = "loanChargeId";
|
||||
String chargeIdParameterName = "chargeId";
|
||||
String amountParameterName = "amount";
|
||||
String chargeTimeTypeParameterName = "chargeTimeType";
|
||||
String chargeCalculationTypeParameterName = "chargeCalculationType";
|
||||
String principalDisbursedParameterName = "transactionAmount";
|
||||
String chargesParameterName = "charges";
|
||||
String loanIdTobeApproved = "loanId";
|
||||
String postDatedChecks = "postDatedChecks";
|
||||
|
||||
String approvedLoanAmountParameterName = "approvedLoanAmount";
|
||||
String approvedOnDateParameterName = "approvedOnDate";
|
||||
String noteParameterName = "note";
|
||||
String localeParameterName = "locale";
|
||||
String dateFormatParameterName = "dateFormat";
|
||||
String rejectedOnDateParameterName = "rejectedOnDate";
|
||||
String withdrawnOnDateParameterName = "withdrawnOnDate";
|
||||
|
||||
String transactionProcessingStrategyCodeParameterName = "transactionProcessingStrategyCode";
|
||||
String loanPurposeIdParameterName = "loanPurposeId";
|
||||
String loanOfficerIdParameterName = "loanOfficerId";
|
||||
String fundIdParameterName = "fundId";
|
||||
String externalIdParameterName = "externalId";
|
||||
String accountNoParameterName = "accountNo";
|
||||
String productIdParameterName = "productId";
|
||||
String calendarIdParameterName = "calendarId";
|
||||
String loanTypeParameterName = "loanType";
|
||||
String groupIdParameterName = "groupId";
|
||||
String clientIdParameterName = "clientId";
|
||||
String idParameterName = "id";
|
||||
String graceOnInterestChargedParameterName = "graceOnInterestCharged";
|
||||
String graceOnInterestPaymentParameterName = "graceOnInterestPayment";
|
||||
String graceOnPrincipalPaymentParameterName = "graceOnPrincipalPayment";
|
||||
String repaymentsStartingFromDateParameterName = "repaymentsStartingFromDate";
|
||||
String interestRateFrequencyTypeParameterName = "interestRateFrequencyType";
|
||||
String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
|
||||
String interestTypeParameterName = "interestType";
|
||||
String amortizationTypeParameterName = "amortizationType";
|
||||
String amortizationTypeOptionsParameterName = "amortizationTypeOptions";
|
||||
String repaymentFrequencyTypeParameterName = "repaymentFrequencyType";
|
||||
String loanTermFrequencyTypeParameterName = "loanTermFrequencyType";
|
||||
String loanTermFrequencyParameterName = "loanTermFrequency";
|
||||
String numberOfRepaymentsParameterName = "numberOfRepayments";
|
||||
String repaymentEveryParameterName = "repaymentEvery";
|
||||
String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
||||
String inArrearsToleranceParameterName = "inArrearsTolerance";
|
||||
String interestChargedFromDateParameterName = "interestChargedFromDate";
|
||||
String submittedOnDateParameterName = "submittedOnDate";
|
||||
String submittedOnNoteParameterName = "submittedOnNote";
|
||||
String collateralParameterName = "collateral";
|
||||
String collateralsParameterName = "collaterals";
|
||||
String clientCollateralIdParameterName = "clientCollateralId";
|
||||
|
||||
String quantityParameterName = "quantity";
|
||||
String syncDisbursementWithMeetingParameterName = "syncDisbursementWithMeeting";
|
||||
String linkAccountIdParameterName = "linkAccountId";
|
||||
String createStandingInstructionAtDisbursementParameterName = "createStandingInstructionAtDisbursement";
|
||||
String daysInYearTypeParameterName = "daysInYearType";
|
||||
String daysInMonthTypeParameterName = "daysInMonthType";
|
||||
|
||||
String MULTIDISBURSE_DETAILS_PARAMNAME = "multiDisburseDetails";
|
||||
String EMI_AMOUNT_VARIATIONS_PARAMNAME = "emiAmountVariations";
|
||||
String COLLECTION_PARAMNAME = "collection";
|
||||
|
||||
// Interest recalculation related
|
||||
String isInterestRecalculationEnabledParameterName = "isInterestRecalculationEnabled";
|
||||
String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod";
|
||||
String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
|
||||
String repaymentFrequencyNthDayTypeParameterName = "repaymentFrequencyNthDayType";
|
||||
String repaymentFrequencyDayOfWeekTypeParameterName = "repaymentFrequencyDayOfWeekType";
|
||||
|
||||
// Floating interest rate related
|
||||
String interestRateDifferentialParameterName = "interestRateDifferential";
|
||||
String isFloatingInterestRateParameterName = "isFloatingInterestRate";
|
||||
|
||||
// Error codes
|
||||
String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_INTEREST_CALCULATION_TYPE = "loancharge.with.calculation.type.interest.not.allowed";
|
||||
String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_PRINCIPAL_CALCULATION_TYPE = "loancharge.with.calculation.type.principal.not.allowed";
|
||||
String DISBURSEMENT_DATE_START_WITH_ERROR = "first.disbursement.date.must.start.with.expected.disbursement.date";
|
||||
String PRINCIPAL_AMOUNT_SHOULD_BE_SAME = "sum.of.multi.disburse.amounts.must.equal.with.total.principal";
|
||||
String DISBURSEMENT_DATE_UNIQUE_ERROR = "disbursement.date.must.be.unique.for.tranches";
|
||||
String ALREADY_DISBURSED = "can.not.change.disbursement.date";
|
||||
String APPROVED_AMOUNT_IS_LESS_THAN_SUM_OF_TRANCHES = "sum.of.multi.disburse.amounts.must.be.equal.to.or.lesser.than.approved.principal";
|
||||
String DISBURSEMENT_DATES_NOT_IN_ORDER = "disbursements.should.be.ordered.based.on.their.disbursement.dates";
|
||||
String DISBURSEMENT_DATE_BEFORE_ERROR = "disbursement.date.of.tranche.cannot.be.before.expected.disbursement.date";
|
||||
String LOAN_COLLATERAL_TOTAL_VALUE_SHOULD_BE_SUFFICIENT = "sum.of.multi.collateral.values.must.equal.or.greater.than.principal.amount";
|
||||
|
||||
String isFloatingInterestRate = "isFloatingInterestRate";
|
||||
String interestRateDifferential = "interestRateDifferential";
|
||||
|
||||
String exceptionParamName = "exceptions";
|
||||
String modifiedinstallmentsParamName = "modifiedinstallments";
|
||||
String newinstallmentsParamName = "newinstallments";
|
||||
String deletedinstallmentsParamName = "deletedinstallments";
|
||||
String dueDateParamName = "dueDate";
|
||||
String modifiedDueDateParamName = "modifiedDueDate";
|
||||
String principalParamName = "principal";
|
||||
String parentAccountParamName = "isParentAccount";
|
||||
String totalLoanParamName = "totalLoan";
|
||||
String installmentAmountParamName = "installmentAmount";
|
||||
// loan write off
|
||||
String WRITEOFFREASONS = "WriteOffReasons";
|
||||
// loan charge-off
|
||||
String CHARGE_OFF_REASONS = "ChargeOffReasons";
|
||||
// fore closure constants
|
||||
String transactionDateParamName = "transactionDate";
|
||||
String noteParamName = "note";
|
||||
|
||||
String canUseForTopup = "canUseForTopup";
|
||||
String clientActiveLoanOptions = "clientActiveLoanOptions";
|
||||
String isTopup = "isTopup";
|
||||
String loanIdToClose = "loanIdToClose";
|
||||
String topupAmount = "topupAmount";
|
||||
|
||||
String datatables = "datatables";
|
||||
|
||||
String isEqualAmortizationParam = "isEqualAmortization";
|
||||
String applicationId = "applicationId";
|
||||
String lastApplication = "lastApplication";
|
||||
|
||||
String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
|
||||
|
||||
String LOAN_ASSOCIATIONS_ALL = "all";
|
||||
String chargeOffReasonIdParamName = "chargeOffReasonId";
|
||||
|
||||
// Reversal Transation Data
|
||||
String REVERSAL_EXTERNAL_ID_PARAMNAME = "reversalExternalId";
|
||||
String REVERSED_ON_DATE_PARAMNAME = "reversedOnDate";
|
||||
|
||||
String DISALLOW_EXPECTED_DISBURSEMENTS = "disallowExpectedDisbursements";
|
||||
|
||||
String TRANSACTION_AMOUNT_PARAMNAME = "transactionAmount";
|
||||
String PAYMENT_TYPE_PARAMNAME = "paymentTypeId";
|
||||
String FRAUD_ATTRIBUTE_NAME = "fraud";
|
||||
|
||||
// Commands
|
||||
String CHARGEBACK_TRANSACTION_COMMAND = "chargeback";
|
||||
String MARK_AS_FRAUD_COMMAND = "markAsFraud";
|
||||
|
||||
// Data Validator names
|
||||
String LOAN_FRAUD_DATAVALIDATOR_PREFIX = "loans.fraud";
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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.command;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
|
||||
/**
|
||||
* Java object representation of {@link LoanCharge} API JSON.
|
||||
*/
|
||||
public class LoanChargeCommand implements Comparable<LoanChargeCommand> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
private final Long chargeId;
|
||||
private final BigDecimal amount;
|
||||
@SuppressWarnings("unused")
|
||||
private final Integer chargeTimeType;
|
||||
@SuppressWarnings("unused")
|
||||
private final Integer chargeCalculationType;
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate dueDate;
|
||||
|
||||
public LoanChargeCommand(final Long id, final Long chargeId, final BigDecimal amount, final Integer chargeTimeType,
|
||||
final Integer chargeCalculationType, final LocalDate dueDate) {
|
||||
this.id = id;
|
||||
this.chargeId = chargeId;
|
||||
this.amount = amount;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.chargeCalculationType = chargeCalculationType;
|
||||
this.dueDate = dueDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final LoanChargeCommand o) {
|
||||
int comparison = this.chargeId.compareTo(o.chargeId);
|
||||
if (comparison == 0) {
|
||||
comparison = this.amount.compareTo(o.amount);
|
||||
}
|
||||
return comparison;
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* Immutable data object representing disbursement information.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public final class DisbursementData implements Comparable<DisbursementData> {
|
||||
|
||||
private final Long id;
|
||||
private final LocalDate expectedDisbursementDate;
|
||||
private final LocalDate actualDisbursementDate;
|
||||
private final BigDecimal principal;
|
||||
private final BigDecimal netDisbursalAmount;
|
||||
private final String loanChargeId;
|
||||
private final BigDecimal chargeAmount;
|
||||
private final BigDecimal waivedChargeAmount;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
private String dateFormat;
|
||||
private String locale;
|
||||
private String note;
|
||||
private transient String linkAccountId;
|
||||
|
||||
public static DisbursementData importInstance(LocalDate actualDisbursementDate, String linkAccountId, Integer rowIndex, String locale,
|
||||
String dateFormat) {
|
||||
return new DisbursementData(actualDisbursementDate, linkAccountId, rowIndex, locale, dateFormat);
|
||||
}
|
||||
|
||||
private DisbursementData(LocalDate actualDisbursementDate, String linkAccountId, Integer rowIndex, String locale, String dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.actualDisbursementDate = actualDisbursementDate;
|
||||
this.rowIndex = rowIndex;
|
||||
this.note = "";
|
||||
this.linkAccountId = linkAccountId;
|
||||
this.id = null;
|
||||
this.expectedDisbursementDate = null;
|
||||
this.principal = null;
|
||||
this.loanChargeId = null;
|
||||
this.chargeAmount = null;
|
||||
this.waivedChargeAmount = null;
|
||||
this.netDisbursalAmount = null;
|
||||
|
||||
}
|
||||
|
||||
public LocalDate disbursementDate() {
|
||||
LocalDate disbursementDate = this.expectedDisbursementDate;
|
||||
if (this.actualDisbursementDate != null) {
|
||||
disbursementDate = this.actualDisbursementDate;
|
||||
}
|
||||
return disbursementDate;
|
||||
}
|
||||
|
||||
public boolean isDisbursed() {
|
||||
return this.actualDisbursementDate != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final DisbursementData obj) {
|
||||
if (obj == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return obj.expectedDisbursementDate.compareTo(this.expectedDisbursementDate);
|
||||
}
|
||||
|
||||
public boolean isDueForDisbursement(final LocalDate fromNotInclusive, final LocalDate upToAndInclusive) {
|
||||
final LocalDate dueDate = disbursementDate();
|
||||
return occursOnDayFromAndUpToAndIncluding(fromNotInclusive, upToAndInclusive, dueDate);
|
||||
}
|
||||
|
||||
private boolean occursOnDayFromAndUpToAndIncluding(final LocalDate fromNotInclusive, final LocalDate upToAndInclusive,
|
||||
final LocalDate target) {
|
||||
return target != null && target.isAfter(fromNotInclusive) && !target.isAfter(upToAndInclusive);
|
||||
}
|
||||
|
||||
public BigDecimal getWaivedChargeAmount() {
|
||||
if (this.waivedChargeAmount == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return this.waivedChargeAmount;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||
|
||||
public class HolidayDetailDTO {
|
||||
|
||||
final boolean isHolidayEnabled;
|
||||
final List<Holiday> holidays;
|
||||
final WorkingDays workingDays;
|
||||
final boolean allowTransactionsOnHoliday;
|
||||
final boolean allowTransactionsOnNonWorkingDay;
|
||||
|
||||
public HolidayDetailDTO(final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays) {
|
||||
this.isHolidayEnabled = isHolidayEnabled;
|
||||
this.holidays = holidays;
|
||||
this.workingDays = workingDays;
|
||||
this.allowTransactionsOnHoliday = false;
|
||||
this.allowTransactionsOnNonWorkingDay = false;
|
||||
}
|
||||
|
||||
public HolidayDetailDTO(final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||
final boolean allowTransactionsOnHoliday, final boolean allowTransactionsOnNonWorkingDay) {
|
||||
this.isHolidayEnabled = isHolidayEnabled;
|
||||
this.holidays = holidays;
|
||||
this.workingDays = workingDays;
|
||||
this.allowTransactionsOnHoliday = allowTransactionsOnHoliday;
|
||||
this.allowTransactionsOnNonWorkingDay = allowTransactionsOnNonWorkingDay;
|
||||
}
|
||||
|
||||
public boolean isHolidayEnabled() {
|
||||
return this.isHolidayEnabled;
|
||||
}
|
||||
|
||||
public List<Holiday> getHolidays() {
|
||||
return this.holidays;
|
||||
}
|
||||
|
||||
public WorkingDays getWorkingDays() {
|
||||
return this.workingDays;
|
||||
}
|
||||
|
||||
public boolean isAllowTransactionsOnHoliday() {
|
||||
return this.allowTransactionsOnHoliday;
|
||||
}
|
||||
|
||||
public boolean isAllowTransactionsOnNonWorkingDay() {
|
||||
return this.allowTransactionsOnNonWorkingDay;
|
||||
}
|
||||
}
|
||||
+430
@@ -0,0 +1,430 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
|
||||
/**
|
||||
* Immutable data object for loan charge data.
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class LoanChargeData {
|
||||
|
||||
private final Long id;
|
||||
private final Long chargeId;
|
||||
private final String name;
|
||||
private final EnumOptionData chargeTimeType;
|
||||
|
||||
private final LocalDate submittedOnDate;
|
||||
|
||||
private final LocalDate dueDate;
|
||||
|
||||
private final EnumOptionData chargeCalculationType;
|
||||
|
||||
private final BigDecimal percentage;
|
||||
|
||||
private final BigDecimal amountPercentageAppliedTo;
|
||||
|
||||
private final CurrencyData currency;
|
||||
|
||||
private final BigDecimal amount;
|
||||
|
||||
private final BigDecimal amountPaid;
|
||||
private final BigDecimal amountWaived;
|
||||
private final BigDecimal amountWrittenOff;
|
||||
|
||||
private final BigDecimal amountOutstanding;
|
||||
|
||||
private final BigDecimal amountOrPercentage;
|
||||
|
||||
private final Collection<ChargeData> chargeOptions;
|
||||
|
||||
private final boolean penalty;
|
||||
|
||||
private final EnumOptionData chargePaymentMode;
|
||||
|
||||
private final boolean paid;
|
||||
|
||||
private final boolean waived;
|
||||
|
||||
private final boolean chargePayable;
|
||||
|
||||
private final Long loanId;
|
||||
|
||||
private final BigDecimal minCap;
|
||||
|
||||
private final BigDecimal maxCap;
|
||||
|
||||
private final Collection<LoanInstallmentChargeData> installmentChargeData;
|
||||
|
||||
private BigDecimal amountAccrued;
|
||||
|
||||
private BigDecimal amountUnrecognized;
|
||||
|
||||
private final ExternalId externalId;
|
||||
|
||||
private final ExternalId externalLoanId;
|
||||
|
||||
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
|
||||
return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null,
|
||||
ExternalId.empty(), null, null, null, null, ExternalId.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* used when populating with details from charge definition (for crud on charges)
|
||||
*/
|
||||
public static LoanChargeData newLoanChargeDetails(final Long chargeId, final String name, final CurrencyData currency,
|
||||
final BigDecimal amount, final BigDecimal percentage, final EnumOptionData chargeTimeType,
|
||||
final EnumOptionData chargeCalculationType, final boolean penalty, final EnumOptionData chargePaymentMode,
|
||||
final BigDecimal minCap, final BigDecimal maxCap, final ExternalId externalId) {
|
||||
return new LoanChargeData(null, chargeId, name, currency, amount, percentage, chargeTimeType, chargeCalculationType, null, penalty,
|
||||
chargePaymentMode, false, false, null, ExternalId.empty(), minCap, maxCap, null, null, externalId);
|
||||
}
|
||||
|
||||
public LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
|
||||
final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
|
||||
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate submittedOnDate,
|
||||
final LocalDate dueDate, final EnumOptionData chargeCalculationType, final BigDecimal percentage,
|
||||
final BigDecimal amountPercentageAppliedTo, final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid,
|
||||
final boolean waived, final Long loanId, final ExternalId externalLoanId, final BigDecimal minCap, final BigDecimal maxCap,
|
||||
final BigDecimal amountOrPercentage, Collection<LoanInstallmentChargeData> installmentChargeData, final ExternalId externalId) {
|
||||
this.id = id;
|
||||
this.chargeId = chargeId;
|
||||
this.name = name;
|
||||
this.currency = currency;
|
||||
this.amount = amount;
|
||||
this.amountPaid = amountPaid;
|
||||
this.amountWaived = amountWaived;
|
||||
this.amountWrittenOff = amountWrittenOff;
|
||||
this.amountOutstanding = amountOutstanding;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.dueDate = dueDate;
|
||||
this.chargeCalculationType = chargeCalculationType;
|
||||
this.percentage = percentage;
|
||||
this.amountPercentageAppliedTo = amountPercentageAppliedTo;
|
||||
this.penalty = penalty;
|
||||
this.chargePaymentMode = chargePaymentMode;
|
||||
this.paid = paid;
|
||||
this.waived = waived;
|
||||
this.minCap = minCap;
|
||||
this.maxCap = maxCap;
|
||||
if (amountOrPercentage == null) {
|
||||
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
|
||||
this.amountOrPercentage = this.percentage;
|
||||
} else {
|
||||
this.amountOrPercentage = amount;
|
||||
}
|
||||
} else {
|
||||
this.amountOrPercentage = amountOrPercentage;
|
||||
}
|
||||
|
||||
this.chargeOptions = null;
|
||||
this.chargePayable = isChargePayable();
|
||||
this.loanId = loanId;
|
||||
this.installmentChargeData = installmentChargeData;
|
||||
this.amountAccrued = null;
|
||||
this.amountUnrecognized = null;
|
||||
this.externalId = externalId;
|
||||
this.externalLoanId = externalLoanId;
|
||||
}
|
||||
|
||||
private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
|
||||
final BigDecimal percentage, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType,
|
||||
final Collection<ChargeData> chargeOptions, final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid,
|
||||
final boolean waived, final Long loanId, final ExternalId externalLoanId, final BigDecimal minCap, final BigDecimal maxCap,
|
||||
final BigDecimal amountOrPercentage, Collection<LoanInstallmentChargeData> installmentChargeData, final ExternalId externalId) {
|
||||
this.id = id;
|
||||
this.chargeId = chargeId;
|
||||
this.name = name;
|
||||
this.currency = currency;
|
||||
this.amount = amount;
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountWaived = BigDecimal.ZERO;
|
||||
this.amountWrittenOff = BigDecimal.ZERO;
|
||||
this.amountOutstanding = amount;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.submittedOnDate = null;
|
||||
this.dueDate = null;
|
||||
this.chargeCalculationType = chargeCalculationType;
|
||||
this.percentage = percentage;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.penalty = penalty;
|
||||
this.chargePaymentMode = chargePaymentMode;
|
||||
this.paid = paid;
|
||||
this.waived = waived;
|
||||
|
||||
if (amountOrPercentage == null) {
|
||||
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
|
||||
this.amountOrPercentage = this.percentage;
|
||||
} else {
|
||||
this.amountOrPercentage = amount;
|
||||
}
|
||||
} else {
|
||||
this.amountOrPercentage = amountOrPercentage;
|
||||
}
|
||||
|
||||
this.chargeOptions = chargeOptions;
|
||||
this.chargePayable = isChargePayable();
|
||||
this.loanId = loanId;
|
||||
this.externalLoanId = externalLoanId;
|
||||
this.minCap = minCap;
|
||||
this.maxCap = maxCap;
|
||||
this.installmentChargeData = installmentChargeData;
|
||||
this.amountAccrued = null;
|
||||
this.amountUnrecognized = null;
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final LocalDate submittedOnDate, final BigDecimal amountOutstanding,
|
||||
EnumOptionData chargeTimeType, final Long loanId, final ExternalId externalLoanId,
|
||||
Collection<LoanInstallmentChargeData> installmentChargeData, final ExternalId externalId) {
|
||||
this.id = id;
|
||||
this.chargeId = null;
|
||||
this.name = null;
|
||||
this.currency = null;
|
||||
this.amount = null;
|
||||
this.amountPaid = null;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
this.amountOutstanding = amountOutstanding;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.dueDate = dueAsOfDate;
|
||||
this.chargeCalculationType = null;
|
||||
this.percentage = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.penalty = false;
|
||||
this.chargePaymentMode = null;
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
this.amountOrPercentage = null;
|
||||
this.chargeOptions = null;
|
||||
this.chargePayable = false;
|
||||
this.loanId = loanId;
|
||||
this.minCap = null;
|
||||
this.maxCap = null;
|
||||
this.installmentChargeData = installmentChargeData;
|
||||
this.amountAccrued = null;
|
||||
this.amountUnrecognized = null;
|
||||
this.externalId = externalId;
|
||||
this.externalLoanId = externalLoanId;
|
||||
}
|
||||
|
||||
public LoanChargeData(final Long id, final Long chargeId, final LocalDate dueAsOfDate, final LocalDate submittedOnDate,
|
||||
EnumOptionData chargeTimeType, final BigDecimal amount, final BigDecimal amountAccrued, final BigDecimal amountWaived,
|
||||
final boolean penalty, final ExternalId externalId) {
|
||||
this.id = id;
|
||||
this.chargeId = chargeId;
|
||||
this.name = null;
|
||||
this.currency = null;
|
||||
this.amount = amount;
|
||||
this.amountPaid = null;
|
||||
this.amountWaived = amountWaived;
|
||||
this.amountWrittenOff = null;
|
||||
this.amountOutstanding = null;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.dueDate = dueAsOfDate;
|
||||
this.chargeCalculationType = null;
|
||||
this.percentage = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.penalty = penalty;
|
||||
this.chargePaymentMode = null;
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
this.amountOrPercentage = null;
|
||||
this.chargeOptions = null;
|
||||
this.chargePayable = false;
|
||||
this.loanId = null;
|
||||
this.externalLoanId = ExternalId.empty();
|
||||
this.minCap = null;
|
||||
this.maxCap = null;
|
||||
this.installmentChargeData = null;
|
||||
this.amountAccrued = amountAccrued;
|
||||
this.amountUnrecognized = null;
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
public LoanChargeData(final BigDecimal amountUnrecognized, final LoanChargeData chargeData) {
|
||||
this.id = chargeData.id;
|
||||
this.chargeId = chargeData.chargeId;
|
||||
this.name = null;
|
||||
this.currency = null;
|
||||
this.amount = chargeData.amount;
|
||||
this.amountPaid = null;
|
||||
this.amountWaived = chargeData.amountWaived;
|
||||
this.amountWrittenOff = null;
|
||||
this.amountOutstanding = null;
|
||||
this.chargeTimeType = chargeData.chargeTimeType;
|
||||
this.submittedOnDate = chargeData.submittedOnDate;
|
||||
this.dueDate = chargeData.dueDate;
|
||||
this.chargeCalculationType = null;
|
||||
this.percentage = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.penalty = chargeData.penalty;
|
||||
this.chargePaymentMode = null;
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
this.amountOrPercentage = null;
|
||||
this.chargeOptions = null;
|
||||
this.chargePayable = false;
|
||||
this.loanId = null;
|
||||
this.externalLoanId = ExternalId.empty();
|
||||
this.minCap = null;
|
||||
this.maxCap = null;
|
||||
this.installmentChargeData = null;
|
||||
this.amountAccrued = chargeData.amountAccrued;
|
||||
this.amountUnrecognized = amountUnrecognized;
|
||||
this.externalId = chargeData.externalId;
|
||||
}
|
||||
|
||||
public LoanChargeData(LoanChargeData chargeData, Collection<LoanInstallmentChargeData> installmentChargeData) {
|
||||
this.id = chargeData.id;
|
||||
this.chargeId = chargeData.chargeId;
|
||||
this.name = chargeData.name;
|
||||
this.currency = chargeData.currency;
|
||||
this.amount = chargeData.amount;
|
||||
this.amountPaid = chargeData.amountPaid;
|
||||
this.amountWaived = chargeData.amountWaived;
|
||||
this.amountWrittenOff = chargeData.amountWrittenOff;
|
||||
this.amountOutstanding = chargeData.amountOutstanding;
|
||||
this.chargeTimeType = chargeData.chargeTimeType;
|
||||
this.submittedOnDate = chargeData.submittedOnDate;
|
||||
this.dueDate = chargeData.dueDate;
|
||||
this.chargeCalculationType = chargeData.chargeCalculationType;
|
||||
this.percentage = chargeData.percentage;
|
||||
this.amountPercentageAppliedTo = chargeData.amountPercentageAppliedTo;
|
||||
this.penalty = chargeData.penalty;
|
||||
this.chargePaymentMode = chargeData.chargePaymentMode;
|
||||
this.paid = chargeData.paid;
|
||||
this.waived = chargeData.waived;
|
||||
this.minCap = chargeData.minCap;
|
||||
this.maxCap = chargeData.maxCap;
|
||||
this.amountOrPercentage = chargeData.amountOrPercentage;
|
||||
this.chargeOptions = chargeData.chargeOptions;
|
||||
this.chargePayable = chargeData.chargePayable;
|
||||
this.loanId = chargeData.loanId;
|
||||
this.externalLoanId = chargeData.externalLoanId;
|
||||
this.installmentChargeData = installmentChargeData;
|
||||
this.amountAccrued = chargeData.amountAccrued;
|
||||
this.amountUnrecognized = chargeData.amountUnrecognized;
|
||||
this.externalId = chargeData.externalId;
|
||||
}
|
||||
|
||||
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amount, final EnumOptionData chargeCalculationType,
|
||||
final EnumOptionData chargeTimeType) {
|
||||
this.id = null;
|
||||
this.chargeId = id;
|
||||
this.name = null;
|
||||
this.currency = null;
|
||||
this.amount = amount;
|
||||
this.amountPaid = null;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
this.amountOutstanding = null;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.submittedOnDate = null;
|
||||
this.dueDate = dueAsOfDate;
|
||||
this.chargeCalculationType = chargeCalculationType;
|
||||
this.percentage = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.penalty = false;
|
||||
this.chargePaymentMode = null;
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
this.amountOrPercentage = null;
|
||||
this.chargeOptions = null;
|
||||
this.chargePayable = false;
|
||||
this.loanId = null;
|
||||
this.externalLoanId = ExternalId.empty();
|
||||
this.minCap = null;
|
||||
this.maxCap = null;
|
||||
this.installmentChargeData = null;
|
||||
this.amountAccrued = null;
|
||||
this.amountUnrecognized = null;
|
||||
this.externalId = ExternalId.empty();
|
||||
}
|
||||
|
||||
public LoanChargeData(final Long id, final LocalDate dueAsOfDate, final BigDecimal amountOrPercentage) {
|
||||
this.id = id;
|
||||
this.chargeId = null;
|
||||
this.name = null;
|
||||
this.currency = null;
|
||||
this.amount = null;
|
||||
this.amountPaid = null;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
this.amountOutstanding = null;
|
||||
this.chargeTimeType = null;
|
||||
this.submittedOnDate = null;
|
||||
this.dueDate = dueAsOfDate;
|
||||
this.chargeCalculationType = null;
|
||||
this.percentage = null;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.penalty = false;
|
||||
this.chargePaymentMode = null;
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
this.amountOrPercentage = amountOrPercentage;
|
||||
this.chargeOptions = null;
|
||||
this.chargePayable = false;
|
||||
this.loanId = null;
|
||||
this.externalLoanId = ExternalId.empty();
|
||||
this.minCap = null;
|
||||
this.maxCap = null;
|
||||
this.installmentChargeData = null;
|
||||
this.amountAccrued = null;
|
||||
this.amountUnrecognized = null;
|
||||
this.externalId = ExternalId.empty();
|
||||
}
|
||||
|
||||
public boolean isChargePayable() {
|
||||
boolean isAccountTransfer = false;
|
||||
if (this.chargePaymentMode != null) {
|
||||
isAccountTransfer = ChargePaymentMode.fromInt(this.chargePaymentMode.getId().intValue()).isPaymentModeAccountTransfer();
|
||||
}
|
||||
return isAccountTransfer && !this.paid && !this.waived;
|
||||
}
|
||||
|
||||
public boolean isInstallmentFee() {
|
||||
boolean isInstalmentFee = false;
|
||||
if (this.chargeTimeType != null) {
|
||||
isInstalmentFee = ChargeTimeType.fromInt(this.chargeTimeType.getId().intValue()).isInstalmentFee();
|
||||
}
|
||||
return isInstalmentFee;
|
||||
}
|
||||
|
||||
public void updateAmountAccrued(BigDecimal amountAccrued) {
|
||||
this.amountAccrued = amountAccrued;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class LoanChargePaidByData {
|
||||
|
||||
private final Long id;
|
||||
private final BigDecimal amount;
|
||||
private final Integer installmentNumber;
|
||||
private final Long chargeId;
|
||||
private final Long transactionId;
|
||||
private final String name;
|
||||
|
||||
public LoanChargePaidByData(final Long id, final BigDecimal amount, final Integer installmentNumber, final Long chargeId,
|
||||
final Long transactionId) {
|
||||
this.id = id;
|
||||
this.amount = amount;
|
||||
this.installmentNumber = installmentNumber;
|
||||
this.chargeId = chargeId;
|
||||
this.transactionId = transactionId;
|
||||
this.name = null;
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
|
||||
public class LoanChargePaidDetail {
|
||||
|
||||
private final Money amount;
|
||||
private final LoanRepaymentScheduleInstallment installment;
|
||||
private final boolean isFeeCharge;
|
||||
|
||||
public LoanChargePaidDetail(Money amount, LoanRepaymentScheduleInstallment installment, boolean isFeeCharge) {
|
||||
this.amount = amount;
|
||||
this.installment = installment;
|
||||
this.isFeeCharge = isFeeCharge;
|
||||
}
|
||||
|
||||
public Money getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment getInstallment() {
|
||||
return this.installment;
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
return this.isFeeCharge;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public class LoanCollateralManagementData {
|
||||
|
||||
private final Long clientCollateralId;
|
||||
|
||||
private final BigDecimal quantity;
|
||||
|
||||
private final BigDecimal total;
|
||||
|
||||
private final BigDecimal totalCollateral;
|
||||
|
||||
private final Long id;
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class LoanInstallmentChargeData {
|
||||
|
||||
private final Integer installmentNumber;
|
||||
private final LocalDate dueDate;
|
||||
private final BigDecimal amount;
|
||||
private final BigDecimal amountOutstanding;
|
||||
private final BigDecimal amountWaived;
|
||||
private final boolean paid;
|
||||
private final boolean waived;
|
||||
private BigDecimal amountAccrued;
|
||||
private BigDecimal amountUnrecognized;
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public final class LoanRepaymentScheduleInstallmentData {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Integer installmentId;
|
||||
|
||||
private LocalDate date;
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
public static LoanRepaymentScheduleInstallmentData instanceOf(final Long id, final Integer installmentId, final LocalDate date,
|
||||
final BigDecimal amount) {
|
||||
return new LoanRepaymentScheduleInstallmentData(id, installmentId, date, amount);
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Immutable data object represent loan status enumerations.
|
||||
*/
|
||||
@Getter
|
||||
public class LoanStatusEnumData {
|
||||
|
||||
private final Long id;
|
||||
private final String code;
|
||||
private final String value;
|
||||
private final boolean pendingApproval;
|
||||
private final boolean waitingForDisbursal;
|
||||
private final boolean active;
|
||||
private final boolean closedObligationsMet;
|
||||
private final boolean closedWrittenOff;
|
||||
private final boolean closedRescheduled;
|
||||
private final boolean closed;
|
||||
private final boolean overpaid;
|
||||
|
||||
public LoanStatusEnumData(final Long id, final String code, final String value) {
|
||||
this.id = id;
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.pendingApproval = Long.valueOf(100).equals(this.id);
|
||||
this.waitingForDisbursal = Long.valueOf(200).equals(this.id);
|
||||
this.active = Long.valueOf(300).equals(this.id);
|
||||
this.closedObligationsMet = Long.valueOf(600).equals(this.id);
|
||||
this.closedWrittenOff = Long.valueOf(601).equals(this.id);
|
||||
this.closedRescheduled = Long.valueOf(602).equals(this.id);
|
||||
this.closed = this.closedObligationsMet || this.closedWrittenOff || this.closedRescheduled;
|
||||
this.overpaid = Long.valueOf(700).equals(this.id);
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||
|
||||
@Getter
|
||||
public class LoanTermVariationsData implements Comparable<LoanTermVariationsData> {
|
||||
|
||||
private final Long id;
|
||||
private final EnumOptionData termType;
|
||||
private LocalDate termVariationApplicableFrom;
|
||||
private final BigDecimal decimalValue;
|
||||
private final LocalDate dateValue;
|
||||
private final boolean isSpecificToInstallment;
|
||||
private Boolean isProcessed;
|
||||
|
||||
public LoanTermVariationsData(final Long id, final EnumOptionData termType, final LocalDate termVariationApplicableFrom,
|
||||
final BigDecimal decimalValue, final LocalDate dateValue, final boolean isSpecificToInstallment) {
|
||||
this.id = id;
|
||||
this.termType = termType;
|
||||
this.termVariationApplicableFrom = termVariationApplicableFrom;
|
||||
this.decimalValue = decimalValue;
|
||||
this.dateValue = dateValue;
|
||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||
}
|
||||
|
||||
public LoanTermVariationsData(final EnumOptionData termType, final LocalDate termVariationApplicableFrom, final BigDecimal decimalValue,
|
||||
LocalDate dateValue, final boolean isSpecificToInstallment) {
|
||||
this.id = null;
|
||||
this.termType = termType;
|
||||
this.termVariationApplicableFrom = termVariationApplicableFrom;
|
||||
this.decimalValue = decimalValue;
|
||||
this.dateValue = dateValue;
|
||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||
}
|
||||
|
||||
public LoanTermVariationType getTermVariationType() {
|
||||
return LoanTermVariationType.fromInt(this.termType.getId().intValue());
|
||||
}
|
||||
|
||||
public boolean isApplicable(final LocalDate fromDate, final LocalDate dueDate) {
|
||||
return occursOnDayFromAndUpTo(fromDate, dueDate, this.termVariationApplicableFrom);
|
||||
}
|
||||
|
||||
private boolean occursOnDayFromAndUpTo(final LocalDate fromNotInclusive, final LocalDate upToInclusive, final LocalDate target) {
|
||||
return target != null && target.isAfter(fromNotInclusive) && !target.isAfter(upToInclusive);
|
||||
}
|
||||
|
||||
public boolean isApplicable(final LocalDate fromDate) {
|
||||
return occursBefore(fromDate, this.termVariationApplicableFrom);
|
||||
}
|
||||
|
||||
private boolean occursBefore(final LocalDate date, final LocalDate target) {
|
||||
return target != null && !target.isAfter(date);
|
||||
}
|
||||
|
||||
public boolean isSpecificToInstallment() {
|
||||
return this.isSpecificToInstallment;
|
||||
}
|
||||
|
||||
public boolean isIsSpecificToInstallment() {
|
||||
return this.isSpecificToInstallment;
|
||||
}
|
||||
|
||||
public Boolean isProcessed() {
|
||||
return this.isProcessed == null ? false : this.isProcessed;
|
||||
}
|
||||
|
||||
public void setProcessed(Boolean isProcessed) {
|
||||
this.isProcessed = isProcessed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(LoanTermVariationsData o) {
|
||||
int comparsion = getTermVariationApplicableFrom().compareTo(o.getTermVariationApplicableFrom());
|
||||
if (comparsion == 0) {
|
||||
if (o.getTermVariationType().isDueDateVariation() || o.getTermVariationType().isInsertInstallment()) {
|
||||
comparsion = 1;
|
||||
}
|
||||
}
|
||||
return comparsion;
|
||||
}
|
||||
|
||||
public void setApplicableFromDate(final LocalDate applicableFromDate) {
|
||||
this.termVariationApplicableFrom = applicableFromDate;
|
||||
}
|
||||
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class LoanTermVariationsDataWrapper {
|
||||
|
||||
private final List<LoanTermVariationsData> exceptionData;
|
||||
private ListIterator<LoanTermVariationsData> iterator;
|
||||
private final List<LoanTermVariationsData> interestRateChanges;
|
||||
private final List<LoanTermVariationsData> interestRateFromInstallment;
|
||||
private final List<LoanTermVariationsData> dueDateVariation;
|
||||
private ListIterator<LoanTermVariationsData> dueDateIterator;
|
||||
|
||||
public LoanTermVariationsDataWrapper(final List<LoanTermVariationsData> exceptionData) {
|
||||
if (exceptionData == null) {
|
||||
this.exceptionData = new ArrayList<>(1);
|
||||
} else {
|
||||
this.exceptionData = exceptionData;
|
||||
}
|
||||
this.interestRateChanges = new ArrayList<>();
|
||||
this.dueDateVariation = new ArrayList<>();
|
||||
this.interestRateFromInstallment = new ArrayList<>();
|
||||
deriveLoanTermVariations();
|
||||
}
|
||||
|
||||
public boolean hasVariation(final LocalDate date) {
|
||||
ListIterator<LoanTermVariationsData> iterator = this.iterator;
|
||||
return hasNext(date, iterator);
|
||||
}
|
||||
|
||||
private boolean hasNext(final LocalDate date, ListIterator<LoanTermVariationsData> iterator) {
|
||||
boolean hasVariation = false;
|
||||
if (iterator.hasNext()) {
|
||||
LoanTermVariationsData loanTermVariationsData = iterator.next();
|
||||
if (!loanTermVariationsData.getTermVariationApplicableFrom().isAfter(date)) {
|
||||
hasVariation = true;
|
||||
}
|
||||
iterator.previous();
|
||||
}
|
||||
return hasVariation;
|
||||
}
|
||||
|
||||
public boolean hasDueDateVariation(final LocalDate date) {
|
||||
ListIterator<LoanTermVariationsData> iterator = this.dueDateIterator;
|
||||
return hasNext(date, iterator);
|
||||
}
|
||||
|
||||
public LoanTermVariationsData nextVariation() {
|
||||
return this.iterator.next();
|
||||
}
|
||||
|
||||
public LoanTermVariationsData nextDueDateVariation() {
|
||||
return this.dueDateIterator.next();
|
||||
}
|
||||
|
||||
public LoanTermVariationsData previousDueDateVariation() {
|
||||
return this.dueDateIterator.previous();
|
||||
}
|
||||
|
||||
public List<LoanTermVariationsData> getInterestRateChanges() {
|
||||
return this.interestRateChanges;
|
||||
}
|
||||
|
||||
public List<LoanTermVariationsData> getDueDateVariation() {
|
||||
return this.dueDateVariation;
|
||||
}
|
||||
|
||||
public List<LoanTermVariationsData> getExceptionData() {
|
||||
return this.exceptionData;
|
||||
}
|
||||
|
||||
public void setExceptionData(final List<LoanTermVariationsData> exceptionData) {
|
||||
clearTerms();
|
||||
this.exceptionData.addAll(exceptionData);
|
||||
deriveLoanTermVariations();
|
||||
}
|
||||
|
||||
public void clearTerms() {
|
||||
this.exceptionData.clear();
|
||||
this.interestRateChanges.clear();
|
||||
this.dueDateVariation.clear();
|
||||
this.interestRateFromInstallment.clear();
|
||||
}
|
||||
|
||||
public List<LoanTermVariationsData> getInterestRateFromInstallment() {
|
||||
return this.interestRateFromInstallment;
|
||||
}
|
||||
|
||||
public int adjustNumberOfRepayments() {
|
||||
int repaymetsForAdjust = 0;
|
||||
for (LoanTermVariationsData loanTermVariations : this.exceptionData) {
|
||||
if (loanTermVariations.getTermVariationType().isInsertInstallment()) {
|
||||
repaymetsForAdjust++;
|
||||
} else if (loanTermVariations.getTermVariationType().isDeleteInstallment()) {
|
||||
repaymetsForAdjust--;
|
||||
}
|
||||
}
|
||||
return repaymetsForAdjust;
|
||||
}
|
||||
|
||||
public LoanTermVariationsData fetchLoanTermDueDateVariationsData(final LocalDate onDate) {
|
||||
LoanTermVariationsData data = null;
|
||||
for (LoanTermVariationsData termVariationsData : this.dueDateVariation) {
|
||||
if (onDate.isEqual(termVariationsData.getTermVariationApplicableFrom())) {
|
||||
data = termVariationsData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public boolean hasExceptionVariation(final LocalDate date, ListIterator<LoanTermVariationsData> exceptionDataListIterator) {
|
||||
ListIterator<LoanTermVariationsData> iterator = exceptionDataListIterator;
|
||||
return hasNext(date, iterator);
|
||||
}
|
||||
|
||||
public void updateLoanTermVariationsData(final List<LoanTermVariationsData> exceptionData) {
|
||||
if (this.exceptionData != null && exceptionData != null && exceptionData.size() > 0) {
|
||||
this.exceptionData.addAll(exceptionData);
|
||||
deriveLoanTermVariations();
|
||||
}
|
||||
}
|
||||
|
||||
private void deriveLoanTermVariations() {
|
||||
Collections.sort(this.exceptionData);
|
||||
for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
|
||||
if (loanTermVariationsData.getTermVariationType().isInterestRateVariation()) {
|
||||
this.interestRateChanges.add(loanTermVariationsData);
|
||||
} else if (loanTermVariationsData.getTermVariationType().isDueDateVariation()) {
|
||||
this.dueDateVariation.add(loanTermVariationsData);
|
||||
} else if (loanTermVariationsData.getTermVariationType().isInterestRateFromInstallment()) {
|
||||
this.interestRateFromInstallment.add(loanTermVariationsData);
|
||||
}
|
||||
}
|
||||
Collections.sort(this.dueDateVariation);
|
||||
this.exceptionData.removeAll(this.interestRateChanges);
|
||||
this.exceptionData.removeAll(this.dueDateVariation);
|
||||
this.exceptionData.removeAll(this.interestRateFromInstallment);
|
||||
this.iterator = this.exceptionData.listIterator();
|
||||
this.dueDateIterator = this.dueDateVariation.listIterator();
|
||||
}
|
||||
|
||||
public void resetVariations() {
|
||||
|
||||
for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
|
||||
loanTermVariationsData.setProcessed(false);
|
||||
}
|
||||
this.iterator = this.exceptionData.listIterator();
|
||||
this.dueDateIterator = this.dueDateVariation.listIterator();
|
||||
}
|
||||
|
||||
}
|
||||
+385
@@ -0,0 +1,385 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.account.data.AccountTransferData;
|
||||
import org.apache.fineract.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a loan transaction.
|
||||
*/
|
||||
@Getter
|
||||
public class LoanTransactionData {
|
||||
|
||||
private final Long id;
|
||||
private final Long loanId;
|
||||
private final ExternalId externalLoanId;
|
||||
private final Long officeId;
|
||||
private final String officeName;
|
||||
|
||||
private final LoanTransactionEnumData type;
|
||||
|
||||
private final LocalDate date;
|
||||
|
||||
private final CurrencyData currency;
|
||||
private final PaymentDetailData paymentDetailData;
|
||||
|
||||
private final BigDecimal amount;
|
||||
private final BigDecimal netDisbursalAmount;
|
||||
private final BigDecimal principalPortion;
|
||||
private final BigDecimal interestPortion;
|
||||
private final BigDecimal feeChargesPortion;
|
||||
private final BigDecimal penaltyChargesPortion;
|
||||
private final BigDecimal overpaymentPortion;
|
||||
private final BigDecimal unrecognizedIncomePortion;
|
||||
private final ExternalId externalId;
|
||||
private final AccountTransferData transfer;
|
||||
private final BigDecimal fixedEmiAmount;
|
||||
private final BigDecimal outstandingLoanBalance;
|
||||
private final LocalDate submittedOnDate;
|
||||
private final boolean manuallyReversed;
|
||||
private final LocalDate possibleNextRepaymentDate;
|
||||
|
||||
private Collection<LoanChargePaidByData> loanChargePaidByList;
|
||||
|
||||
// templates
|
||||
final Collection<PaymentTypeData> paymentTypeOptions;
|
||||
|
||||
private Collection<CodeValueData> writeOffReasonOptions = null;
|
||||
|
||||
private Integer numberOfRepayments = 0;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
private String dateFormat;
|
||||
private String locale;
|
||||
private BigDecimal transactionAmount;
|
||||
private LocalDate transactionDate;
|
||||
private Long paymentTypeId;
|
||||
private String accountNumber;
|
||||
private Integer checkNumber;
|
||||
private Integer routingCode;
|
||||
private Integer receiptNumber;
|
||||
private Integer bankNumber;
|
||||
private transient Long accountId;
|
||||
private transient String transactionType;
|
||||
private List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallments;
|
||||
|
||||
// Reverse Data
|
||||
private final ExternalId reversalExternalId;
|
||||
private LocalDate reversedOnDate;
|
||||
|
||||
private List<LoanTransactionRelationData> transactionRelations;
|
||||
|
||||
private Collection<CodeValueData> chargeOffReasonOptions = null;
|
||||
|
||||
public static LoanTransactionData importInstance(BigDecimal repaymentAmount, LocalDate lastRepaymentDate, Long repaymentTypeId,
|
||||
Integer rowIndex, String locale, String dateFormat) {
|
||||
return new LoanTransactionData(repaymentAmount, lastRepaymentDate, repaymentTypeId, rowIndex, locale, dateFormat);
|
||||
}
|
||||
|
||||
private LoanTransactionData(BigDecimal transactionAmount, LocalDate transactionDate, Long paymentTypeId, Integer rowIndex,
|
||||
String locale, String dateFormat) {
|
||||
this.transactionAmount = transactionAmount;
|
||||
this.transactionDate = transactionDate;
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.rowIndex = rowIndex;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.amount = null;
|
||||
this.netDisbursalAmount = null;
|
||||
this.date = null;
|
||||
this.type = null;
|
||||
this.id = null;
|
||||
this.loanId = null;
|
||||
this.externalLoanId = ExternalId.empty();
|
||||
this.officeId = null;
|
||||
this.officeName = null;
|
||||
this.currency = null;
|
||||
this.paymentDetailData = null;
|
||||
this.principalPortion = null;
|
||||
this.interestPortion = null;
|
||||
this.feeChargesPortion = null;
|
||||
this.penaltyChargesPortion = null;
|
||||
this.overpaymentPortion = null;
|
||||
this.unrecognizedIncomePortion = null;
|
||||
this.externalId = ExternalId.empty();
|
||||
this.transfer = null;
|
||||
this.fixedEmiAmount = null;
|
||||
this.outstandingLoanBalance = null;
|
||||
this.submittedOnDate = null;
|
||||
this.manuallyReversed = false;
|
||||
this.possibleNextRepaymentDate = null;
|
||||
this.paymentTypeOptions = null;
|
||||
this.writeOffReasonOptions = null;
|
||||
this.reversalExternalId = ExternalId.empty();
|
||||
}
|
||||
|
||||
public static LoanTransactionData importInstance(BigDecimal repaymentAmount, LocalDate repaymentDate, Long repaymentTypeId,
|
||||
String accountNumber, Integer checkNumber, Integer routingCode, Integer receiptNumber, Integer bankNumber, Long loanAccountId,
|
||||
String transactionType, Integer rowIndex, String locale, String dateFormat) {
|
||||
return new LoanTransactionData(repaymentAmount, repaymentDate, repaymentTypeId, accountNumber, checkNumber, routingCode,
|
||||
receiptNumber, bankNumber, loanAccountId, "", rowIndex, locale, dateFormat);
|
||||
}
|
||||
|
||||
private LoanTransactionData(BigDecimal transactionAmount, LocalDate transactionDate, Long paymentTypeId, String accountNumber,
|
||||
Integer checkNumber, Integer routingCode, Integer receiptNumber, Integer bankNumber, Long accountId, String transactionType,
|
||||
Integer rowIndex, String locale, String dateFormat) {
|
||||
this.transactionAmount = transactionAmount;
|
||||
this.transactionDate = transactionDate;
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.accountNumber = accountNumber;
|
||||
this.checkNumber = checkNumber;
|
||||
this.routingCode = routingCode;
|
||||
this.receiptNumber = receiptNumber;
|
||||
this.bankNumber = bankNumber;
|
||||
this.accountId = accountId;
|
||||
this.transactionType = transactionType;
|
||||
this.rowIndex = rowIndex;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.id = null;
|
||||
this.loanId = null;
|
||||
this.externalLoanId = ExternalId.empty();
|
||||
this.officeId = null;
|
||||
this.officeName = null;
|
||||
this.type = null;
|
||||
this.date = null;
|
||||
this.currency = null;
|
||||
this.paymentDetailData = null;
|
||||
this.amount = null;
|
||||
this.netDisbursalAmount = null;
|
||||
this.principalPortion = null;
|
||||
this.interestPortion = null;
|
||||
this.feeChargesPortion = null;
|
||||
this.penaltyChargesPortion = null;
|
||||
this.overpaymentPortion = null;
|
||||
this.unrecognizedIncomePortion = null;
|
||||
this.externalId = ExternalId.empty();
|
||||
this.transfer = null;
|
||||
this.fixedEmiAmount = null;
|
||||
this.outstandingLoanBalance = null;
|
||||
this.submittedOnDate = null;
|
||||
this.manuallyReversed = false;
|
||||
this.possibleNextRepaymentDate = null;
|
||||
this.paymentTypeOptions = null;
|
||||
this.writeOffReasonOptions = null;
|
||||
this.reversalExternalId = ExternalId.empty();
|
||||
}
|
||||
|
||||
public void setNumberOfRepayments(Integer numberOfRepayments) {
|
||||
this.numberOfRepayments = numberOfRepayments;
|
||||
}
|
||||
|
||||
public void setLoanRepaymentScheduleInstallments(final List<LoanRepaymentScheduleInstallmentData> loanRepaymentScheduleInstallments) {
|
||||
this.loanRepaymentScheduleInstallments = loanRepaymentScheduleInstallments;
|
||||
}
|
||||
|
||||
public static LoanTransactionData templateOnTop(final LoanTransactionData loanTransactionData,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions) {
|
||||
return new LoanTransactionData(loanTransactionData.id, loanTransactionData.officeId, loanTransactionData.officeName,
|
||||
loanTransactionData.type, loanTransactionData.paymentDetailData, loanTransactionData.currency, loanTransactionData.date,
|
||||
loanTransactionData.amount, loanTransactionData.netDisbursalAmount, loanTransactionData.principalPortion,
|
||||
loanTransactionData.interestPortion, loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion,
|
||||
loanTransactionData.overpaymentPortion, loanTransactionData.unrecognizedIncomePortion, paymentTypeOptions,
|
||||
loanTransactionData.externalId, loanTransactionData.transfer, loanTransactionData.fixedEmiAmount,
|
||||
loanTransactionData.outstandingLoanBalance, loanTransactionData.manuallyReversed, loanTransactionData.loanId,
|
||||
loanTransactionData.externalLoanId);
|
||||
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount,
|
||||
final BigDecimal netDisbursalAmount, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion,
|
||||
final ExternalId externalId, final AccountTransferData transfer, BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance,
|
||||
final BigDecimal unrecognizedIncomePortion, final boolean manuallyReversed, Long loanId, ExternalId externalLoanId) {
|
||||
this(id, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, netDisbursalAmount, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion, null, externalId,
|
||||
transfer, fixedEmiAmount, outstandingLoanBalance, manuallyReversed, loanId, externalLoanId);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount,
|
||||
final BigDecimal netDisbursalAmount, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion,
|
||||
BigDecimal unrecognizedIncomePortion, final Collection<PaymentTypeData> paymentTypeOptions, final ExternalId externalId,
|
||||
final AccountTransferData transfer, final BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance,
|
||||
boolean manuallyReversed, Long loanId, ExternalId externalLoanId) {
|
||||
this(id, externalLoanId, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, netDisbursalAmount,
|
||||
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion,
|
||||
paymentTypeOptions, externalId, transfer, fixedEmiAmount, outstandingLoanBalance, null, manuallyReversed,
|
||||
ExternalId.empty(), null, loanId);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount,
|
||||
final BigDecimal netDisbursalAmount, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion,
|
||||
final BigDecimal unrecognizedIncomePortion, final ExternalId externalId, final AccountTransferData transfer,
|
||||
BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance, LocalDate submittedOnDate, final boolean manuallyReversed,
|
||||
final ExternalId reversalExternalId, final LocalDate reversedOnDate, Long loanId, ExternalId externalLoanId) {
|
||||
this(id, externalLoanId, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, netDisbursalAmount,
|
||||
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion,
|
||||
null, externalId, transfer, fixedEmiAmount, outstandingLoanBalance, submittedOnDate, manuallyReversed, reversalExternalId,
|
||||
reversedOnDate, loanId);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final ExternalId externalLoanId, final Long officeId, final String officeName,
|
||||
final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData, final CurrencyData currency,
|
||||
final LocalDate date, final BigDecimal amount, final BigDecimal netDisbursalAmount, final BigDecimal principalPortion,
|
||||
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion,
|
||||
final BigDecimal overpaymentPortion, final BigDecimal unrecognizedIncomePortion,
|
||||
final Collection<PaymentTypeData> paymentTypeOptions, final ExternalId externalId, final AccountTransferData transfer,
|
||||
final BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance, final LocalDate submittedOnDate,
|
||||
final boolean manuallyReversed, final ExternalId reversalExternalId, final LocalDate reversedOnDate, Long loanId) {
|
||||
this.id = id;
|
||||
this.loanId = loanId;
|
||||
this.externalLoanId = externalLoanId;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
this.type = transactionType;
|
||||
this.paymentDetailData = paymentDetailData;
|
||||
this.currency = currency;
|
||||
this.date = date;
|
||||
this.amount = amount;
|
||||
this.netDisbursalAmount = netDisbursalAmount;
|
||||
this.principalPortion = principalPortion;
|
||||
this.interestPortion = interestPortion;
|
||||
this.feeChargesPortion = feeChargesPortion;
|
||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||
this.unrecognizedIncomePortion = unrecognizedIncomePortion;
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
this.externalId = externalId;
|
||||
this.transfer = transfer;
|
||||
this.overpaymentPortion = overpaymentPortion;
|
||||
this.fixedEmiAmount = fixedEmiAmount;
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.manuallyReversed = manuallyReversed;
|
||||
this.possibleNextRepaymentDate = null;
|
||||
this.reversalExternalId = reversalExternalId;
|
||||
this.reversedOnDate = reversedOnDate;
|
||||
}
|
||||
|
||||
public LoanTransactionData(Long id, LoanTransactionEnumData transactionType, LocalDate date, BigDecimal totalAmount,
|
||||
BigDecimal netDisbursalAmount, BigDecimal principalPortion, BigDecimal interestPortion, BigDecimal feeChargesPortion,
|
||||
BigDecimal penaltyChargesPortion, BigDecimal overpaymentPortion, BigDecimal unrecognizedIncomePortion,
|
||||
BigDecimal outstandingLoanBalance, final boolean manuallyReversed, ExternalId externalId, Long loanId,
|
||||
ExternalId externalLoanId) {
|
||||
this(id, externalLoanId, null, null, transactionType, null, null, date, totalAmount, netDisbursalAmount, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion, null, externalId,
|
||||
null, null, outstandingLoanBalance, null, manuallyReversed, ExternalId.empty(), null, loanId);
|
||||
}
|
||||
|
||||
public static LoanTransactionData loanTransactionDataForDisbursalTemplate(final LoanTransactionEnumData transactionType,
|
||||
final LocalDate expectedDisbursedOnLocalDateForTemplate, final BigDecimal disburseAmountForTemplate,
|
||||
final BigDecimal netDisbursalAmount, final Collection<PaymentTypeData> paymentOptions, final BigDecimal retriveLastEmiAmount,
|
||||
final LocalDate possibleNextRepaymentDate) {
|
||||
final Long id = null;
|
||||
final Long loanId = null;
|
||||
final ExternalId externalLoanId = ExternalId.empty();
|
||||
final Long officeId = null;
|
||||
final String officeName = null;
|
||||
final PaymentDetailData paymentDetailData = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal unrecognizedIncomePortion = null;
|
||||
final BigDecimal principalPortion = null;
|
||||
final BigDecimal interestPortion = null;
|
||||
final BigDecimal feeChargesPortion = null;
|
||||
final BigDecimal penaltyChargesPortion = null;
|
||||
final BigDecimal overpaymentPortion = null;
|
||||
final ExternalId externalId = ExternalId.empty();
|
||||
final BigDecimal outstandingLoanBalance = null;
|
||||
final AccountTransferData transfer = null;
|
||||
final LocalDate submittedOnDate = null;
|
||||
final boolean manuallyReversed = false;
|
||||
return new LoanTransactionData(id, officeId, officeName, transactionType, paymentDetailData, currency,
|
||||
expectedDisbursedOnLocalDateForTemplate, disburseAmountForTemplate, netDisbursalAmount, principalPortion, interestPortion,
|
||||
feeChargesPortion, penaltyChargesPortion, overpaymentPortion, unrecognizedIncomePortion, paymentOptions, transfer,
|
||||
externalId, retriveLastEmiAmount, outstandingLoanBalance, submittedOnDate, manuallyReversed, possibleNextRepaymentDate,
|
||||
loanId, externalLoanId);
|
||||
|
||||
}
|
||||
|
||||
private LoanTransactionData(Long id, final Long officeId, final String officeName, LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, BigDecimal amount,
|
||||
BigDecimal netDisbursalAmount, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion,
|
||||
BigDecimal unrecognizedIncomePortion, Collection<PaymentTypeData> paymentOptions, final AccountTransferData transfer,
|
||||
final ExternalId externalId, final BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance,
|
||||
final LocalDate submittedOnDate, final boolean manuallyReversed, final LocalDate possibleNextRepaymentDate, Long loanId,
|
||||
ExternalId externalLoanId) {
|
||||
this.id = id;
|
||||
this.loanId = loanId;
|
||||
this.externalLoanId = externalLoanId;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
this.type = transactionType;
|
||||
this.paymentDetailData = paymentDetailData;
|
||||
this.currency = currency;
|
||||
this.date = date;
|
||||
this.amount = amount;
|
||||
this.netDisbursalAmount = netDisbursalAmount;
|
||||
this.principalPortion = principalPortion;
|
||||
this.interestPortion = interestPortion;
|
||||
this.feeChargesPortion = feeChargesPortion;
|
||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||
this.unrecognizedIncomePortion = unrecognizedIncomePortion;
|
||||
this.paymentTypeOptions = paymentOptions;
|
||||
this.externalId = externalId;
|
||||
this.transfer = transfer;
|
||||
this.overpaymentPortion = overpaymentPortion;
|
||||
this.fixedEmiAmount = fixedEmiAmount;
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.manuallyReversed = manuallyReversed;
|
||||
this.possibleNextRepaymentDate = possibleNextRepaymentDate;
|
||||
this.reversalExternalId = ExternalId.empty();
|
||||
}
|
||||
|
||||
public boolean isNotDisbursement() {
|
||||
return type.getId() == 1;
|
||||
}
|
||||
|
||||
public void setWriteOffReasonOptions(Collection<CodeValueData> writeOffReasonOptions) {
|
||||
this.writeOffReasonOptions = writeOffReasonOptions;
|
||||
}
|
||||
|
||||
public void setChargeOffReasonOptions(Collection<CodeValueData> chargeOffReasonOptions) {
|
||||
this.chargeOffReasonOptions = chargeOffReasonOptions;
|
||||
}
|
||||
|
||||
public void setLoanChargePaidByList(Collection<LoanChargePaidByData> loanChargePaidByList) {
|
||||
this.loanChargePaidByList = loanChargePaidByList;
|
||||
}
|
||||
|
||||
public void setLoanTransactionRelations(List<LoanTransactionRelationData> transactionRelations) {
|
||||
this.transactionRelations = transactionRelations;
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Immutable data object represent loan status enumerations.
|
||||
*/
|
||||
@Getter
|
||||
public class LoanTransactionEnumData {
|
||||
|
||||
private final Long id;
|
||||
private final String code;
|
||||
private final String value;
|
||||
|
||||
private final boolean disbursement;
|
||||
private final boolean repaymentAtDisbursement;
|
||||
private final boolean repayment;
|
||||
private final boolean merchantIssuedRefund;
|
||||
private final boolean payoutRefund;
|
||||
private final boolean goodwillCredit;
|
||||
private final boolean chargeRefund;
|
||||
private final boolean contra;
|
||||
private final boolean waiveInterest;
|
||||
private final boolean waiveCharges;
|
||||
private final boolean accrual;
|
||||
private final boolean writeOff;
|
||||
private final boolean recoveryRepayment;
|
||||
private final boolean initiateTransfer;
|
||||
private final boolean approveTransfer;
|
||||
private final boolean withdrawTransfer;
|
||||
private final boolean rejectTransfer;
|
||||
private final boolean chargePayment;
|
||||
private final boolean refund;
|
||||
private final boolean refundForActiveLoans;
|
||||
private final boolean creditBalanceRefund;
|
||||
private final boolean chargeAdjustment;
|
||||
private final boolean chargeback;
|
||||
private final boolean chargeoff;
|
||||
|
||||
public LoanTransactionEnumData(final Long id, final String code, final String value) {
|
||||
this.id = id;
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.disbursement = Long.valueOf(1).equals(this.id);
|
||||
this.repaymentAtDisbursement = Long.valueOf(5).equals(this.id);
|
||||
this.repayment = Long.valueOf(2).equals(this.id);
|
||||
this.merchantIssuedRefund = Long.valueOf(21).equals(this.id);
|
||||
this.payoutRefund = Long.valueOf(22).equals(this.id);
|
||||
this.goodwillCredit = Long.valueOf(23).equals(this.id);
|
||||
this.chargeRefund = Long.valueOf(24).equals(this.id);
|
||||
this.contra = Long.valueOf(3).equals(this.id);
|
||||
this.waiveInterest = Long.valueOf(4).equals(this.id);
|
||||
this.waiveCharges = Long.valueOf(9).equals(this.id);
|
||||
this.accrual = Long.valueOf(10).equals(this.id);
|
||||
this.writeOff = Long.valueOf(6).equals(this.id);
|
||||
this.recoveryRepayment = Long.valueOf(8).equals(this.id);
|
||||
this.initiateTransfer = Long.valueOf(12).equals(this.id);
|
||||
this.approveTransfer = Long.valueOf(13).equals(this.id);
|
||||
this.withdrawTransfer = Long.valueOf(14).equals(this.id);
|
||||
this.rejectTransfer = Long.valueOf(15).equals(this.id);
|
||||
this.refund = Long.valueOf(16).equals(this.id);
|
||||
this.chargePayment = Long.valueOf(17).equals(this.id);
|
||||
this.refundForActiveLoans = Long.valueOf(18).equals(this.id);
|
||||
this.creditBalanceRefund = Long.valueOf(20).equals(this.id);
|
||||
this.chargeback = Long.valueOf(25).equals(this.id);
|
||||
this.chargeAdjustment = Long.valueOf(26).equals(this.id);
|
||||
this.chargeoff = Long.valueOf(27).equals(this.id);
|
||||
}
|
||||
|
||||
public boolean isRepaymentType() {
|
||||
if (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit() || isChargeRefund()
|
||||
|| isChargeAdjustment()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public class LoanTransactionRelationData implements Serializable {
|
||||
|
||||
private Long fromLoanTransaction;
|
||||
private Long toLoanTransaction;
|
||||
private Long toLoanCharge;
|
||||
private LoanTransactionRelationTypeEnum relationType;
|
||||
private BigDecimal amount;
|
||||
private String paymentType;
|
||||
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||
|
||||
public class ScheduleGeneratorDTO {
|
||||
|
||||
final LoanScheduleGeneratorFactory loanScheduleFactory;
|
||||
final ApplicationCurrency applicationCurrency;
|
||||
final LocalDate calculatedRepaymentsStartingFromDate;
|
||||
final HolidayDetailDTO holidayDetailDTO;
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation;
|
||||
final CalendarInstance compoundingCalendarInstance;
|
||||
LocalDate recalculateFrom;
|
||||
final Long overdurPenaltyWaitPeriod;
|
||||
final FloatingRateDTO floatingRateDTO;
|
||||
final Calendar calendar;
|
||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper;
|
||||
final Boolean isInterestChargedFromDateAsDisbursementDateEnabled;
|
||||
final Integer numberOfdays;
|
||||
final boolean isSkipRepaymentOnFirstDayofMonth;
|
||||
final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
|
||||
final boolean isFirstRepaymentDateAllowedOnHoliday;
|
||||
final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI;
|
||||
final boolean isPrincipalCompoundingDisabledForOverdueLoans;
|
||||
|
||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
||||
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod, final FloatingRateDTO floatingRateDTO,
|
||||
final Calendar calendar, final CalendarHistoryDataWrapper calendarHistoryDataWrapper,
|
||||
final Boolean isInterestChargedFromDateAsDisbursementDateEnabled, final Integer numberOfdays,
|
||||
final boolean isSkipRepaymentOnFirstDayofMonth, final Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled,
|
||||
final boolean isFirstRepaymentDateAllowedOnHoliday, final boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI,
|
||||
final boolean isPrincipalCompoundingDisabledForOverdueLoans) {
|
||||
|
||||
this.loanScheduleFactory = loanScheduleFactory;
|
||||
this.applicationCurrency = applicationCurrency;
|
||||
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
|
||||
this.calendarInstanceForInterestRecalculation = calendarInstanceForInterestRecalculation;
|
||||
this.compoundingCalendarInstance = compoundingCalendarInstance;
|
||||
this.recalculateFrom = recalculateFrom;
|
||||
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
|
||||
this.holidayDetailDTO = holidayDetailDTO;
|
||||
this.floatingRateDTO = floatingRateDTO;
|
||||
this.calendar = calendar;
|
||||
this.calendarHistoryDataWrapper = calendarHistoryDataWrapper;
|
||||
this.isInterestChargedFromDateAsDisbursementDateEnabled = isInterestChargedFromDateAsDisbursementDateEnabled;
|
||||
this.numberOfdays = numberOfdays;
|
||||
this.isSkipRepaymentOnFirstDayofMonth = isSkipRepaymentOnFirstDayofMonth;
|
||||
this.isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled = isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
|
||||
this.isFirstRepaymentDateAllowedOnHoliday = isFirstRepaymentDateAllowedOnHoliday;
|
||||
this.isInterestToBeRecoveredFirstWhenGreaterThanEMI = isInterestToBeRecoveredFirstWhenGreaterThanEMI;
|
||||
this.isPrincipalCompoundingDisabledForOverdueLoans = isPrincipalCompoundingDisabledForOverdueLoans;
|
||||
}
|
||||
|
||||
public LoanScheduleGeneratorFactory getLoanScheduleFactory() {
|
||||
return this.loanScheduleFactory;
|
||||
}
|
||||
|
||||
public ApplicationCurrency getApplicationCurrency() {
|
||||
return this.applicationCurrency;
|
||||
}
|
||||
|
||||
public LocalDate getCalculatedRepaymentsStartingFromDate() {
|
||||
return this.calculatedRepaymentsStartingFromDate;
|
||||
}
|
||||
|
||||
public CalendarInstance getCalendarInstanceForInterestRecalculation() {
|
||||
return this.calendarInstanceForInterestRecalculation;
|
||||
}
|
||||
|
||||
public LocalDate getRecalculateFrom() {
|
||||
return this.recalculateFrom;
|
||||
}
|
||||
|
||||
public Long getOverdurPenaltyWaitPeriod() {
|
||||
return this.overdurPenaltyWaitPeriod;
|
||||
}
|
||||
|
||||
public int getPenaltyWaitPeriod() {
|
||||
int penaltyWaitPeriod = 0;
|
||||
if (this.overdurPenaltyWaitPeriod != null) {
|
||||
penaltyWaitPeriod = this.overdurPenaltyWaitPeriod.intValue();
|
||||
}
|
||||
return penaltyWaitPeriod;
|
||||
}
|
||||
|
||||
public HolidayDetailDTO getHolidayDetailDTO() {
|
||||
return this.holidayDetailDTO;
|
||||
}
|
||||
|
||||
public void setRecalculateFrom(LocalDate recalculateFrom) {
|
||||
this.recalculateFrom = recalculateFrom;
|
||||
}
|
||||
|
||||
public CalendarInstance getCompoundingCalendarInstance() {
|
||||
return this.compoundingCalendarInstance;
|
||||
}
|
||||
|
||||
public FloatingRateDTO getFloatingRateDTO() {
|
||||
return this.floatingRateDTO;
|
||||
}
|
||||
|
||||
public Calendar getCalendar() {
|
||||
return this.calendar;
|
||||
}
|
||||
|
||||
public CalendarHistoryDataWrapper getCalendarHistoryDataWrapper() {
|
||||
return this.calendarHistoryDataWrapper;
|
||||
}
|
||||
|
||||
public Boolean isInterestChargedFromDateAsDisbursementDateEnabled() {
|
||||
return this.isInterestChargedFromDateAsDisbursementDateEnabled;
|
||||
}
|
||||
|
||||
public Integer getNumberOfdays() {
|
||||
return numberOfdays;
|
||||
}
|
||||
|
||||
public boolean isSkipRepaymentOnFirstDayofMonth() {
|
||||
return isSkipRepaymentOnFirstDayofMonth;
|
||||
}
|
||||
|
||||
public Boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled() {
|
||||
return this.isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled;
|
||||
}
|
||||
|
||||
public boolean isFirstRepaymentDateAllowedOnHoliday() {
|
||||
return isFirstRepaymentDateAllowedOnHoliday;
|
||||
}
|
||||
|
||||
public boolean isInterestToBeRecoveredFirstWhenGreaterThanEMI() {
|
||||
return isInterestToBeRecoveredFirstWhenGreaterThanEMI;
|
||||
}
|
||||
|
||||
public boolean isPrincipalCompoundingDisabledForOverdueLoans() {
|
||||
return isPrincipalCompoundingDisabledForOverdueLoans;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Stores details of {@link LoanTransaction}'s that were reversed or newly created
|
||||
*/
|
||||
public class ChangedTransactionDetail {
|
||||
|
||||
private final Map<Long, LoanTransaction> newTransactionMappings = new LinkedHashMap<>();
|
||||
|
||||
public Map<Long, LoanTransaction> getNewTransactionMappings() {
|
||||
return this.newTransactionMappings;
|
||||
}
|
||||
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
|
||||
@Entity
|
||||
@Table(name = "glim_accounts", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_number" }, name = "FK_glim_id") })
|
||||
public class GroupLoanIndividualMonitoringAccount extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "group_id", nullable = false)
|
||||
private Group group;
|
||||
|
||||
@Column(name = "account_number", nullable = false)
|
||||
private String accountNumber;
|
||||
|
||||
@Column(name = "principal_amount")
|
||||
private BigDecimal principalAmount;
|
||||
|
||||
@Column(name = "child_accounts_count")
|
||||
private Long childAccountsCount;
|
||||
|
||||
@Column(name = "accepting_child")
|
||||
private Boolean isAcceptingChild;
|
||||
|
||||
@OneToMany
|
||||
private Set<Loan> childLoan;
|
||||
|
||||
@Column(name = "loan_status_id", nullable = false)
|
||||
private Integer loanStatus;
|
||||
|
||||
@Column(name = "application_id", nullable = true)
|
||||
private BigDecimal applicationId;
|
||||
|
||||
protected GroupLoanIndividualMonitoringAccount() {}
|
||||
|
||||
private GroupLoanIndividualMonitoringAccount(String accountNumber, Group group, BigDecimal principalAmount, Long childAccountsCount,
|
||||
Boolean isAcceptingChild, Integer loanStatus, BigDecimal applicationId) {
|
||||
this.accountNumber = accountNumber;
|
||||
this.group = group;
|
||||
this.principalAmount = principalAmount;
|
||||
this.childAccountsCount = childAccountsCount;
|
||||
this.isAcceptingChild = isAcceptingChild;
|
||||
this.loanStatus = loanStatus;
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
|
||||
public static GroupLoanIndividualMonitoringAccount getInstance(String accountNumber, Group group, BigDecimal principalAmount,
|
||||
Long childAccountsCount, Boolean isAcceptingChild, Integer loanStatus, BigDecimal applicationId) {
|
||||
return new GroupLoanIndividualMonitoringAccount(accountNumber, group, principalAmount, childAccountsCount, isAcceptingChild,
|
||||
loanStatus, applicationId);
|
||||
}
|
||||
|
||||
public String getAccountNumber() {
|
||||
return accountNumber;
|
||||
}
|
||||
|
||||
public Group getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(Group group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public void setAccountNumber(String accountNumber) {
|
||||
this.accountNumber = accountNumber;
|
||||
}
|
||||
|
||||
public Set<Loan> getChildLoan() {
|
||||
return childLoan;
|
||||
}
|
||||
|
||||
public void setChildLoan(Set<Loan> childLoan) {
|
||||
this.childLoan = childLoan;
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalAmount() {
|
||||
return principalAmount;
|
||||
}
|
||||
|
||||
public void setPrincipalAmount(BigDecimal principalAmount) {
|
||||
this.principalAmount = principalAmount;
|
||||
}
|
||||
|
||||
public Long getChildAccountsCount() {
|
||||
return childAccountsCount;
|
||||
}
|
||||
|
||||
public void setChildAccountsCount(Long childAccountsCount) {
|
||||
this.childAccountsCount = childAccountsCount;
|
||||
}
|
||||
|
||||
public Boolean getIsAcceptingChild() {
|
||||
return isAcceptingChild;
|
||||
}
|
||||
|
||||
public void setIsAcceptingChild(Boolean isAcceptingChild) {
|
||||
this.isAcceptingChild = isAcceptingChild;
|
||||
}
|
||||
|
||||
public Integer getLoanStatus() {
|
||||
return loanStatus;
|
||||
}
|
||||
|
||||
public void setLoanStatus(Integer loanStatus) {
|
||||
this.loanStatus = loanStatus;
|
||||
}
|
||||
|
||||
public BigDecimal getApplicationId() {
|
||||
return applicationId;
|
||||
}
|
||||
|
||||
public void setApplicationId(BigDecimal applicationId) {
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
}
|
||||
+7043
File diff suppressed because it is too large
Load Diff
+1056
File diff suppressed because it is too large
Load Diff
+86
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_charge_paid_by")
|
||||
public class LoanChargePaidBy extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_transaction_id", nullable = false)
|
||||
private LoanTransaction loanTransaction;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_charge_id", nullable = false)
|
||||
private LoanCharge loanCharge;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "installment_number", nullable = true)
|
||||
private Integer installmentNumber;
|
||||
|
||||
protected LoanChargePaidBy() {
|
||||
|
||||
}
|
||||
|
||||
public LoanChargePaidBy(final LoanTransaction loanTransaction, final LoanCharge loanCharge, final BigDecimal amount,
|
||||
Integer installmentNumber) {
|
||||
this.loanTransaction = loanTransaction;
|
||||
this.loanCharge = loanCharge;
|
||||
this.amount = amount;
|
||||
this.installmentNumber = installmentNumber;
|
||||
}
|
||||
|
||||
public LoanTransaction getLoanTransaction() {
|
||||
return this.loanTransaction;
|
||||
}
|
||||
|
||||
public void setLoanTransaction(final LoanTransaction loanTransaction) {
|
||||
this.loanTransaction = loanTransaction;
|
||||
}
|
||||
|
||||
public LoanCharge getLoanCharge() {
|
||||
return this.loanCharge;
|
||||
}
|
||||
|
||||
public void setLoanCharge(final LoanCharge loanCharge) {
|
||||
this.loanCharge = loanCharge;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public void setAmount(final BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public Integer getInstallmentNumber() {
|
||||
return this.installmentNumber;
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanCollateralManagementData;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_collateral_management")
|
||||
public class LoanCollateralManagement extends AbstractPersistableCustom {
|
||||
|
||||
@Column(name = "quantity", nullable = false, scale = 5, precision = 20)
|
||||
private BigDecimal quantity;
|
||||
|
||||
@ManyToOne()
|
||||
@JoinColumn(name = "transaction_id")
|
||||
private LoanTransaction loanTransaction = null;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id", referencedColumnName = "id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@Column(name = "is_released", nullable = false)
|
||||
private boolean isReleased = false;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "client_collateral_id", nullable = false)
|
||||
private ClientCollateralManagement clientCollateralManagement;
|
||||
|
||||
public LoanCollateralManagement() {
|
||||
|
||||
}
|
||||
|
||||
public LoanCollateralManagement(final BigDecimal quantity, final boolean isReleased) {
|
||||
this.quantity = quantity;
|
||||
this.isReleased = isReleased;
|
||||
}
|
||||
|
||||
private LoanCollateralManagement(final BigDecimal quantity, final ClientCollateralManagement clientCollateralManagement) {
|
||||
this.clientCollateralManagement = clientCollateralManagement;
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public void setLoan(Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
public static LoanCollateralManagement from(final ClientCollateralManagement clientCollateralManagement, final BigDecimal quantity) {
|
||||
return new LoanCollateralManagement(quantity, clientCollateralManagement);
|
||||
}
|
||||
|
||||
public static LoanCollateralManagement fromExisting(final ClientCollateralManagement clientCollateralManagement,
|
||||
final BigDecimal quantity, final Loan loan, final LoanTransaction transaction, final Long id) {
|
||||
LoanCollateralManagement loanCollateralManagementInstance = new LoanCollateralManagement(quantity, clientCollateralManagement);
|
||||
loanCollateralManagementInstance.setLoan(loan);
|
||||
loanCollateralManagementInstance.setLoanTransactionData(transaction);
|
||||
loanCollateralManagementInstance.setId(id);
|
||||
return loanCollateralManagementInstance;
|
||||
}
|
||||
|
||||
public void setClientCollateralManagement(final ClientCollateralManagement clientCollateralManagement) {
|
||||
this.clientCollateralManagement = clientCollateralManagement;
|
||||
}
|
||||
|
||||
public void setLoanTransactionData(final LoanTransaction loanTransaction) {
|
||||
this.loanTransaction = loanTransaction;
|
||||
}
|
||||
|
||||
public void setIsReleased(final boolean isReleased) {
|
||||
this.isReleased = isReleased;
|
||||
}
|
||||
|
||||
public void setQuantity(final BigDecimal quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public BigDecimal getQuantity() {
|
||||
return this.quantity;
|
||||
}
|
||||
|
||||
public Loan getLoanData() {
|
||||
return this.loan;
|
||||
}
|
||||
|
||||
public LoanTransaction getLoanTransaction() {
|
||||
return this.loanTransaction;
|
||||
}
|
||||
|
||||
public ClientCollateralManagement getClientCollateralManagement() {
|
||||
return this.clientCollateralManagement;
|
||||
}
|
||||
|
||||
public boolean isReleased() {
|
||||
return this.isReleased;
|
||||
}
|
||||
|
||||
public LoanCollateralManagementData toCommand() {
|
||||
return new LoanCollateralManagementData(this.clientCollateralManagement.getId(), this.getQuantity(), null, null, getId());
|
||||
}
|
||||
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_disbursement_detail")
|
||||
public class LoanDisbursementDetails extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@Column(name = "expected_disburse_date")
|
||||
private LocalDate expectedDisbursementDate;
|
||||
|
||||
@Column(name = "disbursedon_date")
|
||||
private LocalDate actualDisbursementDate;
|
||||
|
||||
@Column(name = "principal", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal principal;
|
||||
|
||||
@Column(name = "net_disbursal_amount", scale = 6, precision = 19)
|
||||
private BigDecimal netDisbursalAmount;
|
||||
|
||||
@Column(name = "is_reversed", nullable = false)
|
||||
private boolean reversed;
|
||||
|
||||
protected LoanDisbursementDetails() {
|
||||
|
||||
}
|
||||
|
||||
public LoanDisbursementDetails(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
|
||||
final BigDecimal principal, final BigDecimal netDisbursalAmount, final boolean reversed) {
|
||||
this.expectedDisbursementDate = expectedDisbursementDate;
|
||||
this.actualDisbursementDate = actualDisbursementDate;
|
||||
this.principal = principal;
|
||||
this.netDisbursalAmount = netDisbursalAmount;
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
public void updateLoan(final Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof LoanDisbursementDetails)) {
|
||||
return false;
|
||||
}
|
||||
final LoanDisbursementDetails loanDisbursementDetails = (LoanDisbursementDetails) obj;
|
||||
if (loanDisbursementDetails.principal.equals(this.principal)
|
||||
&& loanDisbursementDetails.expectedDisbursementDate.compareTo(this.expectedDisbursementDate) == 0 ? Boolean.TRUE
|
||||
: Boolean.FALSE) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(expectedDisbursementDate, principal);
|
||||
}
|
||||
|
||||
public void copy(final LoanDisbursementDetails disbursementDetails) {
|
||||
this.principal = disbursementDetails.principal;
|
||||
this.expectedDisbursementDate = disbursementDetails.expectedDisbursementDate;
|
||||
this.actualDisbursementDate = disbursementDetails.actualDisbursementDate;
|
||||
this.reversed = disbursementDetails.reversed;
|
||||
}
|
||||
|
||||
public LocalDate expectedDisbursementDate() {
|
||||
return this.expectedDisbursementDate;
|
||||
}
|
||||
|
||||
public LocalDate expectedDisbursementDateAsLocalDate() {
|
||||
LocalDate expectedDisburseDate = null;
|
||||
if (this.expectedDisbursementDate != null) {
|
||||
expectedDisburseDate = this.expectedDisbursementDate;
|
||||
}
|
||||
return expectedDisburseDate;
|
||||
}
|
||||
|
||||
public LocalDate actualDisbursementDate() {
|
||||
return this.actualDisbursementDate;
|
||||
}
|
||||
|
||||
public BigDecimal principal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public void updatePrincipal(BigDecimal principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public LocalDate getDisbursementDate() {
|
||||
return this.actualDisbursementDate;
|
||||
}
|
||||
|
||||
public DisbursementData toData() {
|
||||
LocalDate expectedDisburseDate = expectedDisbursementDateAsLocalDate();
|
||||
BigDecimal waivedChargeAmount = null;
|
||||
return new DisbursementData(getId(), expectedDisburseDate, this.actualDisbursementDate, this.principal, this.netDisbursalAmount,
|
||||
null, null, waivedChargeAmount);
|
||||
}
|
||||
|
||||
public void updateActualDisbursementDate(LocalDate actualDisbursementDate) {
|
||||
this.actualDisbursementDate = actualDisbursementDate;
|
||||
}
|
||||
|
||||
public BigDecimal getNetDisbursalAmount() {
|
||||
return this.netDisbursalAmount;
|
||||
}
|
||||
|
||||
public void setNetDisbursalAmount(BigDecimal netDisbursalAmount) {
|
||||
this.netDisbursalAmount = netDisbursalAmount;
|
||||
}
|
||||
|
||||
public void updateExpectedDisbursementDateAndAmount(LocalDate expectedDisbursementDate, BigDecimal principal) {
|
||||
this.expectedDisbursementDate = expectedDisbursementDate;
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public void reverse() {
|
||||
this.reversed = true;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return reversed;
|
||||
}
|
||||
}
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public enum LoanEvent {
|
||||
|
||||
LOAN_CREATED, //
|
||||
LOAN_REJECTED, //
|
||||
LOAN_WITHDRAWN, //
|
||||
LOAN_APPROVED, //
|
||||
LOAN_APPROVAL_UNDO, //
|
||||
LOAN_RECOVERY_PAYMENT, //
|
||||
LOAN_DISBURSED, //
|
||||
LOAN_DISBURSAL_UNDO, //
|
||||
LOAN_DISBURSAL_UNDO_LAST, //
|
||||
LOAN_REPAYMENT_OR_WAIVER, //
|
||||
REPAID_IN_FULL, //
|
||||
WRITE_OFF_OUTSTANDING, //
|
||||
WRITE_OFF_OUTSTANDING_UNDO, //
|
||||
LOAN_RESCHEDULE, //
|
||||
INTERST_REBATE_OWED, //
|
||||
LOAN_OVERPAYMENT, //
|
||||
LOAN_CHARGE_PAYMENT, //
|
||||
LOAN_CLOSED, //
|
||||
LOAN_EDIT_MULTI_DISBURSE_DATE, //
|
||||
LOAN_REFUND, //
|
||||
LOAN_FORECLOSURE, //
|
||||
LOAN_ADJUST_TRANSACTION, //
|
||||
LOAN_INITIATE_TRANSFER, //
|
||||
LOAN_REJECT_TRANSFER, //
|
||||
LOAN_WITHDRAW_TRANSFER, //
|
||||
LOAN_CREDIT_BALANCE_REFUND, //
|
||||
LOAN_CHARGEBACK, //
|
||||
LOAN_CHARGE_ADDED, //
|
||||
LOAN_CHARGE_ADJUSTMENT;
|
||||
}
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_installment_charge")
|
||||
public class LoanInstallmentCharge extends AbstractPersistableCustom implements Comparable<LoanInstallmentCharge> {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false)
|
||||
private LoanCharge loancharge;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_schedule_id", nullable = false)
|
||||
private LoanRepaymentScheduleInstallment installment;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "amount_paid_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountPaid;
|
||||
|
||||
@Column(name = "amount_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountWaived;
|
||||
|
||||
@Column(name = "amount_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountWrittenOff;
|
||||
|
||||
@Column(name = "amount_outstanding_derived", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amountOutstanding;
|
||||
|
||||
@Column(name = "amount_through_charge_payment", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountThroughChargePayment;
|
||||
|
||||
@Column(name = "is_paid_derived", nullable = false)
|
||||
private boolean paid = false;
|
||||
|
||||
@Column(name = "waived", nullable = false)
|
||||
private boolean waived = false;
|
||||
|
||||
public LoanInstallmentCharge() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(LoanInstallmentCharge o) {
|
||||
return this.installment.getInstallmentNumber().compareTo(o.installment.getInstallmentNumber());
|
||||
}
|
||||
|
||||
public LoanInstallmentCharge(final BigDecimal amount, final LoanCharge loancharge, final LoanRepaymentScheduleInstallment installment) {
|
||||
this.loancharge = loancharge;
|
||||
this.installment = installment;
|
||||
this.amount = amount;
|
||||
this.amountOutstanding = amount;
|
||||
this.amountPaid = null;
|
||||
this.amountWaived = null;
|
||||
this.amountWrittenOff = null;
|
||||
}
|
||||
|
||||
public void copyFrom(final LoanInstallmentCharge loanChargePerInstallment) {
|
||||
this.amount = loanChargePerInstallment.amount;
|
||||
this.installment = loanChargePerInstallment.installment;
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
this.paid = determineIfFullyPaid();
|
||||
}
|
||||
|
||||
public Money waive(final MonetaryCurrency currency) {
|
||||
this.amountWaived = this.amountOutstanding;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.paid = false;
|
||||
this.waived = true;
|
||||
return getAmountWaived(currency);
|
||||
}
|
||||
|
||||
public Money getAmountWaived(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountWaived);
|
||||
}
|
||||
|
||||
private boolean determineIfFullyPaid() {
|
||||
if (this.amount == null) {
|
||||
return true;
|
||||
}
|
||||
return BigDecimal.ZERO.compareTo(calculateOutstanding()) == 0;
|
||||
}
|
||||
|
||||
public void undoWaive(final BigDecimal amountOutstanding, final BigDecimal amountWaived) {
|
||||
this.amountOutstanding = amountOutstanding;
|
||||
this.amountWaived = amountWaived;
|
||||
}
|
||||
|
||||
private BigDecimal calculateOutstanding() {
|
||||
if (this.amount == null) {
|
||||
return null;
|
||||
}
|
||||
BigDecimal amountPaidLocal = BigDecimal.ZERO;
|
||||
if (this.amountPaid != null) {
|
||||
amountPaidLocal = this.amountPaid;
|
||||
}
|
||||
|
||||
BigDecimal amountWaivedLocal = BigDecimal.ZERO;
|
||||
if (this.amountWaived != null) {
|
||||
amountWaivedLocal = this.amountWaived;
|
||||
}
|
||||
|
||||
BigDecimal amountWrittenOffLocal = BigDecimal.ZERO;
|
||||
if (this.amountWrittenOff != null) {
|
||||
amountWrittenOffLocal = this.amountWrittenOff;
|
||||
}
|
||||
|
||||
final BigDecimal totalAccountedFor = amountPaidLocal.add(amountWaivedLocal).add(amountWrittenOffLocal);
|
||||
|
||||
return this.amount.subtract(totalAccountedFor);
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
}
|
||||
|
||||
public Money getAmountPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountPaid);
|
||||
}
|
||||
|
||||
public BigDecimal getAmountOutstanding() {
|
||||
return this.amountOutstanding;
|
||||
}
|
||||
|
||||
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
||||
return getAmount(currency).minus(getAmountWaived(currency)).minus(getAmountPaid(currency)).getAmount();
|
||||
}
|
||||
|
||||
public boolean isPaid() {
|
||||
return this.paid;
|
||||
}
|
||||
|
||||
public boolean isWaived() {
|
||||
return this.waived;
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return !(isPaid() || isWaived());
|
||||
}
|
||||
|
||||
public boolean isChargeAmountpaid(MonetaryCurrency currency) {
|
||||
Money amounPaidThroughChargePayment = Money.of(currency, this.amountThroughChargePayment);
|
||||
Money paid = Money.of(currency, this.amountPaid);
|
||||
return amounPaidThroughChargePayment.isEqualTo(paid);
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment getRepaymentInstallment() {
|
||||
return this.installment;
|
||||
}
|
||||
|
||||
public Money updatePaidAmountBy(final Money incrementBy, final Money feeAmount) {
|
||||
|
||||
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
||||
final Money amountOutstanding = Money.of(incrementBy.getCurrency(), this.amountOutstanding);
|
||||
Money amountPaidPreviously = amountPaidToDate;
|
||||
Money amountPaidOnThisCharge;
|
||||
if (incrementBy.isGreaterThanOrEqualTo(amountOutstanding)) {
|
||||
amountPaidOnThisCharge = amountOutstanding;
|
||||
amountPaidToDate = amountPaidToDate.plus(amountOutstanding);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
} else {
|
||||
amountPaidOnThisCharge = incrementBy;
|
||||
amountPaidToDate = amountPaidToDate.plus(incrementBy);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(incrementBy.getCurrency());
|
||||
}
|
||||
Money amountFromChargePayment = Money.of(incrementBy.getCurrency(), this.amountThroughChargePayment);
|
||||
if (amountPaidPreviously.isGreaterThanZero()) {
|
||||
amountFromChargePayment = amountFromChargePayment.plus(feeAmount);
|
||||
} else {
|
||||
amountFromChargePayment = feeAmount;
|
||||
}
|
||||
this.amountThroughChargePayment = amountFromChargePayment.getAmount();
|
||||
if (determineIfFullyPaid()) {
|
||||
Money waivedAmount = getAmountWaived(incrementBy.getCurrency());
|
||||
if (waivedAmount.isGreaterThanZero()) {
|
||||
this.waived = true;
|
||||
} else {
|
||||
this.paid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return amountPaidOnThisCharge;
|
||||
}
|
||||
|
||||
public Money getAmountWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountWrittenOff);
|
||||
}
|
||||
|
||||
public void resetPaidAmount(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
}
|
||||
|
||||
public void setAmountWaived(final BigDecimal amountWaived) {
|
||||
this.amountWaived = amountWaived;
|
||||
}
|
||||
|
||||
public void undoWaiveFlag() {
|
||||
this.waived = false;
|
||||
}
|
||||
|
||||
public void setOutstandingAmount(final BigDecimal amountOutstanding) {
|
||||
this.amountOutstanding = amountOutstanding;
|
||||
}
|
||||
|
||||
public void resetToOriginal(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountWaived = BigDecimal.ZERO;
|
||||
this.amountWrittenOff = BigDecimal.ZERO;
|
||||
this.amountThroughChargePayment = BigDecimal.ZERO;
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
|
||||
}
|
||||
|
||||
public Money getAmountThroughChargePayment(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountThroughChargePayment);
|
||||
}
|
||||
|
||||
public Money getUnpaidAmountThroughChargePayment(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountThroughChargePayment).minus(this.amountPaid);
|
||||
}
|
||||
|
||||
private void updateAmountThroughChargePayment(final MonetaryCurrency currency) {
|
||||
Money amountThroughChargePayment = getAmountThroughChargePayment(currency);
|
||||
if (amountThroughChargePayment.isGreaterThanZero() && amountThroughChargePayment.isGreaterThan(this.getAmount(currency))) {
|
||||
this.amountThroughChargePayment = this.getAmount();
|
||||
}
|
||||
}
|
||||
|
||||
public Money updateWaivedAndAmountPaidThroughChargePaymentAmount(final MonetaryCurrency currency) {
|
||||
updateWaivedAmount(currency);
|
||||
updateAmountThroughChargePayment(currency);
|
||||
return getAmountWaived(currency);
|
||||
}
|
||||
|
||||
private void updateWaivedAmount(final MonetaryCurrency currency) {
|
||||
Money waivedAmount = getAmountWaived(currency);
|
||||
if (waivedAmount.isGreaterThanZero()) {
|
||||
if (waivedAmount.isGreaterThan(this.getAmount(currency))) {
|
||||
this.amountWaived = this.getAmount();
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.paid = false;
|
||||
this.waived = true;
|
||||
} else if (waivedAmount.isLessThan(this.getAmount(currency))) {
|
||||
this.paid = false;
|
||||
this.waived = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateInstallment(LoanRepaymentScheduleInstallment installment) {
|
||||
this.installment = installment;
|
||||
}
|
||||
|
||||
public Money undoPaidAmountBy(final Money incrementBy, final Money feeAmount) {
|
||||
|
||||
Money amountPaidToDate = Money.of(incrementBy.getCurrency(), this.amountPaid);
|
||||
|
||||
Money amountToDeductOnThisCharge;
|
||||
if (incrementBy.isGreaterThanOrEqualTo(amountPaidToDate)) {
|
||||
amountToDeductOnThisCharge = amountPaidToDate;
|
||||
amountPaidToDate = Money.zero(incrementBy.getCurrency());
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = this.amount;
|
||||
} else {
|
||||
amountToDeductOnThisCharge = incrementBy;
|
||||
amountPaidToDate = amountPaidToDate.minus(incrementBy);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(incrementBy.getCurrency());
|
||||
}
|
||||
this.amountThroughChargePayment = feeAmount.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
|
||||
return amountToDeductOnThisCharge;
|
||||
}
|
||||
|
||||
public LoanCharge getLoanCharge() {
|
||||
return this.loancharge;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment getInstallment() {
|
||||
return this.installment;
|
||||
}
|
||||
|
||||
public void setInstallment(LoanRepaymentScheduleInstallment installment) {
|
||||
this.installment = installment;
|
||||
}
|
||||
|
||||
public LoanInstallmentChargeData toData() {
|
||||
return LoanInstallmentChargeData.builder().installmentNumber(installment.getInstallmentNumber()).dueDate(installment.getDueDate())
|
||||
.amount(amount).amountOutstanding(amountOutstanding).amountWaived(amountWaived).paid(paid).waived(waived).build();
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_interest_recalculation_additional_details")
|
||||
public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
|
||||
private LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment;
|
||||
|
||||
@Column(name = "effective_date")
|
||||
private LocalDate effectiveDate;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
protected LoanInterestRecalcualtionAdditionalDetails() {
|
||||
|
||||
}
|
||||
|
||||
public LoanInterestRecalcualtionAdditionalDetails(final LocalDate effectiveDate, final BigDecimal amount) {
|
||||
if (effectiveDate != null) {
|
||||
this.effectiveDate = effectiveDate;
|
||||
}
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public LocalDate getEffectiveDate() {
|
||||
return this.effectiveDate;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment getLoanRepaymentScheduleInstallment() {
|
||||
return loanRepaymentScheduleInstallment;
|
||||
}
|
||||
|
||||
public void setLoanRepaymentScheduleInstallment(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
||||
this.loanRepaymentScheduleInstallment = loanRepaymentScheduleInstallment;
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
|
||||
/**
|
||||
* Entity for holding interest recalculation setting, details will be copied from product directly
|
||||
*
|
||||
* @author conflux
|
||||
*/
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_recalculation_details")
|
||||
public class LoanInterestRecalculationDetails extends AbstractPersistableCustom {
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
/**
|
||||
* {@link InterestRecalculationCompoundingMethod}
|
||||
*/
|
||||
@Column(name = "compound_type_enum", nullable = false)
|
||||
private Integer interestRecalculationCompoundingMethod;
|
||||
|
||||
/**
|
||||
* {@link LoanRescheduleStrategyMethod}
|
||||
*/
|
||||
@Column(name = "reschedule_strategy_enum", nullable = false)
|
||||
private Integer rescheduleStrategyMethod;
|
||||
|
||||
@Column(name = "rest_frequency_type_enum", nullable = false)
|
||||
private Integer restFrequencyType;
|
||||
|
||||
@Column(name = "rest_frequency_interval", nullable = false)
|
||||
private Integer restInterval;
|
||||
|
||||
@Column(name = "rest_frequency_nth_day_enum", nullable = true)
|
||||
private Integer restFrequencyNthDay;
|
||||
|
||||
@Column(name = "rest_frequency_weekday_enum", nullable = true)
|
||||
private Integer restFrequencyWeekday;
|
||||
|
||||
@Column(name = "rest_frequency_on_day", nullable = true)
|
||||
private Integer restFrequencyOnDay;
|
||||
|
||||
@Column(name = "compounding_frequency_type_enum", nullable = true)
|
||||
private Integer compoundingFrequencyType;
|
||||
|
||||
@Column(name = "compounding_frequency_interval", nullable = true)
|
||||
private Integer compoundingInterval;
|
||||
|
||||
@Column(name = "compounding_frequency_nth_day_enum", nullable = true)
|
||||
private Integer compoundingFrequencyNthDay;
|
||||
@Column(name = "compounding_frequency_weekday_enum", nullable = true)
|
||||
private Integer compoundingFrequencyWeekday;
|
||||
@Column(name = "compounding_frequency_on_day", nullable = true)
|
||||
private Integer compoundingFrequencyOnDay;
|
||||
|
||||
@Column(name = "is_compounding_to_be_posted_as_transaction")
|
||||
private Boolean isCompoundingToBePostedAsTransaction;
|
||||
@Column(name = "allow_compounding_on_eod")
|
||||
private Boolean allowCompoundingOnEod;
|
||||
|
||||
protected LoanInterestRecalculationDetails() {
|
||||
// Default constructor for jpa repository
|
||||
}
|
||||
|
||||
private LoanInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod, final Integer rescheduleStrategyMethod,
|
||||
final Integer restFrequencyType, final Integer restInterval, final Integer restFrequencyNthDay, Integer restFrequencyWeekday,
|
||||
Integer restFrequencyOnDay, Integer compoundingFrequencyType, Integer compoundingInterval, Integer compoundingFrequencyNthDay,
|
||||
Integer compoundingFrequencyWeekday, Integer compoundingFrequencyOnDay, final boolean isCompoundingToBePostedAsTransaction,
|
||||
final boolean allowCompoundingOnEod) {
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.restFrequencyNthDay = restFrequencyNthDay;
|
||||
this.restFrequencyWeekday = restFrequencyWeekday;
|
||||
this.restFrequencyOnDay = restFrequencyOnDay;
|
||||
this.restFrequencyType = restFrequencyType;
|
||||
this.restInterval = restInterval;
|
||||
this.compoundingFrequencyNthDay = compoundingFrequencyNthDay;
|
||||
this.compoundingFrequencyWeekday = compoundingFrequencyWeekday;
|
||||
this.compoundingFrequencyOnDay = compoundingFrequencyOnDay;
|
||||
this.compoundingFrequencyType = compoundingFrequencyType;
|
||||
this.compoundingInterval = compoundingInterval;
|
||||
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
|
||||
this.allowCompoundingOnEod = allowCompoundingOnEod;
|
||||
}
|
||||
|
||||
public static LoanInterestRecalculationDetails createFrom(
|
||||
final LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails) {
|
||||
return new LoanInterestRecalculationDetails(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod(),
|
||||
loanProductInterestRecalculationDetails.getRescheduleStrategyMethod(),
|
||||
loanProductInterestRecalculationDetails.getRestFrequencyType().getValue(),
|
||||
loanProductInterestRecalculationDetails.getRestInterval(), loanProductInterestRecalculationDetails.getRestFrequencyNthDay(),
|
||||
loanProductInterestRecalculationDetails.getRestFrequencyWeekday(),
|
||||
loanProductInterestRecalculationDetails.getRestFrequencyOnDay(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingFrequencyType().getValue(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingInterval(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingFrequencyNthDay(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay(),
|
||||
loanProductInterestRecalculationDetails.getIsCompoundingToBePostedAsTransaction(),
|
||||
loanProductInterestRecalculationDetails.allowCompoundingOnEod());
|
||||
}
|
||||
|
||||
public void updateLoan(final Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
public InterestRecalculationCompoundingMethod getInterestRecalculationCompoundingMethod() {
|
||||
return InterestRecalculationCompoundingMethod.fromInt(this.interestRecalculationCompoundingMethod);
|
||||
}
|
||||
|
||||
public LoanRescheduleStrategyMethod getRescheduleStrategyMethod() {
|
||||
return LoanRescheduleStrategyMethod.fromInt(this.rescheduleStrategyMethod);
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getRestFrequencyType() {
|
||||
return RecalculationFrequencyType.fromInt(this.restFrequencyType);
|
||||
}
|
||||
|
||||
public Integer getRestInterval() {
|
||||
return this.restInterval;
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getCompoundingFrequencyType() {
|
||||
return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
|
||||
}
|
||||
|
||||
public Integer getCompoundingInterval() {
|
||||
return this.compoundingInterval;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyNthDay() {
|
||||
return this.restFrequencyNthDay;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyWeekday() {
|
||||
return this.restFrequencyWeekday;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyOnDay() {
|
||||
return this.restFrequencyOnDay;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyNthDay() {
|
||||
return this.compoundingFrequencyNthDay;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyWeekday() {
|
||||
return this.compoundingFrequencyWeekday;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyOnDay() {
|
||||
return this.compoundingFrequencyOnDay;
|
||||
}
|
||||
|
||||
public boolean isCompoundingToBePostedAsTransaction() {
|
||||
return null == this.isCompoundingToBePostedAsTransaction ? false : this.isCompoundingToBePostedAsTransaction;
|
||||
}
|
||||
|
||||
public boolean allowCompoundingOnEod() {
|
||||
return this.allowCompoundingOnEod;
|
||||
}
|
||||
}
|
||||
+26
@@ -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.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
public interface LoanLifecycleStateMachine {
|
||||
|
||||
LoanStatus dryTransition(LoanEvent loanEvent, Loan loan);
|
||||
|
||||
void transition(LoanEvent loanEvent, Loan loan);
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.apache.fineract.organisation.staff.domain.Staff;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_officer_assignment_history")
|
||||
public class LoanOfficerAssignmentHistory extends AbstractAuditableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_officer_id", nullable = true)
|
||||
private Staff loanOfficer;
|
||||
|
||||
@Column(name = "start_date")
|
||||
private LocalDate startDate;
|
||||
|
||||
@Column(name = "end_date")
|
||||
private LocalDate endDate;
|
||||
|
||||
public static LoanOfficerAssignmentHistory createNew(final Loan loan, final Staff loanOfficer, final LocalDate startDate) {
|
||||
return new LoanOfficerAssignmentHistory(loan, loanOfficer, startDate, null);
|
||||
}
|
||||
|
||||
protected LoanOfficerAssignmentHistory() {
|
||||
//
|
||||
}
|
||||
|
||||
private LoanOfficerAssignmentHistory(final Loan loan, final Staff loanOfficer, final LocalDate startDate, final LocalDate endDate) {
|
||||
this.loan = loan;
|
||||
this.loanOfficer = loanOfficer;
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public void updateLoanOfficer(final Staff loanOfficer) {
|
||||
this.loanOfficer = loanOfficer;
|
||||
}
|
||||
|
||||
public void updateStartDate(final LocalDate startDate) {
|
||||
this.startDate = startDate;
|
||||
}
|
||||
|
||||
public void updateEndDate(final LocalDate endDate) {
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public boolean matchesStartDateOf(final LocalDate matchingDate) {
|
||||
return getStartDate().isEqual(matchingDate);
|
||||
}
|
||||
|
||||
public LocalDate getStartDate() {
|
||||
return this.startDate;
|
||||
}
|
||||
|
||||
public boolean hasStartDateBefore(final LocalDate matchingDate) {
|
||||
return matchingDate.isBefore(getStartDate());
|
||||
}
|
||||
|
||||
public boolean isCurrentRecord() {
|
||||
return this.endDate == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If endDate is null then return false.
|
||||
*
|
||||
* @param compareDate
|
||||
* @return
|
||||
*/
|
||||
public boolean isEndDateAfter(final LocalDate compareDate) {
|
||||
return this.endDate.isAfter(compareDate);
|
||||
}
|
||||
|
||||
public LocalDate getEndDate() {
|
||||
return this.endDate;
|
||||
}
|
||||
|
||||
public boolean isSameLoanOfficer(final Staff staff) {
|
||||
return this.loanOfficer.identifiedBy(staff);
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Table(name = "m_loan_overdue_installment_charge")
|
||||
public class LoanOverdueInstallmentCharge extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false)
|
||||
private LoanCharge loancharge;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_schedule_id", referencedColumnName = "id", nullable = false)
|
||||
private LoanRepaymentScheduleInstallment installment;
|
||||
|
||||
@Column(name = "frequency_number")
|
||||
private Integer frequencyNumber;
|
||||
|
||||
public LoanOverdueInstallmentCharge() {
|
||||
|
||||
}
|
||||
|
||||
public LoanOverdueInstallmentCharge(final LoanCharge loancharge, final LoanRepaymentScheduleInstallment installment,
|
||||
final Integer frequencyNumber) {
|
||||
this.loancharge = loancharge;
|
||||
this.installment = installment;
|
||||
this.frequencyNumber = frequencyNumber;
|
||||
}
|
||||
|
||||
public void updateLoanRepaymentScheduleInstallment(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
||||
this.installment = loanRepaymentScheduleInstallment;
|
||||
}
|
||||
}
|
||||
+907
@@ -0,0 +1,907 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_repayment_schedule")
|
||||
public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDateTimeCustom
|
||||
implements Comparable<LoanRepaymentScheduleInstallment> {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id", referencedColumnName = "id")
|
||||
private Loan loan;
|
||||
|
||||
@Column(name = "installment", nullable = false)
|
||||
private Integer installmentNumber;
|
||||
|
||||
@Column(name = "fromdate", nullable = true)
|
||||
private LocalDate fromDate;
|
||||
|
||||
@Column(name = "duedate", nullable = false)
|
||||
private LocalDate dueDate;
|
||||
|
||||
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal principal;
|
||||
|
||||
@Column(name = "principal_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal principalCompleted;
|
||||
|
||||
@Column(name = "principal_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal principalWrittenOff;
|
||||
|
||||
@Column(name = "interest_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestCharged;
|
||||
|
||||
@Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestPaid;
|
||||
|
||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestWaived;
|
||||
|
||||
@Column(name = "interest_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestWrittenOff;
|
||||
|
||||
@Column(name = "accrual_interest_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestAccrued;
|
||||
|
||||
@Column(name = "reschedule_interest_portion", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal rescheduleInterestPortion;
|
||||
|
||||
@Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesCharged;
|
||||
|
||||
@Column(name = "fee_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesPaid;
|
||||
|
||||
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesWrittenOff;
|
||||
|
||||
@Column(name = "fee_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesWaived;
|
||||
|
||||
@Column(name = "accrual_fee_charges_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeAccrued;
|
||||
|
||||
@Column(name = "penalty_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyCharges;
|
||||
|
||||
@Column(name = "penalty_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesPaid;
|
||||
|
||||
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesWrittenOff;
|
||||
|
||||
@Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesWaived;
|
||||
|
||||
@Column(name = "accrual_penalty_charges_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyAccrued;
|
||||
|
||||
@Column(name = "total_paid_in_advance_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal totalPaidInAdvance;
|
||||
|
||||
@Column(name = "total_paid_late_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal totalPaidLate;
|
||||
|
||||
@Column(name = "completed_derived", nullable = false)
|
||||
private boolean obligationsMet;
|
||||
|
||||
@Column(name = "obligations_met_on_date")
|
||||
private LocalDate obligationsMetOnDate;
|
||||
|
||||
@Column(name = "recalculated_interest_component", nullable = false)
|
||||
private boolean recalculatedInterestComponent;
|
||||
|
||||
@Column(name = "is_additional", nullable = false)
|
||||
private boolean additional;
|
||||
|
||||
@Column(name = "credits_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal credits;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanRepaymentScheduleInstallment")
|
||||
private Set<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new HashSet<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanRepaymentScheduleInstallment")
|
||||
private Set<PostDatedChecks> postDatedChecks;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "installment")
|
||||
private Set<LoanInstallmentCharge> installmentCharges = new HashSet<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "installment")
|
||||
private Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = new HashSet<>();
|
||||
|
||||
public LoanRepaymentScheduleInstallment() {
|
||||
this.installmentNumber = null;
|
||||
this.fromDate = null;
|
||||
this.dueDate = null;
|
||||
this.obligationsMet = false;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate,
|
||||
final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
|
||||
final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent,
|
||||
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails, final BigDecimal rescheduleInterestPortion) {
|
||||
this.loan = loan;
|
||||
this.installmentNumber = installmentNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
this.principal = defaultToNullIfZero(principal);
|
||||
this.interestCharged = defaultToNullIfZero(interest);
|
||||
this.feeChargesCharged = defaultToNullIfZero(feeCharges);
|
||||
this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
|
||||
this.obligationsMet = false;
|
||||
this.recalculatedInterestComponent = recalculatedInterestComponent;
|
||||
if (compoundingDetails != null) {
|
||||
compoundingDetails.forEach(cd -> cd.setLoanRepaymentScheduleInstallment(this));
|
||||
}
|
||||
this.loanCompoundingDetails = compoundingDetails;
|
||||
this.rescheduleInterestPortion = rescheduleInterestPortion;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate,
|
||||
final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
|
||||
final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent,
|
||||
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails) {
|
||||
this.loan = loan;
|
||||
this.installmentNumber = installmentNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
this.principal = defaultToNullIfZero(principal);
|
||||
this.interestCharged = defaultToNullIfZero(interest);
|
||||
this.feeChargesCharged = defaultToNullIfZero(feeCharges);
|
||||
this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
|
||||
this.obligationsMet = false;
|
||||
this.recalculatedInterestComponent = recalculatedInterestComponent;
|
||||
if (compoundingDetails != null) {
|
||||
compoundingDetails.forEach(cd -> cd.setLoanRepaymentScheduleInstallment(this));
|
||||
}
|
||||
this.loanCompoundingDetails = compoundingDetails;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment(final Loan loan) {
|
||||
this.loan = loan;
|
||||
this.installmentNumber = null;
|
||||
this.fromDate = null;
|
||||
this.dueDate = null;
|
||||
this.obligationsMet = false;
|
||||
}
|
||||
|
||||
private BigDecimal defaultToNullIfZero(final BigDecimal value) {
|
||||
BigDecimal result = value;
|
||||
if (BigDecimal.ZERO.compareTo(value) == 0) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Loan getLoan() {
|
||||
return this.loan;
|
||||
}
|
||||
|
||||
public Integer getInstallmentNumber() {
|
||||
return this.installmentNumber;
|
||||
}
|
||||
|
||||
public LocalDate getFromDate() {
|
||||
return this.fromDate;
|
||||
}
|
||||
|
||||
public void setPostDatedChecksToNull() {
|
||||
this.postDatedChecks = null;
|
||||
}
|
||||
|
||||
public Set<PostDatedChecks> getPostDatedCheck() {
|
||||
return this.postDatedChecks;
|
||||
}
|
||||
|
||||
public LocalDate getDueDate() {
|
||||
return this.dueDate;
|
||||
}
|
||||
|
||||
public Money getCredits(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.credits);
|
||||
}
|
||||
|
||||
public Money getPrincipal(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principal);
|
||||
}
|
||||
|
||||
public Money getPrincipalCompleted(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalCompleted);
|
||||
}
|
||||
|
||||
public void updateLoanRepaymentSchedule(final BigDecimal amountWaived) {
|
||||
this.feeChargesWaived = this.feeChargesWaived.subtract(amountWaived);
|
||||
}
|
||||
|
||||
public Money getPrincipalWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalWrittenOff);
|
||||
}
|
||||
|
||||
public Money getPrincipalOutstanding(final MonetaryCurrency currency) {
|
||||
final Money principalAccountedFor = getPrincipalCompleted(currency).plus(getPrincipalWrittenOff(currency));
|
||||
return getPrincipal(currency).minus(principalAccountedFor);
|
||||
}
|
||||
|
||||
public Money getInterestCharged(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestCharged);
|
||||
}
|
||||
|
||||
public Money getInterestPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestPaid);
|
||||
}
|
||||
|
||||
public Money getInterestWaived(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestWaived);
|
||||
}
|
||||
|
||||
public Money getInterestWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestWrittenOff);
|
||||
}
|
||||
|
||||
public Money getInterestOutstanding(final MonetaryCurrency currency) {
|
||||
final Money interestAccountedFor = getInterestPaid(currency).plus(getInterestWaived(currency))
|
||||
.plus(getInterestWrittenOff(currency));
|
||||
return getInterestCharged(currency).minus(interestAccountedFor);
|
||||
}
|
||||
|
||||
public Money getInterestAccrued(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestAccrued);
|
||||
}
|
||||
|
||||
public Money getFeeChargesCharged(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesCharged);
|
||||
}
|
||||
|
||||
public Money getFeeChargesPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesPaid);
|
||||
}
|
||||
|
||||
public Money getFeeChargesWaived(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesWaived);
|
||||
}
|
||||
|
||||
public Money getFeeChargesWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesWrittenOff);
|
||||
}
|
||||
|
||||
public Money getFeeChargesOutstanding(final MonetaryCurrency currency) {
|
||||
final Money feeChargesAccountedFor = getFeeChargesPaid(currency).plus(getFeeChargesWaived(currency))
|
||||
.plus(getFeeChargesWrittenOff(currency));
|
||||
return getFeeChargesCharged(currency).minus(feeChargesAccountedFor);
|
||||
}
|
||||
|
||||
public Money getFeeAccrued(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeAccrued);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesCharged(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyCharges);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesPaid);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesWaived(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesWaived);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesWrittenOff);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesOutstanding(final MonetaryCurrency currency) {
|
||||
final Money feeChargesAccountedFor = getPenaltyChargesPaid(currency).plus(getPenaltyChargesWaived(currency))
|
||||
.plus(getPenaltyChargesWrittenOff(currency));
|
||||
return getPenaltyChargesCharged(currency).minus(feeChargesAccountedFor);
|
||||
}
|
||||
|
||||
public Money getPenaltyAccrued(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyAccrued);
|
||||
}
|
||||
|
||||
public boolean isInterestDue(final MonetaryCurrency currency) {
|
||||
return getInterestOutstanding(currency).isGreaterThanZero();
|
||||
}
|
||||
|
||||
public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) {
|
||||
return getPrincipal(currency).plus(getInterestCharged(currency));
|
||||
}
|
||||
|
||||
public Money getTotalOutstanding(final MonetaryCurrency currency) {
|
||||
return getPrincipalOutstanding(currency).plus(getInterestOutstanding(currency)).plus(getFeeChargesOutstanding(currency))
|
||||
.plus(getPenaltyChargesOutstanding(currency));
|
||||
}
|
||||
|
||||
public void updateLoan(final Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
public boolean isPartlyPaid() {
|
||||
return !this.obligationsMet && (this.interestPaid != null || this.feeChargesPaid != null || this.principalCompleted != null);
|
||||
}
|
||||
|
||||
public boolean isObligationsMet() {
|
||||
return this.obligationsMet;
|
||||
}
|
||||
|
||||
public boolean isNotFullyPaidOff() {
|
||||
return !this.obligationsMet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(LoanRepaymentScheduleInstallment o) {
|
||||
return this.installmentNumber.compareTo(o.installmentNumber);
|
||||
}
|
||||
|
||||
public boolean isPrincipalNotCompleted(final MonetaryCurrency currency) {
|
||||
return !isPrincipalCompleted(currency);
|
||||
}
|
||||
|
||||
public boolean isPrincipalCompleted(final MonetaryCurrency currency) {
|
||||
return getPrincipalOutstanding(currency).isZero();
|
||||
}
|
||||
|
||||
public void resetDerivedComponents() {
|
||||
this.principalCompleted = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
this.totalPaidInAdvance = null;
|
||||
this.totalPaidLate = null;
|
||||
|
||||
this.obligationsMet = false;
|
||||
this.obligationsMetOnDate = null;
|
||||
if (this.credits != null) {
|
||||
this.principal = this.principal.subtract(this.credits);
|
||||
this.credits = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetAccrualComponents() {
|
||||
this.interestAccrued = null;
|
||||
this.feeAccrued = null;
|
||||
this.penaltyAccrued = null;
|
||||
}
|
||||
|
||||
public Money payPenaltyChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money penaltyPortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money penaltyChargesDue = getPenaltyChargesOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesDue)) {
|
||||
this.penaltyChargesPaid = getPenaltyChargesPaid(currency).plus(penaltyChargesDue).getAmount();
|
||||
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(penaltyChargesDue);
|
||||
} else {
|
||||
this.penaltyChargesPaid = getPenaltyChargesPaid(currency).plus(transactionAmountRemaining).getAmount();
|
||||
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.penaltyChargesPaid = defaultToNullIfZero(this.penaltyChargesPaid);
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, penaltyPortionOfTransaction);
|
||||
|
||||
return penaltyPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money payFeeChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money feePortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money feeChargesDue = getFeeChargesOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesDue)) {
|
||||
this.feeChargesPaid = getFeeChargesPaid(currency).plus(feeChargesDue).getAmount();
|
||||
feePortionOfTransaction = feePortionOfTransaction.plus(feeChargesDue);
|
||||
} else {
|
||||
this.feeChargesPaid = getFeeChargesPaid(currency).plus(transactionAmountRemaining).getAmount();
|
||||
feePortionOfTransaction = feePortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.feeChargesPaid = defaultToNullIfZero(this.feeChargesPaid);
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, feePortionOfTransaction);
|
||||
|
||||
return feePortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money payInterestComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money interestPortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money interestDue = getInterestOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
|
||||
this.interestPaid = getInterestPaid(currency).plus(interestDue).getAmount();
|
||||
interestPortionOfTransaction = interestPortionOfTransaction.plus(interestDue);
|
||||
} else {
|
||||
this.interestPaid = getInterestPaid(currency).plus(transactionAmountRemaining).getAmount();
|
||||
interestPortionOfTransaction = interestPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.interestPaid = defaultToNullIfZero(this.interestPaid);
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, interestPortionOfTransaction);
|
||||
|
||||
return interestPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money payPrincipalComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money principalPortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money principalDue = getPrincipalOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalDue)) {
|
||||
this.principalCompleted = getPrincipalCompleted(currency).plus(principalDue).getAmount();
|
||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(principalDue);
|
||||
} else {
|
||||
this.principalCompleted = getPrincipalCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.principalCompleted = defaultToNullIfZero(this.principalCompleted);
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, principalPortionOfTransaction);
|
||||
|
||||
return principalPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money waiveInterestComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money waivedInterestPortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money interestDue = getInterestOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
|
||||
this.interestWaived = getInterestWaived(currency).plus(interestDue).getAmount();
|
||||
waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(interestDue);
|
||||
} else {
|
||||
this.interestWaived = getInterestWaived(currency).plus(transactionAmountRemaining).getAmount();
|
||||
waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.interestWaived = defaultToNullIfZero(this.interestWaived);
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return waivedInterestPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money waivePenaltyChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money waivedPenaltyChargesPortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money penanltiesDue = getPenaltyChargesOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penanltiesDue)) {
|
||||
this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(penanltiesDue).getAmount();
|
||||
waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(penanltiesDue);
|
||||
} else {
|
||||
this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
|
||||
waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.penaltyChargesWaived = defaultToNullIfZero(this.penaltyChargesWaived);
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return waivedPenaltyChargesPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money waiveFeeChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money waivedFeeChargesPortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money feesDue = getFeeChargesOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) {
|
||||
this.feeChargesWaived = getFeeChargesWaived(currency).plus(feesDue).getAmount();
|
||||
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(feesDue);
|
||||
} else {
|
||||
this.feeChargesWaived = getFeeChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
|
||||
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(transactionAmountRemaining);
|
||||
}
|
||||
|
||||
this.feeChargesWaived = defaultToNullIfZero(this.feeChargesWaived);
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return waivedFeeChargesPortionOfTransaction;
|
||||
}
|
||||
|
||||
public Money writeOffOutstandingPrincipal(final LocalDate transactionDate, final MonetaryCurrency currency) {
|
||||
|
||||
final Money principalDue = getPrincipalOutstanding(currency);
|
||||
this.principalWrittenOff = defaultToNullIfZero(principalDue.getAmount());
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return principalDue;
|
||||
}
|
||||
|
||||
public Money writeOffOutstandingInterest(final LocalDate transactionDate, final MonetaryCurrency currency) {
|
||||
|
||||
final Money interestDue = getInterestOutstanding(currency);
|
||||
this.interestWrittenOff = defaultToNullIfZero(interestDue.getAmount());
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return interestDue;
|
||||
}
|
||||
|
||||
public Money writeOffOutstandingFeeCharges(final LocalDate transactionDate, final MonetaryCurrency currency) {
|
||||
final Money feeChargesOutstanding = getFeeChargesOutstanding(currency);
|
||||
this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesOutstanding.getAmount());
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return feeChargesOutstanding;
|
||||
}
|
||||
|
||||
public Money writeOffOutstandingPenaltyCharges(final LocalDate transactionDate, final MonetaryCurrency currency) {
|
||||
final Money penaltyChargesOutstanding = getPenaltyChargesOutstanding(currency);
|
||||
this.penaltyChargesWrittenOff = defaultToNullIfZero(penaltyChargesOutstanding.getAmount());
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return penaltyChargesOutstanding;
|
||||
}
|
||||
|
||||
public boolean isOverdueOn(final LocalDate date) {
|
||||
return getDueDate().isBefore(date);
|
||||
}
|
||||
|
||||
public void updateChargePortion(final Money feeChargesDue, final Money feeChargesWaived, final Money feeChargesWrittenOff,
|
||||
final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) {
|
||||
this.feeChargesCharged = defaultToNullIfZero(feeChargesDue.getAmount());
|
||||
this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.getAmount());
|
||||
this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.getAmount());
|
||||
this.penaltyCharges = defaultToNullIfZero(penaltyChargesDue.getAmount());
|
||||
this.penaltyChargesWaived = defaultToNullIfZero(penaltyChargesWaived.getAmount());
|
||||
this.penaltyChargesWrittenOff = defaultToNullIfZero(penaltyChargesWrittenOff.getAmount());
|
||||
}
|
||||
|
||||
public void updateAccrualPortion(final Money interest, final Money feeCharges, final Money penalityCharges) {
|
||||
this.interestAccrued = defaultToNullIfZero(interest.getAmount());
|
||||
this.feeAccrued = defaultToNullIfZero(feeCharges.getAmount());
|
||||
this.penaltyAccrued = defaultToNullIfZero(penalityCharges.getAmount());
|
||||
}
|
||||
|
||||
public void updateDerivedFields(final MonetaryCurrency currency, final LocalDate actualDisbursementDate) {
|
||||
if (!this.obligationsMet && getTotalOutstanding(currency).isZero()) {
|
||||
this.obligationsMet = true;
|
||||
this.obligationsMetOnDate = actualDisbursementDate;
|
||||
}
|
||||
}
|
||||
|
||||
private void trackAdvanceAndLateTotalsForRepaymentPeriod(final LocalDate transactionDate, final MonetaryCurrency currency,
|
||||
final Money amountPaidInRepaymentPeriod) {
|
||||
if (isInAdvance(transactionDate)) {
|
||||
this.totalPaidInAdvance = asMoney(this.totalPaidInAdvance, currency).plus(amountPaidInRepaymentPeriod).getAmount();
|
||||
} else if (isLatePayment(transactionDate)) {
|
||||
this.totalPaidLate = asMoney(this.totalPaidLate, currency).plus(amountPaidInRepaymentPeriod).getAmount();
|
||||
}
|
||||
}
|
||||
|
||||
private Money asMoney(final BigDecimal decimal, final MonetaryCurrency currency) {
|
||||
return Money.of(currency, decimal);
|
||||
}
|
||||
|
||||
private boolean isInAdvance(final LocalDate transactionDate) {
|
||||
return transactionDate.isBefore(getDueDate());
|
||||
}
|
||||
|
||||
private boolean isLatePayment(final LocalDate transactionDate) {
|
||||
return transactionDate.isAfter(getDueDate());
|
||||
}
|
||||
|
||||
private void checkIfRepaymentPeriodObligationsAreMet(final LocalDate transactionDate, final MonetaryCurrency currency) {
|
||||
this.obligationsMet = getTotalOutstanding(currency).isZero();
|
||||
if (this.obligationsMet) {
|
||||
this.obligationsMetOnDate = transactionDate;
|
||||
} else {
|
||||
this.obligationsMetOnDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDueDate(final LocalDate newDueDate) {
|
||||
if (newDueDate != null) {
|
||||
this.dueDate = newDueDate;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFromDate(final LocalDate newFromDate) {
|
||||
if (newFromDate != null) {
|
||||
this.fromDate = newFromDate;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalPaidInAdvance(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.totalPaidInAdvance);
|
||||
}
|
||||
|
||||
public Money getTotalPaidLate(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.totalPaidLate);
|
||||
}
|
||||
|
||||
public boolean isRecalculatedInterestComponent() {
|
||||
return this.recalculatedInterestComponent;
|
||||
}
|
||||
|
||||
public void setRecalculatedInterestComponent(boolean recalculatedInterestComponent) {
|
||||
this.recalculatedInterestComponent = recalculatedInterestComponent;
|
||||
}
|
||||
|
||||
public void updateInstallmentNumber(final Integer installmentNumber) {
|
||||
if (installmentNumber != null) {
|
||||
this.installmentNumber = installmentNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateInterestCharged(final BigDecimal interestCharged) {
|
||||
this.interestCharged = interestCharged;
|
||||
}
|
||||
|
||||
public void updateObligationMet(final Boolean obligationMet) {
|
||||
this.obligationsMet = obligationMet;
|
||||
}
|
||||
|
||||
public void updateObligationMetOnDate(final LocalDate obligationsMetOnDate) {
|
||||
this.obligationsMetOnDate = obligationsMetOnDate;
|
||||
}
|
||||
|
||||
public void updateInterestWrittenOff(final BigDecimal interestWrittenOff) {
|
||||
this.interestWrittenOff = interestWrittenOff;
|
||||
}
|
||||
|
||||
public void updatePrincipal(final BigDecimal principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public void addToPrincipal(final LocalDate transactionDate, final Money transactionAmount) {
|
||||
if (this.principal == null) {
|
||||
this.principal = transactionAmount.getAmount();
|
||||
} else {
|
||||
this.principal = this.principal.add(transactionAmount.getAmount());
|
||||
}
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, transactionAmount.getCurrency());
|
||||
}
|
||||
|
||||
public void addToCredits(final BigDecimal amount) {
|
||||
if (this.credits == null) {
|
||||
this.credits = amount;
|
||||
} else {
|
||||
this.credits = this.credits.add(amount);
|
||||
}
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPaidInAdvance() {
|
||||
return this.totalPaidInAdvance;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPaidLate() {
|
||||
return this.totalPaidLate;
|
||||
}
|
||||
|
||||
public LocalDate getObligationsMetOnDate() {
|
||||
return this.obligationsMetOnDate;
|
||||
}
|
||||
|
||||
/********** UNPAY COMPONENTS ****/
|
||||
|
||||
public Money unpayPenaltyChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money penaltyPortionOfTransactionDeducted;
|
||||
|
||||
final Money penaltyChargesCompleted = getPenaltyChargesPaid(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesCompleted)) {
|
||||
this.penaltyChargesPaid = Money.zero(currency).getAmount();
|
||||
penaltyPortionOfTransactionDeducted = penaltyChargesCompleted;
|
||||
} else {
|
||||
this.penaltyChargesPaid = penaltyChargesCompleted.minus(transactionAmountRemaining).getAmount();
|
||||
penaltyPortionOfTransactionDeducted = transactionAmountRemaining;
|
||||
}
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
return penaltyPortionOfTransactionDeducted;
|
||||
}
|
||||
|
||||
public Money unpayFeeChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money feePortionOfTransactionDeducted;
|
||||
|
||||
final Money feeChargesCompleted = getFeeChargesPaid(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesCompleted)) {
|
||||
this.feeChargesPaid = Money.zero(currency).getAmount();
|
||||
feePortionOfTransactionDeducted = feeChargesCompleted;
|
||||
} else {
|
||||
this.feeChargesPaid = feeChargesCompleted.minus(transactionAmountRemaining).getAmount();
|
||||
feePortionOfTransactionDeducted = transactionAmountRemaining;
|
||||
}
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
reduceAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, feePortionOfTransactionDeducted);
|
||||
|
||||
return feePortionOfTransactionDeducted;
|
||||
}
|
||||
|
||||
public Money unpayInterestComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money interestPortionOfTransactionDeducted;
|
||||
|
||||
final Money interestCompleted = getInterestPaid(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestCompleted)) {
|
||||
this.interestPaid = Money.zero(currency).getAmount();
|
||||
interestPortionOfTransactionDeducted = interestCompleted;
|
||||
} else {
|
||||
this.interestPaid = interestCompleted.minus(transactionAmountRemaining).getAmount();
|
||||
interestPortionOfTransactionDeducted = transactionAmountRemaining;
|
||||
}
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
reduceAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, interestPortionOfTransactionDeducted);
|
||||
|
||||
return interestPortionOfTransactionDeducted;
|
||||
}
|
||||
|
||||
public Money unpayPrincipalComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
|
||||
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money principalPortionOfTransactionDeducted;
|
||||
|
||||
final Money principalCompleted = getPrincipalCompleted(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalCompleted)) {
|
||||
this.principalCompleted = Money.zero(currency).getAmount();
|
||||
principalPortionOfTransactionDeducted = principalCompleted;
|
||||
} else {
|
||||
this.principalCompleted = principalCompleted.minus(transactionAmountRemaining).getAmount();
|
||||
principalPortionOfTransactionDeducted = transactionAmountRemaining;
|
||||
}
|
||||
|
||||
checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
|
||||
|
||||
reduceAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, principalPortionOfTransactionDeducted);
|
||||
|
||||
return principalPortionOfTransactionDeducted;
|
||||
}
|
||||
|
||||
private void reduceAdvanceAndLateTotalsForRepaymentPeriod(final LocalDate transactionDate, final MonetaryCurrency currency,
|
||||
final Money amountDeductedInRepaymentPeriod) {
|
||||
|
||||
if (isInAdvance(transactionDate)) {
|
||||
Money mTotalPaidInAdvance = Money.of(currency, this.totalPaidInAdvance);
|
||||
|
||||
if (mTotalPaidInAdvance.isLessThan(amountDeductedInRepaymentPeriod)
|
||||
|| mTotalPaidInAdvance.isEqualTo(amountDeductedInRepaymentPeriod)) {
|
||||
this.totalPaidInAdvance = Money.zero(currency).getAmount();
|
||||
} else {
|
||||
this.totalPaidInAdvance = mTotalPaidInAdvance.minus(amountDeductedInRepaymentPeriod).getAmount();
|
||||
}
|
||||
} else if (isLatePayment(transactionDate)) {
|
||||
Money mTotalPaidLate = Money.of(currency, this.totalPaidLate);
|
||||
|
||||
if (mTotalPaidLate.isLessThan(amountDeductedInRepaymentPeriod) || mTotalPaidLate.isEqualTo(amountDeductedInRepaymentPeriod)) {
|
||||
this.totalPaidLate = Money.zero(currency).getAmount();
|
||||
} else {
|
||||
this.totalPaidLate = mTotalPaidLate.minus(amountDeductedInRepaymentPeriod).getAmount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDueAndCredits(final LocalDate transactionDate, final Money transactionAmount) {
|
||||
updateDueDate(transactionDate);
|
||||
addToCredits(transactionAmount.getAmount());
|
||||
addToPrincipal(transactionDate, transactionAmount);
|
||||
}
|
||||
|
||||
public Money getDue(MonetaryCurrency currency) {
|
||||
return getPrincipal(currency).plus(getInterestCharged(currency)).plus(getFeeChargesCharged(currency))
|
||||
.plus(getPenaltyChargesCharged(currency));
|
||||
}
|
||||
|
||||
public Set<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
||||
return this.loanCompoundingDetails;
|
||||
}
|
||||
|
||||
public Money getAccruedInterestOutstanding(final MonetaryCurrency currency) {
|
||||
final Money interestAccountedFor = getInterestPaid(currency).plus(getInterestWaived(currency))
|
||||
.plus(getInterestWrittenOff(currency));
|
||||
return getInterestAccrued(currency).minus(interestAccountedFor);
|
||||
}
|
||||
|
||||
public Money getTotalPaid(final MonetaryCurrency currency) {
|
||||
return getPenaltyChargesPaid(currency).plus(getFeeChargesPaid(currency)).plus(getInterestPaid(currency))
|
||||
.plus(getPrincipalCompleted(currency));
|
||||
}
|
||||
|
||||
public BigDecimal getRescheduleInterestPortion() {
|
||||
return rescheduleInterestPortion;
|
||||
}
|
||||
|
||||
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
|
||||
this.rescheduleInterestPortion = rescheduleInterestPortion;
|
||||
}
|
||||
|
||||
public void setFeeChargesWaived(final BigDecimal newFeeChargesCharged) {
|
||||
this.feeChargesWaived = newFeeChargesCharged;
|
||||
}
|
||||
|
||||
public void setPenaltyChargesWaived(final BigDecimal newPenaltyChargesCharged) {
|
||||
this.penaltyChargesWaived = newPenaltyChargesCharged;
|
||||
}
|
||||
|
||||
public Set<LoanInstallmentCharge> getInstallmentCharges() {
|
||||
return installmentCharges;
|
||||
}
|
||||
|
||||
public boolean isAdditional() {
|
||||
return additional;
|
||||
}
|
||||
|
||||
public void markAsAdditional() {
|
||||
this.additional = true;
|
||||
}
|
||||
|
||||
public boolean isFirstPeriod() {
|
||||
return (this.installmentNumber == 1);
|
||||
}
|
||||
|
||||
public Set<LoanTransactionToRepaymentScheduleMapping> getLoanTransactionToRepaymentScheduleMappings() {
|
||||
return this.loanTransactionToRepaymentScheduleMappings;
|
||||
}
|
||||
|
||||
}
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
|
||||
/**
|
||||
* A wrapper around loan schedule related data exposing needed behaviour by loan.
|
||||
*/
|
||||
public class LoanRepaymentScheduleProcessingWrapper {
|
||||
|
||||
public void reprocess(final MonetaryCurrency currency, final LocalDate disbursementDate,
|
||||
final List<LoanRepaymentScheduleInstallment> repaymentPeriods, final Set<LoanCharge> loanCharges) {
|
||||
|
||||
Money totalInterest = Money.zero(currency);
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentPeriods) {
|
||||
totalInterest = totalInterest.plus(installment.getInterestCharged(currency));
|
||||
totalPrincipal = totalPrincipal.plus(installment.getPrincipal(currency));
|
||||
}
|
||||
LocalDate startDate = disbursementDate;
|
||||
for (final LoanRepaymentScheduleInstallment period : repaymentPeriods) {
|
||||
|
||||
final Money feeChargesDueForRepaymentPeriod = cumulativeFeeChargesDueWithin(startDate, period.getDueDate(), loanCharges,
|
||||
currency, period, totalPrincipal, totalInterest, !period.isRecalculatedInterestComponent());
|
||||
final Money feeChargesWaivedForRepaymentPeriod = cumulativeFeeChargesWaivedWithin(startDate, period.getDueDate(), loanCharges,
|
||||
currency, !period.isRecalculatedInterestComponent(), period.isFirstPeriod());
|
||||
final Money feeChargesWrittenOffForRepaymentPeriod = cumulativeFeeChargesWrittenOffWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, !period.isRecalculatedInterestComponent(), period.isFirstPeriod());
|
||||
|
||||
final Money penaltyChargesDueForRepaymentPeriod = cumulativePenaltyChargesDueWithin(startDate, period.getDueDate(), loanCharges,
|
||||
currency, period, totalPrincipal, totalInterest, !period.isRecalculatedInterestComponent());
|
||||
final Money penaltyChargesWaivedForRepaymentPeriod = cumulativePenaltyChargesWaivedWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, !period.isRecalculatedInterestComponent(), period.isFirstPeriod());
|
||||
final Money penaltyChargesWrittenOffForRepaymentPeriod = cumulativePenaltyChargesWrittenOffWithin(startDate,
|
||||
period.getDueDate(), loanCharges, currency, !period.isRecalculatedInterestComponent(), period.isFirstPeriod());
|
||||
|
||||
period.updateChargePortion(feeChargesDueForRepaymentPeriod, feeChargesWaivedForRepaymentPeriod,
|
||||
feeChargesWrittenOffForRepaymentPeriod, penaltyChargesDueForRepaymentPeriod, penaltyChargesWaivedForRepaymentPeriod,
|
||||
penaltyChargesWrittenOffForRepaymentPeriod);
|
||||
|
||||
startDate = period.getDueDate();
|
||||
}
|
||||
}
|
||||
|
||||
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
|
||||
final MonetaryCurrency monetaryCurrency, LoanRepaymentScheduleInstallment period, final Money totalPrincipal,
|
||||
final Money totalInterest, boolean isInstallmentChargeApplicable) {
|
||||
|
||||
Money cumulative = Money.zero(monetaryCurrency);
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) {
|
||||
boolean isDue = period.isFirstPeriod()
|
||||
? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, periodEnd)
|
||||
: loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
|
||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||
if (loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
|
||||
amount = amount.add(period.getPrincipal(monetaryCurrency).getAmount())
|
||||
.add(period.getInterestCharged(monetaryCurrency).getAmount());
|
||||
} else if (loanCharge.getChargeCalculation().isPercentageOfInterest()) {
|
||||
amount = amount.add(period.getInterestCharged(monetaryCurrency).getAmount());
|
||||
} else {
|
||||
amount = amount.add(period.getPrincipal(monetaryCurrency).getAmount());
|
||||
}
|
||||
BigDecimal loanChargeAmt = amount.multiply(loanCharge.getPercentage()).divide(BigDecimal.valueOf(100));
|
||||
cumulative = cumulative.plus(loanChargeAmt);
|
||||
} else {
|
||||
cumulative = cumulative.plus(loanCharge.amountOrPercentage());
|
||||
}
|
||||
} else if (loanCharge.isOverdueInstallmentCharge() && isDue && loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = cumulative.plus(loanCharge.chargeAmount());
|
||||
} else if (isDue && loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
|
||||
amount = amount.add(totalPrincipal.getAmount()).add(totalInterest.getAmount());
|
||||
} else if (loanCharge.getChargeCalculation().isPercentageOfInterest()) {
|
||||
amount = amount.add(totalInterest.getAmount());
|
||||
} else {
|
||||
// If charge type is specified due date and loan is
|
||||
// multi disburment loan.
|
||||
// Then we need to get as of this loan charge due date
|
||||
// how much amount disbursed.
|
||||
if (loanCharge.getLoan() != null && loanCharge.isSpecifiedDueDate()
|
||||
&& loanCharge.getLoan().isMultiDisburmentLoan()) {
|
||||
for (final LoanDisbursementDetails loanDisbursementDetails : loanCharge.getLoan().getDisbursementDetails()) {
|
||||
if (!loanDisbursementDetails.expectedDisbursementDate().isAfter(loanCharge.getDueDate())) {
|
||||
amount = amount.add(loanDisbursementDetails.principal());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
amount = amount.add(totalPrincipal.getAmount());
|
||||
}
|
||||
}
|
||||
BigDecimal loanChargeAmt = amount.multiply(loanCharge.getPercentage()).divide(BigDecimal.valueOf(100));
|
||||
cumulative = cumulative.plus(loanChargeAmt);
|
||||
} else if (isDue) {
|
||||
cumulative = cumulative.plus(loanCharge.amount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cumulative;
|
||||
}
|
||||
|
||||
private Money cumulativeFeeChargesWaivedWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency currency, boolean isInstallmentChargeApplicable,
|
||||
boolean isFirstPeriod) {
|
||||
|
||||
Money cumulative = Money.zero(currency);
|
||||
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) {
|
||||
boolean isDue = isFirstPeriod ? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, periodEnd)
|
||||
: loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
|
||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
||||
if (loanChargePerInstallment != null) {
|
||||
cumulative = cumulative.plus(loanChargePerInstallment.getAmountWaived(currency));
|
||||
}
|
||||
} else if (isDue) {
|
||||
cumulative = cumulative.plus(loanCharge.getAmountWaived(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cumulative;
|
||||
}
|
||||
|
||||
private Money cumulativeFeeChargesWrittenOffWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency currency, boolean isInstallmentChargeApplicable,
|
||||
boolean isFirstPeriod) {
|
||||
|
||||
Money cumulative = Money.zero(currency);
|
||||
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isFeeCharge() && !loanCharge.isDueAtDisbursement()) {
|
||||
boolean isDue = isFirstPeriod ? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, periodEnd)
|
||||
: loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
|
||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
||||
if (loanChargePerInstallment != null) {
|
||||
cumulative = cumulative.plus(loanChargePerInstallment.getAmountWrittenOff(currency));
|
||||
}
|
||||
} else if (isDue) {
|
||||
cumulative = cumulative.plus(loanCharge.getAmountWrittenOff(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cumulative;
|
||||
}
|
||||
|
||||
private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency currency, LoanRepaymentScheduleInstallment period,
|
||||
final Money totalPrincipal, final Money totalInterest, boolean isInstallmentChargeApplicable) {
|
||||
|
||||
Money cumulative = Money.zero(currency);
|
||||
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isPenaltyCharge()) {
|
||||
boolean isDue = period.isFirstPeriod()
|
||||
? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, periodEnd)
|
||||
: loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
|
||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||
if (loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
|
||||
amount = amount.add(period.getPrincipal(currency).getAmount())
|
||||
.add(period.getInterestCharged(currency).getAmount());
|
||||
} else if (loanCharge.getChargeCalculation().isPercentageOfInterest()) {
|
||||
amount = amount.add(period.getInterestCharged(currency).getAmount());
|
||||
} else {
|
||||
amount = amount.add(period.getPrincipal(currency).getAmount());
|
||||
}
|
||||
BigDecimal loanChargeAmt = amount.multiply(loanCharge.getPercentage()).divide(BigDecimal.valueOf(100));
|
||||
cumulative = cumulative.plus(loanChargeAmt);
|
||||
} else {
|
||||
cumulative = cumulative.plus(loanCharge.amountOrPercentage());
|
||||
}
|
||||
} else if (loanCharge.isOverdueInstallmentCharge() && isDue && loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = cumulative.plus(loanCharge.chargeAmount());
|
||||
} else if (isDue && loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
|
||||
amount = amount.add(totalPrincipal.getAmount()).add(totalInterest.getAmount());
|
||||
} else if (loanCharge.getChargeCalculation().isPercentageOfInterest()) {
|
||||
amount = amount.add(totalInterest.getAmount());
|
||||
} else {
|
||||
amount = amount.add(totalPrincipal.getAmount());
|
||||
}
|
||||
BigDecimal loanChargeAmt = amount.multiply(loanCharge.getPercentage()).divide(BigDecimal.valueOf(100));
|
||||
cumulative = cumulative.plus(loanChargeAmt);
|
||||
} else if (isDue) {
|
||||
cumulative = cumulative.plus(loanCharge.amount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cumulative;
|
||||
}
|
||||
|
||||
private Money cumulativePenaltyChargesWaivedWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency currency, boolean isInstallmentChargeApplicable,
|
||||
boolean isFirstPeriod) {
|
||||
|
||||
Money cumulative = Money.zero(currency);
|
||||
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isPenaltyCharge()) {
|
||||
boolean isDue = isFirstPeriod ? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, periodEnd)
|
||||
: loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
|
||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
||||
if (loanChargePerInstallment != null) {
|
||||
cumulative = cumulative.plus(loanChargePerInstallment.getAmountWaived(currency));
|
||||
}
|
||||
} else if (isDue) {
|
||||
cumulative = cumulative.plus(loanCharge.getAmountWaived(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cumulative;
|
||||
}
|
||||
|
||||
private Money cumulativePenaltyChargesWrittenOffWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency currency, boolean isInstallmentChargeApplicable,
|
||||
final boolean isFirstPeriod) {
|
||||
|
||||
Money cumulative = Money.zero(currency);
|
||||
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isPenaltyCharge()) {
|
||||
boolean isDue = isFirstPeriod ? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart, periodEnd)
|
||||
: loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd);
|
||||
if (loanCharge.isInstalmentFee() && isInstallmentChargeApplicable) {
|
||||
LoanInstallmentCharge loanChargePerInstallment = loanCharge.getInstallmentLoanCharge(periodEnd);
|
||||
if (loanChargePerInstallment != null) {
|
||||
cumulative = cumulative.plus(loanChargePerInstallment.getAmountWrittenOff(currency));
|
||||
}
|
||||
} else if (isDue) {
|
||||
cumulative = cumulative.plus(loanCharge.getAmountWrittenOff(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cumulative;
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LoanRepaymentScheduleTransactionProcessorFactory {
|
||||
|
||||
private final LoanRepaymentScheduleTransactionProcessor defaultLoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
private final List<LoanRepaymentScheduleTransactionProcessor> processors;
|
||||
|
||||
@Value("${fineract.loan.transactionprocessor.error-not-found-fail}")
|
||||
private Boolean errorNotFoundFail;
|
||||
|
||||
public LoanRepaymentScheduleTransactionProcessor determineProcessor(final String transactionProcessingStrategy) {
|
||||
|
||||
Optional<LoanRepaymentScheduleTransactionProcessor> processor = processors.stream()
|
||||
.filter(p -> p.accept(transactionProcessingStrategy)).findFirst();
|
||||
|
||||
if (processor.isEmpty() && Boolean.TRUE.equals(errorNotFoundFail)) {
|
||||
throw new LoanTransactionProcessingStrategyNotFoundException(transactionProcessingStrategy);
|
||||
} else {
|
||||
return processor.orElse(defaultLoanRepaymentScheduleTransactionProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
public List<TransactionProcessingStrategyData> getStrategies() {
|
||||
return processors.stream().map(p -> new TransactionProcessingStrategyData(null, p.getCode(), p.getName())).toList();
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
/**
|
||||
* Enum representation of loan status states.
|
||||
*/
|
||||
public enum LoanStatus {
|
||||
|
||||
INVALID(0, "loanStatusType.invalid"), //
|
||||
SUBMITTED_AND_PENDING_APPROVAL(100, "loanStatusType.submitted.and.pending.approval"), //
|
||||
APPROVED(200, "loanStatusType.approved"), //
|
||||
ACTIVE(300, "loanStatusType.active"), //
|
||||
TRANSFER_IN_PROGRESS(303, "loanStatusType.transfer.in.progress"), //
|
||||
TRANSFER_ON_HOLD(304, "loanStatusType.transfer.on.hold"), //
|
||||
WITHDRAWN_BY_CLIENT(400, "loanStatusType.withdrawn.by.client"), //
|
||||
REJECTED(500, "loanStatusType.rejected"), //
|
||||
CLOSED_OBLIGATIONS_MET(600, "loanStatusType.closed.obligations.met"), //
|
||||
CLOSED_WRITTEN_OFF(601, "loanStatusType.closed.written.off"), //
|
||||
CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT(602, "loanStatusType.closed.reschedule.outstanding.amount"), //
|
||||
OVERPAID(700, "loanStatusType.overpaid");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
public static LoanStatus fromInt(final Integer statusValue) {
|
||||
|
||||
LoanStatus enumeration = LoanStatus.INVALID;
|
||||
switch (statusValue) {
|
||||
case 100:
|
||||
enumeration = LoanStatus.SUBMITTED_AND_PENDING_APPROVAL;
|
||||
break;
|
||||
case 200:
|
||||
enumeration = LoanStatus.APPROVED;
|
||||
break;
|
||||
case 300:
|
||||
enumeration = LoanStatus.ACTIVE;
|
||||
break;
|
||||
case 303:
|
||||
enumeration = LoanStatus.TRANSFER_IN_PROGRESS;
|
||||
break;
|
||||
case 304:
|
||||
enumeration = LoanStatus.TRANSFER_ON_HOLD;
|
||||
break;
|
||||
case 400:
|
||||
enumeration = LoanStatus.WITHDRAWN_BY_CLIENT;
|
||||
break;
|
||||
case 500:
|
||||
enumeration = LoanStatus.REJECTED;
|
||||
break;
|
||||
case 600:
|
||||
enumeration = LoanStatus.CLOSED_OBLIGATIONS_MET;
|
||||
break;
|
||||
case 601:
|
||||
enumeration = LoanStatus.CLOSED_WRITTEN_OFF;
|
||||
break;
|
||||
case 602:
|
||||
enumeration = LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT;
|
||||
break;
|
||||
case 700:
|
||||
enumeration = LoanStatus.OVERPAID;
|
||||
break;
|
||||
}
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
LoanStatus(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public boolean hasStateOf(final LoanStatus state) {
|
||||
return this.value.equals(state.getValue());
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public boolean isSubmittedAndPendingApproval() {
|
||||
return this.value.equals(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue());
|
||||
}
|
||||
|
||||
public boolean isApproved() {
|
||||
return this.value.equals(LoanStatus.APPROVED.getValue());
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.value.equals(LoanStatus.ACTIVE.getValue());
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return isClosedObligationsMet() || isClosedWrittenOff() || isClosedWithOutsandingAmountMarkedForReschedule();
|
||||
}
|
||||
|
||||
public boolean isClosedObligationsMet() {
|
||||
return this.value.equals(LoanStatus.CLOSED_OBLIGATIONS_MET.getValue());
|
||||
}
|
||||
|
||||
public boolean isClosedWrittenOff() {
|
||||
return this.value.equals(LoanStatus.CLOSED_WRITTEN_OFF.getValue());
|
||||
}
|
||||
|
||||
public boolean isClosedWithOutsandingAmountMarkedForReschedule() {
|
||||
return this.value.equals(LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT.getValue());
|
||||
}
|
||||
|
||||
public boolean isWithdrawnByClient() {
|
||||
return this.value.equals(LoanStatus.WITHDRAWN_BY_CLIENT.getValue());
|
||||
}
|
||||
|
||||
public boolean isRejected() {
|
||||
return this.value.equals(LoanStatus.REJECTED.getValue());
|
||||
}
|
||||
|
||||
public boolean isActiveOrAwaitingApprovalOrDisbursal() {
|
||||
return isApproved() || isSubmittedAndPendingApproval() || isActive();
|
||||
}
|
||||
|
||||
public boolean isTransferInProgress() {
|
||||
return this.value.equals(LoanStatus.TRANSFER_IN_PROGRESS.getValue());
|
||||
}
|
||||
|
||||
public boolean isTransferOnHold() {
|
||||
return this.value.equals(LoanStatus.TRANSFER_ON_HOLD.getValue());
|
||||
}
|
||||
|
||||
public boolean isUnderTransfer() {
|
||||
return isTransferInProgress() || isTransferOnHold();
|
||||
}
|
||||
|
||||
public boolean isOverpaid() {
|
||||
return this.value.equals(LoanStatus.OVERPAID.getValue());
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public enum LoanSubStatus {
|
||||
|
||||
INVALID(0, "loanSubStatusType.invalid"), //
|
||||
FORECLOSED(100, "loanSubStatusType.foreclosed");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
public static LoanSubStatus fromInt(final Integer statusValue) {
|
||||
|
||||
LoanSubStatus enumeration = LoanSubStatus.INVALID;
|
||||
switch (statusValue) {
|
||||
case 100:
|
||||
enumeration = LoanSubStatus.FORECLOSED;
|
||||
break;
|
||||
}
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
LoanSubStatus(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public boolean hasStateOf(final LoanSubStatus state) {
|
||||
return this.value.equals(state.getValue());
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public boolean isForeclosed() {
|
||||
return this.value.equals(LoanSubStatus.FORECLOSED.getValue());
|
||||
}
|
||||
|
||||
public static EnumOptionData loanSubStatus(final int id) {
|
||||
return loanSubStatusEnum(LoanSubStatus.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData loanSubStatusEnum(final LoanSubStatus type) {
|
||||
final String codePrefix = "loanSubStatus.";
|
||||
EnumOptionData optionData = null;
|
||||
switch (type) {
|
||||
case FORECLOSED:
|
||||
optionData = new EnumOptionData(LoanSubStatus.FORECLOSED.getValue().longValue(),
|
||||
codePrefix + LoanSubStatus.FORECLOSED.getCode(), "Foreclosed");
|
||||
break;
|
||||
default:
|
||||
optionData = new EnumOptionData(LoanSubStatus.INVALID.getValue().longValue(), LoanSubStatus.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
}
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
|
||||
/**
|
||||
* Encapsulates all the summary details of a {@link Loan}.
|
||||
*
|
||||
* {@link LoanSummary} fields are updated through a scheduled job. see -
|
||||
*
|
||||
*/
|
||||
@Embeddable
|
||||
@Getter
|
||||
public class LoanSummary {
|
||||
|
||||
// derived totals fields
|
||||
@Column(name = "principal_disbursed_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalDisbursed;
|
||||
|
||||
@Column(name = "principal_adjustments_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalAdjustments;
|
||||
|
||||
@Column(name = "principal_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalRepaid;
|
||||
|
||||
@Column(name = "principal_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalWrittenOff;
|
||||
|
||||
@Column(name = "principal_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPrincipalOutstanding;
|
||||
|
||||
@Column(name = "interest_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestCharged;
|
||||
|
||||
@Column(name = "interest_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestRepaid;
|
||||
|
||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestWaived;
|
||||
|
||||
@Column(name = "interest_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestWrittenOff;
|
||||
|
||||
@Column(name = "interest_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalInterestOutstanding;
|
||||
|
||||
@Column(name = "fee_charges_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesCharged;
|
||||
|
||||
@Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesDueAtDisbursement;
|
||||
|
||||
@Column(name = "fee_charges_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesRepaid;
|
||||
|
||||
@Column(name = "fee_charges_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesWaived;
|
||||
|
||||
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesWrittenOff;
|
||||
|
||||
@Column(name = "fee_charges_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalFeeChargesOutstanding;
|
||||
|
||||
@Column(name = "penalty_charges_charged_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesCharged;
|
||||
|
||||
@Column(name = "penalty_charges_repaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesRepaid;
|
||||
|
||||
@Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesWaived;
|
||||
|
||||
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesWrittenOff;
|
||||
|
||||
@Column(name = "penalty_charges_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPenaltyChargesOutstanding;
|
||||
|
||||
@Column(name = "total_expected_repayment_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalExpectedRepayment;
|
||||
|
||||
@Column(name = "total_repayment_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalRepayment;
|
||||
|
||||
@Column(name = "total_expected_costofloan_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalExpectedCostOfLoan;
|
||||
|
||||
@Column(name = "total_costofloan_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalCostOfLoan;
|
||||
|
||||
@Column(name = "total_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalWaived;
|
||||
|
||||
@Column(name = "total_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalWrittenOff;
|
||||
|
||||
@Column(name = "total_outstanding_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOutstanding;
|
||||
|
||||
public static LoanSummary create(final BigDecimal totalFeeChargesDueAtDisbursement) {
|
||||
return new LoanSummary(totalFeeChargesDueAtDisbursement);
|
||||
}
|
||||
|
||||
protected LoanSummary() {
|
||||
//
|
||||
}
|
||||
|
||||
private LoanSummary(final BigDecimal totalFeeChargesDueAtDisbursement) {
|
||||
this.totalFeeChargesDueAtDisbursement = totalFeeChargesDueAtDisbursement;
|
||||
}
|
||||
|
||||
public void updateTotalFeeChargesDueAtDisbursement(final BigDecimal totalFeeChargesDueAtDisbursement) {
|
||||
this.totalFeeChargesDueAtDisbursement = totalFeeChargesDueAtDisbursement;
|
||||
}
|
||||
|
||||
public Money getTotalFeeChargesDueAtDisbursement(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.totalFeeChargesDueAtDisbursement);
|
||||
}
|
||||
|
||||
public Money getTotalOutstanding(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.totalOutstanding);
|
||||
}
|
||||
|
||||
public void updateFeeChargeOutstanding(final BigDecimal totalFeeChargesOutstanding) {
|
||||
this.totalFeeChargesOutstanding = totalFeeChargesOutstanding;
|
||||
}
|
||||
|
||||
public void updatePenaltyChargeOutstanding(final BigDecimal totalPenaltyChargesOutstanding) {
|
||||
this.totalPenaltyChargesOutstanding = totalPenaltyChargesOutstanding;
|
||||
}
|
||||
|
||||
public void updateFeeChargesWaived(final BigDecimal totalFeeChargesWaived) {
|
||||
this.totalFeeChargesWaived = totalFeeChargesWaived;
|
||||
}
|
||||
|
||||
public void updatePenaltyChargesWaived(final BigDecimal totalPenaltyChargesWaived) {
|
||||
this.totalPenaltyChargesWaived = totalPenaltyChargesWaived;
|
||||
}
|
||||
|
||||
public boolean isRepaidInFull(final MonetaryCurrency currency) {
|
||||
return getTotalOutstanding(currency).isZero();
|
||||
}
|
||||
|
||||
public BigDecimal getTotalInterestCharged() {
|
||||
return this.totalInterestCharged;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPrincipalOutstanding() {
|
||||
return this.totalPrincipalOutstanding;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalInterestOutstanding() {
|
||||
return this.totalInterestOutstanding;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalFeeChargesOutstanding() {
|
||||
return this.totalFeeChargesOutstanding;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesOutstanding() {
|
||||
return this.totalPenaltyChargesOutstanding;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalOutstanding() {
|
||||
return this.totalOutstanding;
|
||||
}
|
||||
|
||||
public void updateTotalOutstanding(final BigDecimal newTotalOutstanding) {
|
||||
this.totalOutstanding = newTotalOutstanding;
|
||||
}
|
||||
|
||||
public void updateTotalWaived(final BigDecimal totalWaived) {
|
||||
this.totalWaived = totalWaived;
|
||||
}
|
||||
|
||||
/**
|
||||
* All fields but <code>totalFeeChargesDueAtDisbursement</code> should be reset.
|
||||
*/
|
||||
public void zeroFields() {
|
||||
this.totalPrincipalDisbursed = BigDecimal.ZERO;
|
||||
this.totalPrincipalAdjustments = BigDecimal.ZERO;
|
||||
this.totalPrincipalRepaid = BigDecimal.ZERO;
|
||||
this.totalPrincipalWrittenOff = BigDecimal.ZERO;
|
||||
this.totalPrincipalOutstanding = BigDecimal.ZERO;
|
||||
this.totalInterestCharged = BigDecimal.ZERO;
|
||||
this.totalInterestRepaid = BigDecimal.ZERO;
|
||||
this.totalInterestWaived = BigDecimal.ZERO;
|
||||
this.totalInterestWrittenOff = BigDecimal.ZERO;
|
||||
this.totalInterestOutstanding = BigDecimal.ZERO;
|
||||
this.totalFeeChargesCharged = BigDecimal.ZERO;
|
||||
this.totalFeeChargesRepaid = BigDecimal.ZERO;
|
||||
this.totalFeeChargesWaived = BigDecimal.ZERO;
|
||||
this.totalFeeChargesWrittenOff = BigDecimal.ZERO;
|
||||
this.totalFeeChargesOutstanding = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesCharged = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesRepaid = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesWaived = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesWrittenOff = BigDecimal.ZERO;
|
||||
this.totalPenaltyChargesOutstanding = BigDecimal.ZERO;
|
||||
this.totalExpectedRepayment = BigDecimal.ZERO;
|
||||
this.totalRepayment = BigDecimal.ZERO;
|
||||
this.totalExpectedCostOfLoan = BigDecimal.ZERO;
|
||||
this.totalCostOfLoan = BigDecimal.ZERO;
|
||||
this.totalWaived = BigDecimal.ZERO;
|
||||
this.totalWrittenOff = BigDecimal.ZERO;
|
||||
this.totalOutstanding = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void updateSummary(final MonetaryCurrency currency, final Money principal,
|
||||
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LoanSummaryWrapper summaryWrapper,
|
||||
Set<LoanCharge> charges) {
|
||||
|
||||
this.totalPrincipalDisbursed = principal.getAmount();
|
||||
this.totalPrincipalAdjustments = summaryWrapper.calculateTotalPrincipalAdjusted(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
this.totalPrincipalRepaid = summaryWrapper.calculateTotalPrincipalRepaid(repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalPrincipalWrittenOff = summaryWrapper.calculateTotalPrincipalWrittenOff(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
this.totalPrincipalOutstanding = principal.plus(this.totalPrincipalAdjustments).minus(this.totalPrincipalRepaid)
|
||||
.minus(this.totalPrincipalWrittenOff).getAmount();
|
||||
|
||||
final Money totalInterestCharged = summaryWrapper.calculateTotalInterestCharged(repaymentScheduleInstallments, currency);
|
||||
this.totalInterestCharged = totalInterestCharged.getAmount();
|
||||
this.totalInterestRepaid = summaryWrapper.calculateTotalInterestRepaid(repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalInterestWaived = summaryWrapper.calculateTotalInterestWaived(repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalInterestWrittenOff = summaryWrapper.calculateTotalInterestWrittenOff(repaymentScheduleInstallments, currency).getAmount();
|
||||
|
||||
this.totalInterestOutstanding = totalInterestCharged.minus(this.totalInterestRepaid).minus(this.totalInterestWaived)
|
||||
.minus(this.totalInterestWrittenOff).getAmount();
|
||||
|
||||
final Money totalFeeChargesCharged = summaryWrapper.calculateTotalFeeChargesCharged(repaymentScheduleInstallments, currency)
|
||||
.plus(this.totalFeeChargesDueAtDisbursement);
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged.getAmount();
|
||||
|
||||
Money totalFeeChargesRepaidAtDisbursement = summaryWrapper.calculateTotalChargesRepaidAtDisbursement(charges, currency);
|
||||
this.totalFeeChargesRepaid = totalFeeChargesRepaidAtDisbursement.getAmount();
|
||||
|
||||
if (charges != null) {
|
||||
this.totalFeeChargesWaived = summaryWrapper.calculateTotalFeeChargesWaived(charges, currency).getAmount();
|
||||
} else {
|
||||
this.totalFeeChargesWaived = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
this.totalFeeChargesWrittenOff = summaryWrapper.calculateTotalFeeChargesWrittenOff(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
this.totalFeeChargesOutstanding = totalFeeChargesCharged.minus(this.totalFeeChargesRepaid).minus(this.totalFeeChargesWaived)
|
||||
.minus(this.totalFeeChargesWrittenOff).getAmount();
|
||||
|
||||
final Money totalPenaltyChargesCharged = summaryWrapper.calculateTotalPenaltyChargesCharged(repaymentScheduleInstallments,
|
||||
currency);
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged.getAmount();
|
||||
this.totalPenaltyChargesRepaid = summaryWrapper.calculateTotalPenaltyChargesRepaid(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
this.totalPenaltyChargesWaived = summaryWrapper.calculateTotalPenaltyChargesWaived(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
this.totalPenaltyChargesWrittenOff = summaryWrapper.calculateTotalPenaltyChargesWrittenOff(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
this.totalPenaltyChargesOutstanding = totalPenaltyChargesCharged.minus(this.totalPenaltyChargesRepaid)
|
||||
.minus(this.totalPenaltyChargesWaived).minus(this.totalPenaltyChargesWrittenOff).getAmount();
|
||||
|
||||
final Money totalExpectedRepayment = Money.of(currency, this.totalPrincipalDisbursed).plus(this.totalInterestCharged)
|
||||
.plus(this.totalFeeChargesCharged).plus(this.totalPenaltyChargesCharged);
|
||||
this.totalExpectedRepayment = totalExpectedRepayment.getAmount();
|
||||
|
||||
final Money totalRepayment = Money.of(currency, this.totalPrincipalRepaid).plus(this.totalInterestRepaid)
|
||||
.plus(this.totalFeeChargesRepaid).plus(this.totalPenaltyChargesRepaid);
|
||||
this.totalRepayment = totalRepayment.getAmount();
|
||||
|
||||
final Money totalExpectedCostOfLoan = Money.of(currency, this.totalInterestCharged).plus(this.totalFeeChargesCharged)
|
||||
.plus(this.totalPenaltyChargesCharged);
|
||||
this.totalExpectedCostOfLoan = totalExpectedCostOfLoan.getAmount();
|
||||
|
||||
final Money totalCostOfLoan = Money.of(currency, this.totalInterestRepaid).plus(this.totalFeeChargesRepaid)
|
||||
.plus(this.totalPenaltyChargesRepaid);
|
||||
this.totalCostOfLoan = totalCostOfLoan.getAmount();
|
||||
|
||||
final Money totalWaived = Money.of(currency, this.totalInterestWaived).plus(this.totalFeeChargesWaived)
|
||||
.plus(this.totalPenaltyChargesWaived);
|
||||
this.totalWaived = totalWaived.getAmount();
|
||||
|
||||
final Money totalWrittenOff = Money.of(currency, this.totalPrincipalWrittenOff).plus(this.totalInterestWrittenOff)
|
||||
.plus(this.totalFeeChargesWrittenOff).plus(this.totalPenaltyChargesWrittenOff);
|
||||
this.totalWrittenOff = totalWrittenOff.getAmount();
|
||||
|
||||
final Money totalOutstanding = Money.of(currency, this.totalPrincipalOutstanding).plus(this.totalInterestOutstanding)
|
||||
.plus(this.totalFeeChargesOutstanding).plus(this.totalPenaltyChargesOutstanding);
|
||||
this.totalOutstanding = totalOutstanding.getAmount();
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPrincipalDisbursed() {
|
||||
return this.totalPrincipalDisbursed;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPrincipalRepaid() {
|
||||
return this.totalPrincipalRepaid;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalWrittenOff() {
|
||||
return this.totalWrittenOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return total interest repaid
|
||||
**/
|
||||
public BigDecimal getTotalInterestRepaid() {
|
||||
return this.totalInterestRepaid;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalFeeChargesCharged() {
|
||||
return this.totalFeeChargesCharged;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesCharged() {
|
||||
return this.totalPenaltyChargesCharged;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPrincipalWrittenOff() {
|
||||
return this.totalPrincipalWrittenOff;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalInterestWaived() {
|
||||
return this.totalInterestWaived;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalFeeChargesRepaid() {
|
||||
return this.totalFeeChargesRepaid;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalFeeChargesWaived() {
|
||||
return this.totalFeeChargesWaived;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesRepaid() {
|
||||
return this.totalPenaltyChargesRepaid;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesWaived() {
|
||||
return this.totalPenaltyChargesWaived;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalExpectedRepayment() {
|
||||
return this.totalExpectedRepayment;
|
||||
}
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* A wrapper for dealing with side-effect free functionality related to a loans transactions and repayment schedule.
|
||||
*/
|
||||
@Component
|
||||
public final class LoanSummaryWrapper {
|
||||
|
||||
public Money calculateTotalPrincipalRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPrincipalCompleted(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPrincipalAdjusted(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getCredits(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPrincipalWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPrincipalWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPrincipalOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestCharged(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestCharged(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestPaid(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestWaived(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestWaived(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getInterestWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalInterestOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getInterestOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesCharged(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getFeeChargesCharged(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getFeeChargesPaid(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesWaived(Set<LoanCharge> charges, final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanCharge charge : charges) {
|
||||
if (charge.isActive() && !charge.isPenaltyCharge()) {
|
||||
total = total.plus(charge.getAmountWaived(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getFeeChargesWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalFeeChargesOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getFeeChargesOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesCharged(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesCharged(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesRepaid(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesPaid(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesWaived(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesWaived(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesWrittenOff(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
total = total.plus(installment.getPenaltyChargesWrittenOff(currency));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalPenaltyChargesOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(overdueAsOf)) {
|
||||
total = total.plus(installment.getPenaltyChargesOutstanding(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public Money calculateTotalOverdueOn(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate overdueAsOf) {
|
||||
|
||||
final Money principalOverdue = calculateTotalPrincipalOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
final Money interestOverdue = calculateTotalInterestOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
final Money feeChargesOverdue = calculateTotalFeeChargesOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
final Money penaltyChargesOverdue = calculateTotalPenaltyChargesOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf);
|
||||
|
||||
return principalOverdue.plus(interestOverdue).plus(feeChargesOverdue).plus(penaltyChargesOverdue);
|
||||
}
|
||||
|
||||
public LocalDate determineOverdueSinceDateFrom(final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
|
||||
final MonetaryCurrency currency, final LocalDate from) {
|
||||
|
||||
LocalDate overdueSince = null;
|
||||
final Money totalOverdue = calculateTotalOverdueOn(repaymentScheduleInstallments, currency, from);
|
||||
if (totalOverdue.isGreaterThanZero()) {
|
||||
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
|
||||
if (installment.isOverdueOn(from)) {
|
||||
if (overdueSince == null || overdueSince.isAfter(installment.getDueDate())) {
|
||||
overdueSince = installment.getDueDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return overdueSince;
|
||||
}
|
||||
|
||||
public Money calculateTotalChargesRepaidAtDisbursement(Set<LoanCharge> charges, MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
if (charges == null) {
|
||||
return total;
|
||||
}
|
||||
for (final LoanCharge loanCharge : charges) {
|
||||
if (!loanCharge.isPenaltyCharge() && loanCharge.getAmountPaid(currency).isGreaterThanZero()) {
|
||||
total = total.plus(loanCharge.getAmountPaid(currency));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
|
||||
}
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
public enum LoanTermVariationType {
|
||||
|
||||
INVALID(0, "loanTermType.invalid"), //
|
||||
EMI_AMOUNT(1, "loanTermType.emiAmount"), //
|
||||
INTEREST_RATE(2, "loanTermType.interestRate"), //
|
||||
PRINCIPAL_AMOUNT(3, "loanTermType.principalAmount"), //
|
||||
DUE_DATE(4, "loanTermType.dueDate"), //
|
||||
INSERT_INSTALLMENT(5, "loanTermType.insertInstallment"), //
|
||||
DELETE_INSTALLMENT(6, "loanTermType.deleteInstallment"), GRACE_ON_INTEREST(7, "loanTermType.graceOnInterest"), GRACE_ON_PRINCIPAL(8,
|
||||
"loanTermType.graceOnPrincipal"), EXTEND_REPAYMENT_PERIOD(9,
|
||||
"loanTermType.extendRepaymentPeriod"), INTEREST_RATE_FROM_INSTALLMENT(10, "loanTermType.interestRateFromInstallment");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
LoanTermVariationType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static LoanTermVariationType fromInt(final Integer value) {
|
||||
|
||||
LoanTermVariationType enumeration = LoanTermVariationType.INVALID;
|
||||
switch (value) {
|
||||
case 1:
|
||||
enumeration = LoanTermVariationType.EMI_AMOUNT;
|
||||
break;
|
||||
case 2:
|
||||
enumeration = LoanTermVariationType.INTEREST_RATE;
|
||||
break;
|
||||
case 3:
|
||||
enumeration = LoanTermVariationType.PRINCIPAL_AMOUNT;
|
||||
break;
|
||||
case 4:
|
||||
enumeration = LoanTermVariationType.DUE_DATE;
|
||||
break;
|
||||
case 5:
|
||||
enumeration = LoanTermVariationType.INSERT_INSTALLMENT;
|
||||
break;
|
||||
case 6:
|
||||
enumeration = LoanTermVariationType.DELETE_INSTALLMENT;
|
||||
break;
|
||||
case 7:
|
||||
enumeration = LoanTermVariationType.GRACE_ON_INTEREST;
|
||||
break;
|
||||
case 8:
|
||||
enumeration = LoanTermVariationType.GRACE_ON_PRINCIPAL;
|
||||
break;
|
||||
case 9:
|
||||
enumeration = LoanTermVariationType.EXTEND_REPAYMENT_PERIOD;
|
||||
break;
|
||||
case 10:
|
||||
enumeration = LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT;
|
||||
break;
|
||||
}
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
public boolean isEMIAmountVariation() {
|
||||
return this.value.equals(LoanTermVariationType.EMI_AMOUNT.getValue());
|
||||
}
|
||||
|
||||
public boolean isInterestRateVariation() {
|
||||
return this.value.equals(LoanTermVariationType.INTEREST_RATE.getValue());
|
||||
}
|
||||
|
||||
public boolean isPrincipalAmountVariation() {
|
||||
return this.value.equals(LoanTermVariationType.PRINCIPAL_AMOUNT.getValue());
|
||||
}
|
||||
|
||||
public boolean isDueDateVariation() {
|
||||
return this.value.equals(LoanTermVariationType.DUE_DATE.getValue());
|
||||
}
|
||||
|
||||
public boolean isInsertInstallment() {
|
||||
return this.value.equals(LoanTermVariationType.INSERT_INSTALLMENT.getValue());
|
||||
}
|
||||
|
||||
public boolean isDeleteInstallment() {
|
||||
return this.value.equals(LoanTermVariationType.DELETE_INSTALLMENT.getValue());
|
||||
}
|
||||
|
||||
public boolean isGraceOnInterest() {
|
||||
return this.value.equals(LoanTermVariationType.GRACE_ON_INTEREST.getValue());
|
||||
}
|
||||
|
||||
public boolean isGraceOnPrincipal() {
|
||||
return this.value.equals(LoanTermVariationType.GRACE_ON_PRINCIPAL.getValue());
|
||||
}
|
||||
|
||||
public boolean isExtendRepaymentPeriod() {
|
||||
return this.value.equals(LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue());
|
||||
}
|
||||
|
||||
public boolean isInterestRateFromInstallment() {
|
||||
return this.value.equals(LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT.getValue());
|
||||
}
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_term_variations")
|
||||
public class LoanTermVariations extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@Column(name = "term_type", nullable = false)
|
||||
private Integer termType;
|
||||
|
||||
@Column(name = "applicable_date", nullable = false)
|
||||
private LocalDate termApplicableFrom;
|
||||
|
||||
@Column(name = "decimal_value", scale = 6, precision = 19)
|
||||
private BigDecimal decimalValue;
|
||||
|
||||
@Column(name = "date_value")
|
||||
private LocalDate dateValue;
|
||||
|
||||
@Column(name = "is_specific_to_installment", nullable = false)
|
||||
private boolean isSpecificToInstallment;
|
||||
|
||||
@Column(name = "applied_on_loan_status", nullable = false)
|
||||
private Integer onLoanStatus;
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private Boolean isActive;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "parent_id")
|
||||
private LoanTermVariations parent;
|
||||
|
||||
public LoanTermVariations(final Integer termType, final LocalDate termApplicableFrom, final BigDecimal decimalValue,
|
||||
final LocalDate dateValue, final boolean isSpecificToInstallment, final Loan loan) {
|
||||
this.loan = loan;
|
||||
this.termApplicableFrom = termApplicableFrom;
|
||||
this.termType = termType;
|
||||
this.decimalValue = decimalValue;
|
||||
this.dateValue = dateValue;
|
||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||
this.onLoanStatus = loan.getStatus().getValue();
|
||||
this.isActive = true;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
public LoanTermVariations(final Integer termType, final LocalDate termApplicableFrom, final BigDecimal decimalValue,
|
||||
final LocalDate dateValue, final boolean isSpecificToInstallment, final Loan loan, final Integer loanStatus) {
|
||||
this.loan = loan;
|
||||
this.termApplicableFrom = termApplicableFrom;
|
||||
this.termType = termType;
|
||||
this.decimalValue = decimalValue;
|
||||
this.dateValue = dateValue;
|
||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||
this.onLoanStatus = loanStatus;
|
||||
this.isActive = true;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
public LoanTermVariations(final Integer termType, final LocalDate termApplicableFrom, final BigDecimal decimalValue,
|
||||
final LocalDate dateValue, final boolean isSpecificToInstallment, final Loan loan, final Integer loanStatus,
|
||||
final Boolean isActive, final LoanTermVariations parent) {
|
||||
this.loan = loan;
|
||||
this.termApplicableFrom = termApplicableFrom;
|
||||
this.termType = termType;
|
||||
this.decimalValue = decimalValue;
|
||||
this.dateValue = dateValue;
|
||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||
this.onLoanStatus = loanStatus;
|
||||
this.isActive = isActive;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
protected LoanTermVariations() {
|
||||
|
||||
}
|
||||
|
||||
public LoanTermVariationType getTermType() {
|
||||
return LoanTermVariationType.fromInt(this.termType);
|
||||
}
|
||||
|
||||
public LoanTermVariationsData toData() {
|
||||
EnumOptionData type = LoanEnumerations.loanVariationType(this.termType);
|
||||
return new LoanTermVariationsData(getId(), type, this.termApplicableFrom, this.decimalValue, this.dateValue,
|
||||
this.isSpecificToInstallment);
|
||||
}
|
||||
|
||||
public LocalDate getTermApplicableFrom() {
|
||||
return this.termApplicableFrom;
|
||||
}
|
||||
|
||||
public LocalDate fetchTermApplicaDate() {
|
||||
return this.termApplicableFrom;
|
||||
}
|
||||
|
||||
public BigDecimal getTermValue() {
|
||||
return this.decimalValue;
|
||||
}
|
||||
|
||||
public LocalDate getDateValue() {
|
||||
return this.dateValue;
|
||||
}
|
||||
|
||||
public LocalDate fetchDateValue() {
|
||||
return this.dateValue;
|
||||
}
|
||||
|
||||
public void setTermApplicableFrom(LocalDate termApplicableFrom) {
|
||||
this.termApplicableFrom = termApplicableFrom;
|
||||
}
|
||||
|
||||
public void setDecimalValue(BigDecimal decimalValue) {
|
||||
this.decimalValue = decimalValue;
|
||||
}
|
||||
|
||||
public Integer getOnLoanStatus() {
|
||||
return this.onLoanStatus;
|
||||
}
|
||||
|
||||
public Boolean isActive() {
|
||||
return this.isActive;
|
||||
}
|
||||
|
||||
public LoanTermVariations parent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public void updateIsActive(final Boolean isActive) {
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
public void markAsInactive() {
|
||||
this.isActive = false;
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_topup")
|
||||
public class LoanTopupDetails extends AbstractPersistableCustom {
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@Column(name = "closure_loan_id", nullable = false)
|
||||
private Long closureLoanId;
|
||||
|
||||
@Column(name = "account_transfer_details_id", nullable = true)
|
||||
private Long accountTransferDetailsId;
|
||||
|
||||
@Column(name = "topup_amount", nullable = true)
|
||||
private BigDecimal topupAmount;
|
||||
|
||||
protected LoanTopupDetails() {}
|
||||
|
||||
public LoanTopupDetails(final Loan loan, final Long loanIdToClose) {
|
||||
this.loan = loan;
|
||||
this.closureLoanId = loanIdToClose;
|
||||
}
|
||||
|
||||
public Long getLoanIdToClose() {
|
||||
return this.closureLoanId;
|
||||
}
|
||||
|
||||
public BigDecimal getTopupAmount() {
|
||||
return this.topupAmount;
|
||||
}
|
||||
|
||||
public void setTopupAmount(BigDecimal topupAmount) {
|
||||
this.topupAmount = topupAmount;
|
||||
}
|
||||
|
||||
public void setAccountTransferDetails(Long accountTransferDetailsId) {
|
||||
this.accountTransferDetailsId = accountTransferDetailsId;
|
||||
}
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_tranche_charges")
|
||||
public class LoanTrancheCharge extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL, optional = false)
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL, optional = false)
|
||||
@JoinColumn(name = "charge_id", nullable = false)
|
||||
private Charge charge;
|
||||
|
||||
LoanTrancheCharge() {
|
||||
|
||||
}
|
||||
|
||||
LoanTrancheCharge(Charge chargeDefinition) {
|
||||
this.charge = chargeDefinition;
|
||||
}
|
||||
|
||||
public LoanTrancheCharge(Charge charge, Loan loan) {
|
||||
this.charge = charge;
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
public static LoanTrancheCharge createLoanTrancheCharge(Charge chargeDefinition) {
|
||||
return new LoanTrancheCharge(chargeDefinition);
|
||||
}
|
||||
|
||||
public static LoanTrancheCharge createLoanTrancheChargeWithLoan(Charge chargeDefinition, Loan loan) {
|
||||
return new LoanTrancheCharge(chargeDefinition, loan);
|
||||
}
|
||||
|
||||
public Charge getCharge() {
|
||||
return charge;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_tranche_disbursement_charge")
|
||||
public class LoanTrancheDisbursementCharge extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_charge_id", referencedColumnName = "id", nullable = false)
|
||||
private LoanCharge loancharge;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL, optional = false)
|
||||
@JoinColumn(name = "disbursement_detail_id", referencedColumnName = "id", nullable = false)
|
||||
private LoanDisbursementDetails loanDisbursementDetails;
|
||||
|
||||
public LoanTrancheDisbursementCharge() {
|
||||
|
||||
}
|
||||
|
||||
public LoanTrancheDisbursementCharge(final LoanCharge loancharge, final LoanDisbursementDetails loanDisbursementDetails) {
|
||||
this.loancharge = loancharge;
|
||||
this.loanDisbursementDetails = loanDisbursementDetails;
|
||||
}
|
||||
|
||||
public LoanDisbursementDetails getloanDisbursementDetails() {
|
||||
return this.loanDisbursementDetails;
|
||||
}
|
||||
|
||||
}
|
||||
+961
@@ -0,0 +1,961 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
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.office.domain.Office;
|
||||
import org.apache.fineract.portfolio.account.data.AccountTransferData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.apache.fineract.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
|
||||
/**
|
||||
* All monetary transactions against a loan are modelled through this entity. Disbursements, Repayments, Waivers,
|
||||
* Write-off etc
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_loan_transaction", uniqueConstraints = { @UniqueConstraint(columnNames = { "external_id" }, name = "external_id_UNIQUE") })
|
||||
public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "office_id", nullable = false)
|
||||
private Office office;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
@JoinColumn(name = "payment_detail_id", nullable = true)
|
||||
private PaymentDetail paymentDetail;
|
||||
|
||||
@Column(name = "transaction_type_enum", nullable = false)
|
||||
private Integer typeOf;
|
||||
|
||||
@Column(name = "transaction_date", nullable = false)
|
||||
private LocalDate dateOf;
|
||||
|
||||
@Column(name = "submitted_on_date", nullable = false)
|
||||
private LocalDate submittedOnDate;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
@Column(name = "principal_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal principalPortion;
|
||||
|
||||
@Column(name = "interest_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestPortion;
|
||||
|
||||
@Column(name = "fee_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesPortion;
|
||||
|
||||
@Column(name = "penalty_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesPortion;
|
||||
|
||||
@Column(name = "overpayment_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal overPaymentPortion;
|
||||
|
||||
@Column(name = "unrecognized_income_portion", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal unrecognizedIncomePortion;
|
||||
|
||||
@Column(name = "is_reversed", nullable = false)
|
||||
private boolean reversed;
|
||||
|
||||
@Column(name = "external_id", length = 100, nullable = true, unique = true)
|
||||
private ExternalId externalId;
|
||||
|
||||
@Column(name = "reversal_external_id", length = 100, nullable = true, unique = true)
|
||||
private ExternalId reversalExternalId;
|
||||
|
||||
@Column(name = "reversed_on_date", nullable = true)
|
||||
private LocalDate reversedOnDate;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private Set<LoanChargePaidBy> loanChargesPaid = new HashSet<>();
|
||||
|
||||
@Column(name = "outstanding_loan_balance_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal outstandingLoanBalance;
|
||||
|
||||
@Column(name = "manually_adjusted_or_reversed", nullable = false)
|
||||
private boolean manuallyAdjustedOrReversed;
|
||||
|
||||
@Column(name = "charge_refund_charge_type", length = 1, nullable = true, unique = true)
|
||||
private String chargeRefundChargeType;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "loanTransaction")
|
||||
private Set<LoanCollateralManagement> loanCollateralManagementSet = new HashSet<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "loanTransaction")
|
||||
private Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = new HashSet<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "fromTransaction")
|
||||
private Set<LoanTransactionRelation> loanTransactionRelations = new HashSet<>();
|
||||
|
||||
protected LoanTransaction() {}
|
||||
|
||||
public static LoanTransaction incomePosting(final Loan loan, final Office office, final LocalDate dateOf, final BigDecimal amount,
|
||||
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion,
|
||||
final ExternalId externalId) {
|
||||
final Integer typeOf = LoanTransactionType.INCOME_POSTING.getValue();
|
||||
final BigDecimal principalPortion = BigDecimal.ZERO;
|
||||
final BigDecimal overPaymentPortion = BigDecimal.ZERO;
|
||||
final boolean reversed = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
return new LoanTransaction(loan, office, typeOf, dateOf, amount, principalPortion, interestPortion, feeChargesPortion,
|
||||
penaltyChargesPortion, overPaymentPortion, reversed, paymentDetail, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction disbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate disbursementDate, final ExternalId externalId) {
|
||||
return new LoanTransaction(null, office, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate,
|
||||
externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction repayment(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate paymentDate, final ExternalId externalId) {
|
||||
return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction chargeback(final Loan loan, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate paymentDate, final ExternalId externalId) {
|
||||
LoanTransaction loanTransaction = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.CHARGEBACK, paymentDetail,
|
||||
amount.getAmount(), paymentDate, externalId);
|
||||
loanTransaction.principalPortion = amount.getAmount();
|
||||
return loanTransaction;
|
||||
}
|
||||
|
||||
public static LoanTransaction repaymentType(final LoanTransactionType repaymentType, final Office office, final Money amount,
|
||||
final PaymentDetail paymentDetail, final LocalDate paymentDate, final ExternalId externalId,
|
||||
final String chargeRefundChargeType) {
|
||||
return new LoanTransaction(null, office, repaymentType, paymentDetail, amount.getAmount(), paymentDate, externalId,
|
||||
chargeRefundChargeType);
|
||||
}
|
||||
|
||||
public static LoanTransaction chargeAdjustment(final Loan loan, final BigDecimal amount, final LocalDate transactionDate,
|
||||
final ExternalId externalId, PaymentDetail paymentDetail) {
|
||||
return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.CHARGE_ADJUSTMENT, paymentDetail, amount, transactionDate,
|
||||
externalId);
|
||||
}
|
||||
|
||||
public void setLoanTransactionToRepaymentScheduleMappings(final Integer installmentId, final BigDecimal chargePerInstallment) {
|
||||
for (LoanTransactionToRepaymentScheduleMapping loanTransactionToRepaymentScheduleMapping : this.loanTransactionToRepaymentScheduleMappings) {
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loanTransactionToRepaymentScheduleMapping
|
||||
.getLoanRepaymentScheduleInstallment();
|
||||
if (loanRepaymentScheduleInstallment.getInstallmentNumber().equals(installmentId)) {
|
||||
loanRepaymentScheduleInstallment.updateLoanRepaymentSchedule(chargePerInstallment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static LoanTransaction recoveryRepayment(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate paymentDate, final ExternalId externalId) {
|
||||
return new LoanTransaction(null, office, LoanTransactionType.RECOVERY_REPAYMENT, paymentDetail, amount.getAmount(), paymentDate,
|
||||
externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction loanPayment(final Loan loan, final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate paymentDate, final ExternalId externalId, final LoanTransactionType transactionType) {
|
||||
return new LoanTransaction(loan, office, transactionType, paymentDetail, amount.getAmount(), paymentDate, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction repaymentAtDisbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate paymentDate, final ExternalId externalId) {
|
||||
return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT, paymentDetail, amount.getAmount(),
|
||||
paymentDate, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction waiver(final Office office, final Loan loan, final Money amount, final LocalDate waiveDate,
|
||||
final Money waived, final Money unrecognizedPortion, final ExternalId externalId) {
|
||||
LoanTransaction loanTransaction = new LoanTransaction(loan, office, LoanTransactionType.WAIVE_INTEREST, amount.getAmount(),
|
||||
waiveDate, externalId);
|
||||
loanTransaction.updateInterestComponent(waived, unrecognizedPortion);
|
||||
return loanTransaction;
|
||||
}
|
||||
|
||||
public static LoanTransaction accrueInterest(final Office office, final Loan loan, final Money amount,
|
||||
final LocalDate interestAppliedDate, final ExternalId externalId) {
|
||||
BigDecimal principalPortion = null;
|
||||
BigDecimal feesPortion = null;
|
||||
BigDecimal penaltiesPortion = null;
|
||||
BigDecimal interestPortion = amount.getAmount();
|
||||
BigDecimal overPaymentPortion = null;
|
||||
boolean reversed = false;
|
||||
PaymentDetail paymentDetail = null;
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL.getValue(), interestAppliedDate, interestPortion,
|
||||
principalPortion, interestPortion, feesPortion, penaltiesPortion, overPaymentPortion, reversed, paymentDetail, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction accrual(final Loan loan, final Office office, final Money amount, final Money interest,
|
||||
final Money feeCharges, final Money penaltyCharges, final LocalDate transactionDate, final ExternalId externalId) {
|
||||
return accrueTransaction(loan, office, transactionDate, amount.getAmount(), interest.getAmount(), feeCharges.getAmount(),
|
||||
penaltyCharges.getAmount(), externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction accrueTransaction(final Loan loan, final Office office, final LocalDate dateOf, final BigDecimal amount,
|
||||
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion,
|
||||
final ExternalId externalId) {
|
||||
BigDecimal principalPortion = null;
|
||||
BigDecimal overPaymentPortion = null;
|
||||
boolean reversed = false;
|
||||
PaymentDetail paymentDetail = null;
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL.getValue(), dateOf, amount, principalPortion, interestPortion,
|
||||
feeChargesPortion, penaltyChargesPortion, overPaymentPortion, reversed, paymentDetail, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction initiateTransfer(final Office office, final Loan loan, final LocalDate transferDate,
|
||||
final ExternalId externalId) {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.INITIATE_TRANSFER.getValue(), transferDate,
|
||||
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(),
|
||||
loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(),
|
||||
loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction approveTransfer(final Office office, final Loan loan, final LocalDate transferDate,
|
||||
final ExternalId externalId) {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate,
|
||||
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(),
|
||||
loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(),
|
||||
loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate,
|
||||
final ExternalId externalId) {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate,
|
||||
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(),
|
||||
loan.getSummary().getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(),
|
||||
loan.getSummary().getTotalPenaltyChargesOutstanding(), null, false, null, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate paymentDate, final ExternalId externalId) {
|
||||
return new LoanTransaction(null, office, LoanTransactionType.REFUND, paymentDetail, amount.getAmount(), paymentDate, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction copyTransactionProperties(final LoanTransaction loanTransaction) {
|
||||
return new LoanTransaction(loanTransaction.loan, loanTransaction.office, loanTransaction.typeOf, loanTransaction.dateOf,
|
||||
loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion,
|
||||
loanTransaction.feeChargesPortion, loanTransaction.penaltyChargesPortion, loanTransaction.overPaymentPortion,
|
||||
loanTransaction.reversed, loanTransaction.paymentDetail, loanTransaction.externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction accrueLoanCharge(final Loan loan, final Office office, final Money amount, final LocalDate applyDate,
|
||||
final Money feeCharges, final Money penaltyCharges, final ExternalId externalId) {
|
||||
final LoanTransaction applyCharge = new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL, amount.getAmount(), applyDate,
|
||||
externalId);
|
||||
applyCharge.updateChargesComponents(feeCharges, penaltyCharges);
|
||||
return applyCharge;
|
||||
}
|
||||
|
||||
public static LoanTransaction creditBalanceRefund(final Loan loan, final Office office, final Money amount, final LocalDate paymentDate,
|
||||
final ExternalId externalId, PaymentDetail paymentDetail) {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.CREDIT_BALANCE_REFUND.getValue(), paymentDate, amount.getAmount(),
|
||||
null, null, null, null, amount.getAmount(), false, paymentDetail, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction refundForActiveLoan(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate paymentDate, final ExternalId externalId) {
|
||||
return new LoanTransaction(null, office, LoanTransactionType.REFUND_FOR_ACTIVE_LOAN, paymentDetail, amount.getAmount(), paymentDate,
|
||||
externalId);
|
||||
}
|
||||
|
||||
public static boolean transactionAmountsMatch(final MonetaryCurrency currency, final LoanTransaction loanTransaction,
|
||||
final LoanTransaction newLoanTransaction) {
|
||||
return loanTransaction.getAmount(currency).isEqualTo(newLoanTransaction.getAmount(currency))
|
||||
&& loanTransaction.getPrincipalPortion(currency).isEqualTo(newLoanTransaction.getPrincipalPortion(currency))
|
||||
&& loanTransaction.getInterestPortion(currency).isEqualTo(newLoanTransaction.getInterestPortion(currency))
|
||||
&& loanTransaction.getFeeChargesPortion(currency).isEqualTo(newLoanTransaction.getFeeChargesPortion(currency))
|
||||
&& loanTransaction.getPenaltyChargesPortion(currency).isEqualTo(newLoanTransaction.getPenaltyChargesPortion(currency))
|
||||
&& loanTransaction.getOverPaymentPortion(currency).isEqualTo(newLoanTransaction.getOverPaymentPortion(currency));
|
||||
}
|
||||
|
||||
private LoanTransaction(final Loan loan, final Office office, final Integer typeOf, final LocalDate dateOf, final BigDecimal amount,
|
||||
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final BigDecimal overPaymentPortion, final boolean reversed,
|
||||
final PaymentDetail paymentDetail, final ExternalId externalId) {
|
||||
|
||||
this.loan = loan;
|
||||
this.typeOf = typeOf;
|
||||
this.dateOf = dateOf;
|
||||
this.amount = amount;
|
||||
this.principalPortion = principalPortion;
|
||||
this.interestPortion = interestPortion;
|
||||
this.feeChargesPortion = feeChargesPortion;
|
||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||
this.overPaymentPortion = overPaymentPortion;
|
||||
this.reversed = reversed;
|
||||
this.paymentDetail = paymentDetail;
|
||||
this.office = office;
|
||||
this.externalId = externalId;
|
||||
this.submittedOnDate = DateUtils.getBusinessLocalDate();
|
||||
}
|
||||
|
||||
public static LoanTransaction waiveLoanCharge(final Loan loan, final Office office, final Money waived, final LocalDate waiveDate,
|
||||
final Money feeChargesWaived, final Money penaltyChargesWaived, final Money unrecognizedCharge, final ExternalId externalId) {
|
||||
final LoanTransaction waiver = new LoanTransaction(loan, office, LoanTransactionType.WAIVE_CHARGES, waived.getAmount(), waiveDate,
|
||||
externalId);
|
||||
waiver.updateChargesComponents(feeChargesWaived, penaltyChargesWaived, unrecognizedCharge);
|
||||
|
||||
return waiver;
|
||||
}
|
||||
|
||||
public static LoanTransaction writeoff(final Loan loan, final Office office, final LocalDate writeOffDate,
|
||||
final ExternalId externalId) {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.WRITEOFF, null, writeOffDate, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction chargeOff(final Loan loan, final LocalDate chargeOffDate, final ExternalId externalId) {
|
||||
BigDecimal principalPortion = loan.getLoanSummary().getTotalPrincipalOutstanding().compareTo(BigDecimal.ZERO) != 0
|
||||
? loan.getLoanSummary().getTotalPrincipalOutstanding()
|
||||
: null;
|
||||
BigDecimal interestPortion = loan.getLoanSummary().getTotalInterestOutstanding().compareTo(BigDecimal.ZERO) != 0
|
||||
? loan.getLoanSummary().getTotalInterestOutstanding()
|
||||
: null;
|
||||
BigDecimal feePortion = loan.getLoanSummary().getTotalFeeChargesOutstanding().compareTo(BigDecimal.ZERO) != 0
|
||||
? loan.getLoanSummary().getTotalFeeChargesOutstanding()
|
||||
: null;
|
||||
BigDecimal penaltyPortion = loan.getLoanSummary().getTotalPenaltyChargesOutstanding().compareTo(BigDecimal.ZERO) != 0
|
||||
? loan.getLoanSummary().getTotalPenaltyChargesOutstanding()
|
||||
: null;
|
||||
BigDecimal totalOutstanding = loan.getLoanSummary().getTotalOutstanding();
|
||||
|
||||
return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.CHARGE_OFF.getValue(), chargeOffDate, totalOutstanding,
|
||||
principalPortion, interestPortion, feePortion, penaltyPortion, null, false, null, externalId);
|
||||
}
|
||||
|
||||
private LoanTransaction(final Loan loan, final Office office, final LoanTransactionType type, final BigDecimal amount,
|
||||
final LocalDate date, final ExternalId externalId) {
|
||||
this.loan = loan;
|
||||
this.typeOf = type.getValue();
|
||||
this.amount = amount;
|
||||
this.dateOf = date;
|
||||
this.externalId = externalId;
|
||||
this.office = office;
|
||||
this.submittedOnDate = DateUtils.getBusinessLocalDate();
|
||||
}
|
||||
|
||||
private LoanTransaction(final Loan loan, final Office office, final LoanTransactionType type, final PaymentDetail paymentDetail,
|
||||
final BigDecimal amount, final LocalDate date, final ExternalId externalId) {
|
||||
this.loan = loan;
|
||||
this.typeOf = type.getValue();
|
||||
this.paymentDetail = paymentDetail;
|
||||
this.amount = amount;
|
||||
this.dateOf = date;
|
||||
this.externalId = externalId;
|
||||
this.office = office;
|
||||
this.submittedOnDate = DateUtils.getBusinessLocalDate();
|
||||
}
|
||||
|
||||
private LoanTransaction(final Loan loan, final Office office, final LoanTransactionType type, final PaymentDetail paymentDetail,
|
||||
final BigDecimal amount, final LocalDate date, final ExternalId externalId, final String chargeRefundChargeType) {
|
||||
this.loan = loan;
|
||||
this.typeOf = type.getValue();
|
||||
this.paymentDetail = paymentDetail;
|
||||
this.amount = amount;
|
||||
this.dateOf = date;
|
||||
this.externalId = externalId;
|
||||
this.office = office;
|
||||
this.submittedOnDate = DateUtils.getBusinessLocalDate();
|
||||
this.chargeRefundChargeType = chargeRefundChargeType;
|
||||
}
|
||||
|
||||
public void reverse() {
|
||||
this.loan.validateRepaymentTypeTransactionNotBeforeAChargeRefund(this, "reversed");
|
||||
this.reversed = true;
|
||||
this.reversedOnDate = DateUtils.getBusinessLocalDate();
|
||||
this.loanTransactionToRepaymentScheduleMappings.clear();
|
||||
}
|
||||
|
||||
public void reverse(final ExternalId reversalExternalId) {
|
||||
this.reverse();
|
||||
this.reversalExternalId = reversalExternalId;
|
||||
}
|
||||
|
||||
public void resetDerivedComponents() {
|
||||
this.principalPortion = null;
|
||||
this.interestPortion = null;
|
||||
this.feeChargesPortion = null;
|
||||
this.penaltyChargesPortion = null;
|
||||
this.overPaymentPortion = null;
|
||||
this.outstandingLoanBalance = null;
|
||||
}
|
||||
|
||||
public void updateLoan(final Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates the derived fields of a loan transaction for the principal, interest and interest waived portions.
|
||||
*
|
||||
* This accumulates the values passed to the already existent values for each of the portions.
|
||||
*
|
||||
* @param principal
|
||||
* principal
|
||||
* @param interest
|
||||
* interest
|
||||
* @param feeCharges
|
||||
* feeCharges
|
||||
* @param penaltyCharges
|
||||
* penaltyCharges
|
||||
*/
|
||||
public void updateComponents(final Money principal, final Money interest, final Money feeCharges, final Money penaltyCharges) {
|
||||
final MonetaryCurrency currency = principal.getCurrency();
|
||||
this.principalPortion = defaultToNullIfZero(getPrincipalPortion(currency).plus(principal).getAmount());
|
||||
this.interestPortion = defaultToNullIfZero(getInterestPortion(currency).plus(interest).getAmount());
|
||||
updateChargesComponents(feeCharges, penaltyCharges);
|
||||
}
|
||||
|
||||
public void updateChargesComponents(final Money feeCharges, final Money penaltyCharges) {
|
||||
final MonetaryCurrency currency = feeCharges.getCurrency();
|
||||
this.feeChargesPortion = defaultToNullIfZero(getFeeChargesPortion(currency).plus(feeCharges).getAmount());
|
||||
this.penaltyChargesPortion = defaultToNullIfZero(getPenaltyChargesPortion(currency).plus(penaltyCharges).getAmount());
|
||||
}
|
||||
|
||||
private void updateChargesComponents(final Money feeCharges, final Money penaltyCharges, final Money unrecognizedCharges) {
|
||||
final MonetaryCurrency currency = feeCharges.getCurrency();
|
||||
this.feeChargesPortion = defaultToNullIfZero(getFeeChargesPortion(currency).plus(feeCharges).getAmount());
|
||||
this.penaltyChargesPortion = defaultToNullIfZero(getPenaltyChargesPortion(currency).plus(penaltyCharges).getAmount());
|
||||
this.unrecognizedIncomePortion = defaultToNullIfZero(getUnrecognizedIncomePortion(currency).plus(unrecognizedCharges).getAmount());
|
||||
}
|
||||
|
||||
private void updateInterestComponent(final Money interest, final Money unrecognizedInterest) {
|
||||
final MonetaryCurrency currency = interest.getCurrency();
|
||||
this.interestPortion = defaultToNullIfZero(getInterestPortion(currency).plus(interest).getAmount());
|
||||
this.unrecognizedIncomePortion = defaultToNullIfZero(getUnrecognizedIncomePortion(currency).plus(unrecognizedInterest).getAmount());
|
||||
}
|
||||
|
||||
public void adjustInterestComponent(final MonetaryCurrency currency) {
|
||||
this.interestPortion = defaultToNullIfZero(getInterestPortion(currency).minus(getUnrecognizedIncomePortion(currency)).getAmount());
|
||||
}
|
||||
|
||||
public void updateComponentsAndTotal(final Money principal, final Money interest, final Money feeCharges, final Money penaltyCharges) {
|
||||
updateComponents(principal, interest, feeCharges, penaltyCharges);
|
||||
|
||||
final MonetaryCurrency currency = principal.getCurrency();
|
||||
this.amount = getPrincipalPortion(currency).plus(getInterestPortion(currency)).plus(getFeeChargesPortion(currency))
|
||||
.plus(getPenaltyChargesPortion(currency)).getAmount();
|
||||
}
|
||||
|
||||
public void updateOverPayments(final Money overPayment) {
|
||||
final MonetaryCurrency currency = overPayment.getCurrency();
|
||||
this.overPaymentPortion = defaultToNullIfZero(getOverPaymentPortion(currency).plus(overPayment).getAmount());
|
||||
}
|
||||
|
||||
public void setOverPayments(final Money overPayment) {
|
||||
if (overPayment != null) {
|
||||
this.overPaymentPortion = defaultToNullIfZero(overPayment.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
public Money getPrincipalPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalPortion);
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalPortion() {
|
||||
return this.principalPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestPortion() {
|
||||
return this.interestPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesPortion() {
|
||||
return this.penaltyChargesPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesPortion() {
|
||||
return this.feeChargesPortion;
|
||||
}
|
||||
|
||||
public Money getInterestPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestPortion);
|
||||
}
|
||||
|
||||
public Money getUnrecognizedIncomePortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.unrecognizedIncomePortion);
|
||||
}
|
||||
|
||||
public Money getFeeChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesPortion);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesPortion);
|
||||
}
|
||||
|
||||
public Money getOverPaymentPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.overPaymentPortion);
|
||||
}
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return this.dateOf;
|
||||
}
|
||||
|
||||
public LocalDate getDateOf() {
|
||||
return this.dateOf;
|
||||
}
|
||||
|
||||
public LoanTransactionType getTypeOf() {
|
||||
return LoanTransactionType.fromInt(this.typeOf);
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
public boolean isNotReversed() {
|
||||
return !isReversed();
|
||||
}
|
||||
|
||||
public void setReversed() {
|
||||
this.reversed = true;
|
||||
}
|
||||
|
||||
public void setManuallyAdjustedOrReversed() {
|
||||
this.manuallyAdjustedOrReversed = true;
|
||||
}
|
||||
|
||||
public boolean isRepaymentLikeType() {
|
||||
return isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit() || isChargeRefund()
|
||||
|| isChargeAdjustment();
|
||||
}
|
||||
|
||||
public boolean isTypeAllowedForChargeback() {
|
||||
return isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit();
|
||||
}
|
||||
|
||||
public boolean isRepayment() {
|
||||
return LoanTransactionType.REPAYMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isMerchantIssuedRefund() {
|
||||
return LoanTransactionType.MERCHANT_ISSUED_REFUND.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isPayoutRefund() {
|
||||
return LoanTransactionType.PAYOUT_REFUND.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isGoodwillCredit() {
|
||||
return LoanTransactionType.GOODWILL_CREDIT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isChargeRefund() {
|
||||
return LoanTransactionType.CHARGE_REFUND.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isChargeAdjustment() {
|
||||
return LoanTransactionType.CHARGE_ADJUSTMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isNotRepaymentLikeType() {
|
||||
return !isRepaymentLikeType();
|
||||
}
|
||||
|
||||
public boolean isIncomePosting() {
|
||||
return LoanTransactionType.INCOME_POSTING.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isNotIncomePosting() {
|
||||
return !isIncomePosting();
|
||||
}
|
||||
|
||||
public boolean isDisbursement() {
|
||||
return LoanTransactionType.DISBURSEMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isRepaymentAtDisbursement() {
|
||||
return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isNotRecoveryRepayment() {
|
||||
return !isRecoveryRepayment();
|
||||
}
|
||||
|
||||
public boolean isRecoveryRepayment() {
|
||||
return LoanTransactionType.RECOVERY_REPAYMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isInterestWaiver() {
|
||||
return LoanTransactionType.WAIVE_INTEREST.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isChargesWaiver() {
|
||||
return LoanTransactionType.WAIVE_CHARGES.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isNotInterestWaiver() {
|
||||
return !isInterestWaiver();
|
||||
}
|
||||
|
||||
public boolean isWaiver() {
|
||||
return isInterestWaiver() || isChargesWaiver();
|
||||
}
|
||||
|
||||
public boolean isNotWaiver() {
|
||||
return !isInterestWaiver() && !isChargesWaiver();
|
||||
}
|
||||
|
||||
public boolean isNotCreditBalanceRefund() {
|
||||
return !isCreditBalanceRefund();
|
||||
}
|
||||
|
||||
public boolean isChargePayment() {
|
||||
return getTypeOf().isChargePayment() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isChargeback() {
|
||||
return getTypeOf().isChargeback() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isEditable() {
|
||||
return !(isChargeback() || isGoodwillCredit() || isPayoutRefund() || isMerchantIssuedRefund());
|
||||
}
|
||||
|
||||
public boolean isPenaltyPayment() {
|
||||
boolean isPenalty = false;
|
||||
if (isChargePayment()) {
|
||||
for (final LoanChargePaidBy chargePaidBy : this.loanChargesPaid) {
|
||||
isPenalty = chargePaidBy.getLoanCharge().isPenaltyCharge();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isPenalty;
|
||||
}
|
||||
|
||||
public boolean isWriteOff() {
|
||||
return getTypeOf().isWriteOff() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isChargeOff() {
|
||||
return getTypeOf().isChargeOff() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isIdentifiedBy(final Long identifier) {
|
||||
return getId().equals(identifier);
|
||||
}
|
||||
|
||||
public boolean isBelongingToLoanOf(final Loan check) {
|
||||
return this.loan.getId().equals(check.getId());
|
||||
}
|
||||
|
||||
public boolean isNotBelongingToLoanOf(final Loan check) {
|
||||
return !isBelongingToLoanOf(check);
|
||||
}
|
||||
|
||||
public boolean isNonZero() {
|
||||
return this.amount.subtract(BigDecimal.ZERO).doubleValue() > 0;
|
||||
}
|
||||
|
||||
public boolean isGreaterThan(final Money monetaryAmount) {
|
||||
return getAmount(monetaryAmount.getCurrency()).isGreaterThan(monetaryAmount);
|
||||
}
|
||||
|
||||
public boolean isGreaterThanZero(final MonetaryCurrency currency) {
|
||||
return getAmount(currency).isGreaterThanZero();
|
||||
}
|
||||
|
||||
public boolean isGreaterThanZeroAndLessThanOrEqualTo(BigDecimal totalOverpaid) {
|
||||
return isNonZero() && this.amount.compareTo(totalOverpaid) <= 0;
|
||||
}
|
||||
|
||||
public boolean isNotZero(final MonetaryCurrency currency) {
|
||||
return !getAmount(currency).isZero();
|
||||
}
|
||||
|
||||
private BigDecimal defaultToNullIfZero(final BigDecimal value) {
|
||||
BigDecimal result = value;
|
||||
if (BigDecimal.ZERO.compareTo(value) == 0) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public LoanTransactionData toData(final CurrencyData currencyData, final AccountTransferData transfer) {
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf);
|
||||
PaymentDetailData paymentDetailData = null;
|
||||
if (this.paymentDetail != null) {
|
||||
paymentDetailData = this.paymentDetail.toData();
|
||||
}
|
||||
return new LoanTransactionData(getId(), this.office.getId(), this.office.getName(), transactionType, paymentDetailData,
|
||||
currencyData, getTransactionDate(), this.amount, this.loan.getNetDisbursalAmount(), this.principalPortion,
|
||||
this.interestPortion, this.feeChargesPortion, this.penaltyChargesPortion, this.overPaymentPortion, this.externalId,
|
||||
transfer, null, outstandingLoanBalance, this.unrecognizedIncomePortion, this.manuallyAdjustedOrReversed, this.loan.getId(),
|
||||
this.loan.getExternalId());
|
||||
}
|
||||
|
||||
public Map<String, Object> toMapData(final String currencyCode) {
|
||||
final Map<String, Object> thisTransactionData = new LinkedHashMap<>();
|
||||
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf);
|
||||
|
||||
thisTransactionData.put("id", getId());
|
||||
thisTransactionData.put("officeId", this.office.getId());
|
||||
thisTransactionData.put("type", transactionType);
|
||||
thisTransactionData.put("reversed", Boolean.valueOf(isReversed()));
|
||||
thisTransactionData.put("date", getTransactionDate());
|
||||
thisTransactionData.put("currencyCode", currencyCode);
|
||||
thisTransactionData.put("amount", this.amount);
|
||||
thisTransactionData.put("netDisbursalAmount", this.loan.getNetDisbursalAmount());
|
||||
thisTransactionData.put("principalPortion", this.principalPortion);
|
||||
thisTransactionData.put("interestPortion", this.interestPortion);
|
||||
thisTransactionData.put("feeChargesPortion", this.feeChargesPortion);
|
||||
thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion);
|
||||
thisTransactionData.put("overPaymentPortion", this.overPaymentPortion);
|
||||
if (transactionType.isChargeRefund()) {
|
||||
thisTransactionData.put("chargeRefundChargeType", this.chargeRefundChargeType);
|
||||
}
|
||||
|
||||
if (this.paymentDetail != null) {
|
||||
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
|
||||
}
|
||||
|
||||
if (!this.loanChargesPaid.isEmpty()) {
|
||||
final List<Map<String, Object>> loanChargesPaidData = new ArrayList<>();
|
||||
for (final LoanChargePaidBy chargePaidBy : this.loanChargesPaid) {
|
||||
final Map<String, Object> loanChargePaidData = new LinkedHashMap<>();
|
||||
loanChargePaidData.put("chargeId", chargePaidBy.getLoanCharge().getCharge().getId());
|
||||
loanChargePaidData.put("isPenalty", chargePaidBy.getLoanCharge().isPenaltyCharge());
|
||||
loanChargePaidData.put("loanChargeId", chargePaidBy.getLoanCharge().getId());
|
||||
loanChargePaidData.put("amount", chargePaidBy.getAmount());
|
||||
|
||||
loanChargesPaidData.add(loanChargePaidData);
|
||||
}
|
||||
thisTransactionData.put("loanChargesPaid", loanChargesPaidData);
|
||||
}
|
||||
|
||||
LoanTransactionRelation loanTransactionRelation = loanTransactionRelations.stream()
|
||||
.filter(e -> LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT.equals(e.getRelationType())).findAny().orElse(null);
|
||||
if (loanTransactionRelation != null) {
|
||||
LoanCharge loanCharge = loanTransactionRelation.getToCharge();
|
||||
thisTransactionData.put("loanChargeData", loanCharge.toData());
|
||||
}
|
||||
|
||||
return thisTransactionData;
|
||||
}
|
||||
|
||||
public Loan getLoan() {
|
||||
return this.loan;
|
||||
}
|
||||
|
||||
public Set<LoanChargePaidBy> getLoanChargesPaid() {
|
||||
return this.loanChargesPaid;
|
||||
}
|
||||
|
||||
public void setLoanChargesPaid(final Set<LoanChargePaidBy> loanChargesPaid) {
|
||||
this.loanChargesPaid = loanChargesPaid;
|
||||
}
|
||||
|
||||
public ExternalId getExternalId() {
|
||||
return this.externalId;
|
||||
}
|
||||
|
||||
public boolean isRefund() {
|
||||
return LoanTransactionType.REFUND.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isCreditBalanceRefund() {
|
||||
return LoanTransactionType.CREDIT_BALANCE_REFUND.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public void updateExternalId(final ExternalId externalId) {
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
public boolean isAccrual() {
|
||||
return LoanTransactionType.ACCRUAL.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isNonMonetaryTransaction() {
|
||||
return isNotReversed() && (LoanTransactionType.CONTRA.equals(getTypeOf())
|
||||
|| LoanTransactionType.MARKED_FOR_RESCHEDULING.equals(getTypeOf())
|
||||
|| LoanTransactionType.APPROVE_TRANSFER.equals(getTypeOf()) || LoanTransactionType.INITIATE_TRANSFER.equals(getTypeOf())
|
||||
|| LoanTransactionType.REJECT_TRANSFER.equals(getTypeOf()) || LoanTransactionType.WITHDRAW_TRANSFER.equals(getTypeOf())
|
||||
|| LoanTransactionType.CHARGE_OFF.equals(getTypeOf()));
|
||||
}
|
||||
|
||||
public void updateOutstandingLoanBalance(BigDecimal outstandingLoanBalance) {
|
||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||
}
|
||||
|
||||
public boolean isNotRefundForActiveLoan() {
|
||||
// TODO Auto-generated method stub
|
||||
return !isRefundForActiveLoan();
|
||||
}
|
||||
|
||||
public boolean isRefundForActiveLoan() {
|
||||
return LoanTransactionType.REFUND_FOR_ACTIVE_LOAN.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isManuallyAdjustedOrReversed() {
|
||||
return this.manuallyAdjustedOrReversed;
|
||||
}
|
||||
|
||||
public boolean isNotManuallyAdjustedOrReversed() {
|
||||
return !this.manuallyAdjustedOrReversed;
|
||||
}
|
||||
|
||||
public void manuallyAdjustedOrReversed() {
|
||||
this.manuallyAdjustedOrReversed = true;
|
||||
}
|
||||
|
||||
public OffsetDateTime getCreatedDateTime() {
|
||||
return (this.getCreatedDate().isPresent() ? this.getCreatedDate().get() : DateUtils.getOffsetDateTimeOfTenant());
|
||||
}
|
||||
|
||||
public boolean isLastTransaction(final LoanTransaction loanTransaction) {
|
||||
boolean isLatest = false;
|
||||
if (loanTransaction != null) {
|
||||
isLatest = this.getTransactionDate().isBefore(loanTransaction.getTransactionDate())
|
||||
|| (this.getTransactionDate().isEqual(loanTransaction.getTransactionDate())
|
||||
&& this.getCreatedDateTime().isBefore(loanTransaction.getCreatedDateTime()));
|
||||
}
|
||||
return isLatest;
|
||||
}
|
||||
|
||||
public boolean isLatestTransaction(final LoanTransaction loanTransaction) {
|
||||
boolean isLatest = false;
|
||||
if (loanTransaction != null) {
|
||||
isLatest = this.getCreatedDateTime().isBefore(loanTransaction.getCreatedDateTime());
|
||||
}
|
||||
return isLatest;
|
||||
}
|
||||
|
||||
public void updateLoanTransactionToRepaymentScheduleMappings(final Collection<LoanTransactionToRepaymentScheduleMapping> mappings) {
|
||||
Collection<LoanTransactionToRepaymentScheduleMapping> retainMappings = new ArrayList<>();
|
||||
for (LoanTransactionToRepaymentScheduleMapping updatedrepaymentScheduleMapping : mappings) {
|
||||
updateMapingDetail(retainMappings, updatedrepaymentScheduleMapping);
|
||||
}
|
||||
this.loanTransactionToRepaymentScheduleMappings.retainAll(retainMappings);
|
||||
}
|
||||
|
||||
private boolean updateMapingDetail(final Collection<LoanTransactionToRepaymentScheduleMapping> retainMappings,
|
||||
final LoanTransactionToRepaymentScheduleMapping updatedrepaymentScheduleMapping) {
|
||||
boolean isMappingUpdated = false;
|
||||
for (LoanTransactionToRepaymentScheduleMapping repaymentScheduleMapping : this.loanTransactionToRepaymentScheduleMappings) {
|
||||
if (updatedrepaymentScheduleMapping.getLoanRepaymentScheduleInstallment().getId() != null
|
||||
&& repaymentScheduleMapping.getLoanRepaymentScheduleInstallment().getDueDate()
|
||||
.equals(updatedrepaymentScheduleMapping.getLoanRepaymentScheduleInstallment().getDueDate())) {
|
||||
repaymentScheduleMapping.setComponents(updatedrepaymentScheduleMapping.getPrincipalPortion(),
|
||||
updatedrepaymentScheduleMapping.getInterestPortion(), updatedrepaymentScheduleMapping.getFeeChargesPortion(),
|
||||
updatedrepaymentScheduleMapping.getPenaltyChargesPortion());
|
||||
isMappingUpdated = true;
|
||||
retainMappings.add(repaymentScheduleMapping);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isMappingUpdated) {
|
||||
updatedrepaymentScheduleMapping.setLoanTransaction(this);
|
||||
this.loanTransactionToRepaymentScheduleMappings.add(updatedrepaymentScheduleMapping);
|
||||
retainMappings.add(updatedrepaymentScheduleMapping);
|
||||
}
|
||||
return isMappingUpdated;
|
||||
}
|
||||
|
||||
public Set<LoanTransactionToRepaymentScheduleMapping> getLoanTransactionToRepaymentScheduleMappings() {
|
||||
return this.loanTransactionToRepaymentScheduleMappings;
|
||||
}
|
||||
|
||||
public Boolean isAllowTypeTransactionAtTheTimeOfLastUndo() {
|
||||
return isDisbursement() || isAccrual() || isRepaymentAtDisbursement();
|
||||
}
|
||||
|
||||
public boolean isAccrualTransaction() {
|
||||
return isAccrual();
|
||||
}
|
||||
|
||||
public BigDecimal getOutstandingLoanBalance() {
|
||||
return outstandingLoanBalance;
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
public boolean isPaymentTransaction() {
|
||||
return this.isNotReversed() && !(this.isDisbursement() || this.isAccrual() || this.isRepaymentAtDisbursement()
|
||||
|| this.isNonMonetaryTransaction() || this.isIncomePosting());
|
||||
}
|
||||
|
||||
public Set<LoanCollateralManagement> getLoanCollateralManagementSet() {
|
||||
return this.loanCollateralManagementSet;
|
||||
}
|
||||
|
||||
public LocalDate getSubmittedOnDate() {
|
||||
return submittedOnDate;
|
||||
}
|
||||
|
||||
public boolean hasLoanTransactionRelations() {
|
||||
return (loanTransactionRelations != null && loanTransactionRelations.size() > 0);
|
||||
}
|
||||
|
||||
public boolean hasChargebackLoanTransactionRelations() {
|
||||
return (loanTransactionRelations != null
|
||||
&& loanTransactionRelations.stream().anyMatch(e -> LoanTransactionRelationTypeEnum.CHARGEBACK.equals(e.getRelationType())));
|
||||
}
|
||||
|
||||
public Set<LoanTransactionRelation> getLoanTransactionRelations() {
|
||||
return loanTransactionRelations;
|
||||
}
|
||||
|
||||
public void copyLoanTransactionRelations(Set<LoanTransactionRelation> sourceLoanTransactionRelations) {
|
||||
for (LoanTransactionRelation existingLoanTransactionRelation : sourceLoanTransactionRelations) {
|
||||
loanTransactionRelations.add(new LoanTransactionRelation(this, existingLoanTransactionRelation.getToTransaction(),
|
||||
existingLoanTransactionRelation.getToCharge(), existingLoanTransactionRelation.getRelationType()));
|
||||
}
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
// TODO missing hashCode(), equals(Object obj), but probably OK as long as
|
||||
// this is never stored in a Collection.
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Sort loan transactions by transaction date, created date and transaction type placing
|
||||
*/
|
||||
public class LoanTransactionComparator implements Comparator<LoanTransaction> {
|
||||
|
||||
@Override
|
||||
public int compare(final LoanTransaction o1, final LoanTransaction o2) {
|
||||
int compareResult = 0;
|
||||
final int comparsion = o1.getTransactionDate().compareTo(o2.getTransactionDate());
|
||||
/**
|
||||
* For transactions bearing the same transaction date, we sort transactions based on created date (when
|
||||
* available) after which sorting for waivers takes place
|
||||
**/
|
||||
if (comparsion == 0) {
|
||||
int comparisonBasedOnCreatedDate = 0;
|
||||
if (o1.isIncomePosting() && o2.isNotIncomePosting()) {
|
||||
compareResult = -1;
|
||||
} else if (o1.isNotIncomePosting() && o2.isIncomePosting()) {
|
||||
compareResult = 1;
|
||||
} else {
|
||||
compareResult = 0;
|
||||
}
|
||||
if (o1.getCreatedDateTime() != null && o2.getCreatedDateTime() != null) {
|
||||
comparisonBasedOnCreatedDate = o1.getCreatedDateTime().compareTo(o2.getCreatedDateTime());
|
||||
}
|
||||
// equal transaction dates
|
||||
if (comparisonBasedOnCreatedDate == 0) {
|
||||
if (o1.isWaiver() && o2.isNotWaiver()) {
|
||||
compareResult = -1;
|
||||
} else if (o1.isNotWaiver() && o2.isWaiver()) {
|
||||
compareResult = 1;
|
||||
} else {
|
||||
compareResult = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
compareResult = comparsion;
|
||||
}
|
||||
|
||||
return compareResult;
|
||||
}
|
||||
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
|
||||
@Getter
|
||||
@Entity
|
||||
@Table(name = "m_loan_transaction_relation")
|
||||
public class LoanTransactionRelation extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "from_loan_transaction_id", nullable = false)
|
||||
private LoanTransaction fromTransaction;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "to_loan_transaction_id")
|
||||
private LoanTransaction toTransaction;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "to_loan_charge_id")
|
||||
private LoanCharge toCharge;
|
||||
|
||||
@Enumerated(EnumType.ORDINAL)
|
||||
@Column(name = "relation_type_enum", nullable = false)
|
||||
private LoanTransactionRelationTypeEnum relationType;
|
||||
|
||||
protected LoanTransactionRelation() {}
|
||||
|
||||
protected LoanTransactionRelation(@NotNull LoanTransaction fromTransaction, LoanTransaction toTransaction, LoanCharge toCharge,
|
||||
LoanTransactionRelationTypeEnum relationType) {
|
||||
this.fromTransaction = fromTransaction;
|
||||
this.toTransaction = toTransaction;
|
||||
this.toCharge = toCharge;
|
||||
this.relationType = relationType;
|
||||
}
|
||||
|
||||
public static LoanTransactionRelation linkToTransaction(@NotNull LoanTransaction fromTransaction,
|
||||
@NotNull LoanTransaction toTransaction, LoanTransactionRelationTypeEnum relation) {
|
||||
return new LoanTransactionRelation(fromTransaction, toTransaction, null, relation);
|
||||
}
|
||||
|
||||
public static LoanTransactionRelation linkToCharge(@NotNull LoanTransaction fromTransaction, @NotNull LoanCharge loanCharge,
|
||||
LoanTransactionRelationTypeEnum relation) {
|
||||
return new LoanTransactionRelation(fromTransaction, null, loanCharge, relation);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
public enum LoanTransactionRelationTypeEnum {
|
||||
|
||||
INVALID(0, "loanTransactionType.invalid"), //
|
||||
CHARGEBACK(1, "loanTransactionRelationType.chargeback"), //
|
||||
CHARGE_ADJUSTMENT(2, "loanTransactionRelationType.chargeAdjustment"), //
|
||||
REPLAYED(3, "loanTransactionRelationType.replayed");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
LoanTransactionRelationTypeEnum(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static LoanTransactionRelationTypeEnum fromInt(final Integer transactionType) {
|
||||
|
||||
if (transactionType == null) {
|
||||
return LoanTransactionRelationTypeEnum.INVALID;
|
||||
}
|
||||
|
||||
return switch (transactionType) {
|
||||
case 1 -> LoanTransactionRelationTypeEnum.CHARGEBACK;
|
||||
case 2 -> LoanTransactionRelationTypeEnum.CHARGE_ADJUSTMENT;
|
||||
case 3 -> LoanTransactionRelationTypeEnum.REPLAYED;
|
||||
default -> LoanTransactionRelationTypeEnum.INVALID;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_transaction_repayment_schedule_mapping")
|
||||
public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
||||
@JoinColumn(name = "loan_transaction_id", nullable = false)
|
||||
private LoanTransaction loanTransaction;
|
||||
|
||||
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
||||
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
|
||||
private LoanRepaymentScheduleInstallment installment;
|
||||
|
||||
@Column(name = "principal_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal principalPortion;
|
||||
|
||||
@Column(name = "interest_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestPortion;
|
||||
|
||||
@Column(name = "fee_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesPortion;
|
||||
|
||||
@Column(name = "penalty_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesPortion;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19)
|
||||
private BigDecimal amount;
|
||||
|
||||
protected LoanTransactionToRepaymentScheduleMapping() {
|
||||
|
||||
}
|
||||
|
||||
private LoanTransactionToRepaymentScheduleMapping(final LoanTransaction loanTransaction,
|
||||
final LoanRepaymentScheduleInstallment installment, final BigDecimal principalPortion, final BigDecimal interestPortion,
|
||||
final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal amount) {
|
||||
this.loanTransaction = loanTransaction;
|
||||
this.installment = installment;
|
||||
this.principalPortion = principalPortion;
|
||||
this.interestPortion = interestPortion;
|
||||
this.feeChargesPortion = feeChargesPortion;
|
||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public static LoanTransactionToRepaymentScheduleMapping createFrom(final LoanTransaction loanTransaction,
|
||||
final LoanRepaymentScheduleInstallment installment, final Money principalPortion, final Money interestPortion,
|
||||
final Money feeChargesPortion, final Money penaltyChargesPortion) {
|
||||
return new LoanTransactionToRepaymentScheduleMapping(loanTransaction, installment, defaultToNullIfZero(principalPortion),
|
||||
defaultToNullIfZero(interestPortion), defaultToNullIfZero(feeChargesPortion), defaultToNullIfZero(penaltyChargesPortion),
|
||||
defaultToNullIfZero(principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion)));
|
||||
}
|
||||
|
||||
private static BigDecimal defaultToNullIfZero(final Money value) {
|
||||
BigDecimal result = value.getAmount();
|
||||
if (value.isZero()) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private BigDecimal defaultToZeroIfNull(final BigDecimal value) {
|
||||
BigDecimal result = value;
|
||||
if (value == null) {
|
||||
result = BigDecimal.ZERO;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment getLoanRepaymentScheduleInstallment() {
|
||||
return this.installment;
|
||||
}
|
||||
|
||||
public void updateComponents(final Money principal, final Money interest, final Money feeCharges, final Money penaltyCharges) {
|
||||
final MonetaryCurrency currency = principal.getCurrency();
|
||||
this.principalPortion = defaultToNullIfZero(getPrincipalPortion(currency).plus(principal));
|
||||
this.interestPortion = defaultToNullIfZero(getInterestPortion(currency).plus(interest));
|
||||
updateChargesComponents(feeCharges, penaltyCharges);
|
||||
updateAmount();
|
||||
}
|
||||
|
||||
private void updateAmount() {
|
||||
this.amount = defaultToZeroIfNull(getPrincipalPortion()).add(defaultToZeroIfNull(getInterestPortion()))
|
||||
.add(defaultToZeroIfNull(getFeeChargesPortion())).add(defaultToZeroIfNull(getPenaltyChargesPortion()));
|
||||
}
|
||||
|
||||
public void setComponents(final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
|
||||
final BigDecimal penaltyCharges) {
|
||||
this.principalPortion = principal;
|
||||
this.interestPortion = interest;
|
||||
this.feeChargesPortion = feeCharges;
|
||||
this.penaltyChargesPortion = penaltyCharges;
|
||||
updateAmount();
|
||||
}
|
||||
|
||||
private void updateChargesComponents(final Money feeCharges, final Money penaltyCharges) {
|
||||
final MonetaryCurrency currency = feeCharges.getCurrency();
|
||||
this.feeChargesPortion = defaultToNullIfZero(getFeeChargesPortion(currency).plus(feeCharges));
|
||||
this.penaltyChargesPortion = defaultToNullIfZero(getPenaltyChargesPortion(currency).plus(penaltyCharges));
|
||||
}
|
||||
|
||||
public Money getPrincipalPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalPortion);
|
||||
}
|
||||
|
||||
public Money getInterestPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestPortion);
|
||||
}
|
||||
|
||||
public Money getFeeChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesPortion);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesPortion);
|
||||
}
|
||||
|
||||
public LoanTransaction getLoanTransaction() {
|
||||
return loanTransaction;
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalPortion() {
|
||||
return this.principalPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestPortion() {
|
||||
return this.interestPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesPortion() {
|
||||
return this.feeChargesPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesPortion() {
|
||||
return this.penaltyChargesPortion;
|
||||
}
|
||||
|
||||
public void setLoanTransaction(LoanTransaction loanTransaction) {
|
||||
this.loanTransaction = loanTransaction;
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
public enum LoanTransactionType {
|
||||
|
||||
INVALID(0, "loanTransactionType.invalid"), //
|
||||
DISBURSEMENT(1, "loanTransactionType.disbursement"), //
|
||||
REPAYMENT(2, "loanTransactionType.repayment"), //
|
||||
CONTRA(3, "loanTransactionType.contra"), //
|
||||
WAIVE_INTEREST(4, "loanTransactionType.waiver"), //
|
||||
REPAYMENT_AT_DISBURSEMENT(5, "loanTransactionType.repaymentAtDisbursement"), //
|
||||
WRITEOFF(6, "loanTransactionType.writeOff"), //
|
||||
MARKED_FOR_RESCHEDULING(7, "loanTransactionType.marked.for.rescheduling"), //
|
||||
/**
|
||||
* This type of transactions is allowed on written-off loans where mfi still attempts to recover payments from
|
||||
* applicant after writing-off.
|
||||
*/
|
||||
RECOVERY_REPAYMENT(8, "loanTransactionType.recoveryRepayment"), //
|
||||
WAIVE_CHARGES(9, "loanTransactionType.waiveCharges"), //
|
||||
// UNDO_WAIVE_CHARGE(20, "loanTransactionType.undoWaiveCharge"),
|
||||
/**
|
||||
* Transaction represents an Accrual (For either interest, charge or a penalty
|
||||
**/
|
||||
ACCRUAL(10, "loanTransactionType.accrual"), //
|
||||
|
||||
/***
|
||||
* A Loan Transfer involves two steps, first a "initiate" Loan transfer transaction done by the Source branch
|
||||
* followed by a "complete" loan transaction initiated by the destination branch
|
||||
**/
|
||||
INITIATE_TRANSFER(12, "loanTransactionType.initiateTransfer"), //
|
||||
APPROVE_TRANSFER(13, "loanTransactionType.approveTransfer"), //
|
||||
WITHDRAW_TRANSFER(14, "loanTransactionType.withdrawTransfer"), //
|
||||
REJECT_TRANSFER(15, "loanTransactionType.rejectTransfer"), //
|
||||
REFUND(16, "loanTransactionType.refund"), //
|
||||
CHARGE_PAYMENT(17, "loanTransactionType.chargePayment"), //
|
||||
REFUND_FOR_ACTIVE_LOAN(18, "loanTransactionType.refund"), //
|
||||
INCOME_POSTING(19, "loanTransactionType.incomePosting"), //
|
||||
CREDIT_BALANCE_REFUND(20, "loanTransactionType.creditBalanceRefund"), //
|
||||
MERCHANT_ISSUED_REFUND(21, "loanTransactionType.merchantIssuedRefund"), //
|
||||
PAYOUT_REFUND(22, "loanTransactionType.payoutRefund"), //
|
||||
GOODWILL_CREDIT(23, "loanTransactionType.goodwillCredit"), //
|
||||
CHARGE_REFUND(24, "loanTransactionType.chargeRefund"), //
|
||||
CHARGEBACK(25, "loanTransactionType.chargeback"), //
|
||||
CHARGE_ADJUSTMENT(26, "loanTransactionType.chargeAdjustment"), //
|
||||
CHARGE_OFF(27, "loanTransactionType.chargeOff");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
LoanTransactionType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static LoanTransactionType fromInt(final Integer transactionType) {
|
||||
|
||||
if (transactionType == null) {
|
||||
return LoanTransactionType.INVALID;
|
||||
}
|
||||
|
||||
return switch (transactionType) {
|
||||
case 1 -> LoanTransactionType.DISBURSEMENT;
|
||||
case 2 -> LoanTransactionType.REPAYMENT;
|
||||
case 3 -> LoanTransactionType.CONTRA;
|
||||
case 4 -> LoanTransactionType.WAIVE_INTEREST;
|
||||
case 5 -> LoanTransactionType.REPAYMENT_AT_DISBURSEMENT;
|
||||
case 6 -> LoanTransactionType.WRITEOFF;
|
||||
case 7 -> LoanTransactionType.MARKED_FOR_RESCHEDULING;
|
||||
case 8 -> LoanTransactionType.RECOVERY_REPAYMENT;
|
||||
case 9 -> LoanTransactionType.WAIVE_CHARGES;
|
||||
case 10 -> LoanTransactionType.ACCRUAL;
|
||||
case 12 -> LoanTransactionType.INITIATE_TRANSFER;
|
||||
case 13 -> LoanTransactionType.APPROVE_TRANSFER;
|
||||
case 14 -> LoanTransactionType.WITHDRAW_TRANSFER;
|
||||
case 15 -> LoanTransactionType.REJECT_TRANSFER;
|
||||
case 16 -> LoanTransactionType.REFUND;
|
||||
case 17 -> LoanTransactionType.CHARGE_PAYMENT;
|
||||
case 18 -> LoanTransactionType.REFUND_FOR_ACTIVE_LOAN;
|
||||
case 19 -> LoanTransactionType.INCOME_POSTING;
|
||||
case 20 -> LoanTransactionType.CREDIT_BALANCE_REFUND;
|
||||
case 21 -> LoanTransactionType.MERCHANT_ISSUED_REFUND;
|
||||
case 22 -> LoanTransactionType.PAYOUT_REFUND;
|
||||
case 23 -> LoanTransactionType.GOODWILL_CREDIT;
|
||||
case 24 -> LoanTransactionType.CHARGE_REFUND;
|
||||
case 25 -> LoanTransactionType.CHARGEBACK;
|
||||
case 26 -> LoanTransactionType.CHARGE_ADJUSTMENT;
|
||||
case 27 -> LoanTransactionType.CHARGE_OFF;
|
||||
default -> LoanTransactionType.INVALID;
|
||||
};
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public boolean isDisbursement() {
|
||||
return this.equals(LoanTransactionType.DISBURSEMENT);
|
||||
}
|
||||
|
||||
public boolean isRepaymentAtDisbursement() {
|
||||
return this.equals(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT);
|
||||
}
|
||||
|
||||
public boolean isRepayment() {
|
||||
return this.equals(LoanTransactionType.REPAYMENT);
|
||||
}
|
||||
|
||||
public boolean isMerchantIssuedRefund() {
|
||||
return this.equals(LoanTransactionType.MERCHANT_ISSUED_REFUND);
|
||||
}
|
||||
|
||||
public boolean isPayoutRefund() {
|
||||
return this.equals(LoanTransactionType.PAYOUT_REFUND);
|
||||
}
|
||||
|
||||
public boolean isGoodwillCredit() {
|
||||
return this.equals(LoanTransactionType.GOODWILL_CREDIT);
|
||||
}
|
||||
|
||||
public boolean isChargeRefund() {
|
||||
return this.equals(LoanTransactionType.CHARGE_REFUND);
|
||||
}
|
||||
|
||||
public boolean isRepaymentType() {
|
||||
return (isRepayment() || isMerchantIssuedRefund() || isPayoutRefund() || isGoodwillCredit() || isChargeRefund());
|
||||
}
|
||||
|
||||
public boolean isRecoveryRepayment() {
|
||||
return this.equals(LoanTransactionType.RECOVERY_REPAYMENT);
|
||||
}
|
||||
|
||||
public boolean isWaiveInterest() {
|
||||
return this.equals(LoanTransactionType.WAIVE_INTEREST);
|
||||
}
|
||||
|
||||
public boolean isWaiveCharges() {
|
||||
return this.equals(LoanTransactionType.WAIVE_CHARGES);
|
||||
}
|
||||
|
||||
public boolean isAccrual() {
|
||||
return this.equals(LoanTransactionType.ACCRUAL);
|
||||
}
|
||||
|
||||
public boolean isWriteOff() {
|
||||
return this.equals(LoanTransactionType.WRITEOFF);
|
||||
}
|
||||
|
||||
public boolean isChargePayment() {
|
||||
return this.equals(LoanTransactionType.CHARGE_PAYMENT);
|
||||
}
|
||||
|
||||
public boolean isRefundForActiveLoan() {
|
||||
return this.equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN);
|
||||
}
|
||||
|
||||
public boolean isIncomePosting() {
|
||||
return this.equals(LoanTransactionType.INCOME_POSTING);
|
||||
}
|
||||
|
||||
public boolean isChargeback() {
|
||||
return this.equals(LoanTransactionType.CHARGEBACK);
|
||||
}
|
||||
|
||||
public boolean isChargeAdjustment() {
|
||||
return this.equals(LoanTransactionType.CHARGE_ADJUSTMENT);
|
||||
}
|
||||
|
||||
public boolean isChargeOff() {
|
||||
return this.equals(LoanTransactionType.CHARGE_OFF);
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.domain.transactionprocessor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
|
||||
public interface LoanRepaymentScheduleTransactionProcessor {
|
||||
|
||||
String getCode();
|
||||
|
||||
String getName();
|
||||
|
||||
boolean accept(String s);
|
||||
|
||||
void handleTransaction(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
|
||||
Set<LoanCharge> charges);
|
||||
|
||||
ChangedTransactionDetail handleTransaction(LocalDate disbursementDate, List<LoanTransaction> repaymentsOrWaivers,
|
||||
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Set<LoanCharge> charges);
|
||||
|
||||
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
||||
|
||||
Money handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> loanCharges);
|
||||
|
||||
/**
|
||||
* Used in interest recalculation to introduce new interest only installment.
|
||||
*/
|
||||
boolean isInterestFirstRepaymentScheduleTransactionProcessor();
|
||||
|
||||
void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
|
||||
Set<LoanCharge> charges);
|
||||
|
||||
void handleChargeback(LoanTransaction loanTransaction, MonetaryCurrency currency, Money overpaidAmount,
|
||||
List<LoanRepaymentScheduleInstallment> installments);
|
||||
|
||||
void processTransactionsFromDerivedFields(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges);
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class ExceedingTrancheCountException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public ExceedingTrancheCountException(final String entity, final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg." + entity + ".exceeding.max.tranche.count", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* {@link AbstractPlatformDomainRuleException} thrown an action to transition a loan from one state to another violates
|
||||
* a domain rule.
|
||||
*/
|
||||
public class InvalidLoanStateTransitionException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public InvalidLoanStateTransitionException(final String action, final String postFix, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan." + action + "." + postFix, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* {@link AbstractPlatformDomainRuleException} thrown an action to transition a loan from one state to another violates
|
||||
* a domain rule.
|
||||
*/
|
||||
public class InvalidLoanTransactionTypeException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public InvalidLoanTransactionTypeException(final String action, final String postFix, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan." + action + "." + postFix, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class InvalidRefundDateException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public InvalidRefundDateException(final String refundDateAsString) {
|
||||
super("error.msg.loan.refund.failed",
|
||||
"The refund date`" + refundDateAsString + "`" + "` cannot be before the smallest repayment transaction date",
|
||||
new Object[] { refundDateAsString });
|
||||
}
|
||||
|
||||
public InvalidRefundDateException(final String defaultUserMessage, final String entity, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan." + entity, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanApplicationDateException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanApplicationDateException(final String postFix, final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan.application." + postFix, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanChargeRefundException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanChargeRefundException(final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg." + defaultUserMessage, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanDisbursalException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanDisbursalException(final String currentProduct, final String restrictedProduct) {
|
||||
super("error.msg.loan.disbursal.failed",
|
||||
"This loan could not be disbursed as `" + currentProduct + "` and `" + restrictedProduct + "` are not allowed to co-exist",
|
||||
new Object[] { currentProduct, restrictedProduct });
|
||||
}
|
||||
|
||||
public LoanDisbursalException(final String defaultUserMessage, final String entity, final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan." + entity, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanForeclosureException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanForeclosureException(final String errorCode, final String errorMessage, final Object... defaultUserMessageArgs) {
|
||||
super(errorCode, errorMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanOfficerAssignmentDateException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanOfficerAssignmentDateException(final String postFix, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan.assignment.date." + postFix, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanOfficerAssignmentException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanOfficerAssignmentException(final Long loanId, final Long fromLoanOfficerId) {
|
||||
super("error.msg.loan.not.assigned.to.loan.officer",
|
||||
"Loan with identifier " + loanId + " is not assigned to Loan Officer with identifier " + fromLoanOfficerId + ".", loanId);
|
||||
}
|
||||
|
||||
public LoanOfficerAssignmentException(final Long loanId, final LocalDate date) {
|
||||
super("error.msg.loan.assignment.date.is.before.last.assignment.date",
|
||||
"Loan with identifier " + loanId + " was already assigned before date " + date.toString());
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanOfficerUnassignmentDateException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public LoanOfficerUnassignmentDateException(final String postFix, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.loan.loanofficer.unassign.date." + postFix, defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when loan transactions processing strategy resources are not found.
|
||||
*/
|
||||
public class LoanTransactionProcessingStrategyNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public LoanTransactionProcessingStrategyNotFoundException(final String code) {
|
||||
super("error.msg.transactions.processing.strategy.code.invalid",
|
||||
"Loan transaction processing strategy with code " + code + " does not exist", code);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class MultiDisbursementDataNotAllowedException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public MultiDisbursementDataNotAllowedException(final String entity, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg." + entity + ".not.allowed", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class MultiDisbursementDataRequiredException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public MultiDisbursementDataRequiredException(final String entity, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
super("error.msg." + entity + ".required", defaultUserMessage, defaultUserMessageArgs);
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class UndoLastTrancheDisbursementException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public UndoLastTrancheDisbursementException(final Object... defaultUserMessageArgs) {
|
||||
super("error.msg.cannot.undo.last.disbursal.after.repayments or waivers",
|
||||
" Cannot undo last disbursement after repayments or waivers.", defaultUserMessageArgs);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
|
||||
/**
|
||||
* Transfer object to return the schedule after generation of schedule
|
||||
*/
|
||||
public final class LoanScheduleDTO {
|
||||
|
||||
private final List<LoanRepaymentScheduleInstallment> installments;
|
||||
private final LoanScheduleModel loanScheduleModel;
|
||||
|
||||
private LoanScheduleDTO(final List<LoanRepaymentScheduleInstallment> installments, final LoanScheduleModel loanScheduleModel) {
|
||||
this.installments = installments;
|
||||
this.loanScheduleModel = loanScheduleModel;
|
||||
}
|
||||
|
||||
public static LoanScheduleDTO from(final List<LoanRepaymentScheduleInstallment> installments,
|
||||
final LoanScheduleModel loanScheduleModel) {
|
||||
return new LoanScheduleDTO(installments, loanScheduleModel);
|
||||
}
|
||||
|
||||
public List<LoanRepaymentScheduleInstallment> getInstallments() {
|
||||
return this.installments;
|
||||
}
|
||||
|
||||
public LoanScheduleModel getLoanScheduleModel() {
|
||||
return this.loanScheduleModel;
|
||||
}
|
||||
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
|
||||
/**
|
||||
* Immutable data object to represent aspects of a loan schedule such as:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Totals information - the totals for each part of repayment schedule monitored.</li>
|
||||
* <li>Repayment schedule - the principal due, outstanding balance and cost of loan items such as interest and charges
|
||||
* (both fees and penalties)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Getter
|
||||
public class LoanScheduleData {
|
||||
|
||||
/**
|
||||
* The currency associated with all monetary values in loan schedule.
|
||||
*/
|
||||
private final CurrencyData currency;
|
||||
private final Integer loanTermInDays;
|
||||
private final BigDecimal totalPrincipalDisbursed;
|
||||
private final BigDecimal totalPrincipalExpected;
|
||||
private final BigDecimal totalPrincipalPaid;
|
||||
private final BigDecimal totalInterestCharged;
|
||||
private final BigDecimal totalFeeChargesCharged;
|
||||
private final BigDecimal totalPenaltyChargesCharged;
|
||||
private final BigDecimal totalWaived;
|
||||
private final BigDecimal totalWrittenOff;
|
||||
private final BigDecimal totalRepaymentExpected;
|
||||
private final BigDecimal totalRepayment;
|
||||
private final BigDecimal totalPaidInAdvance;
|
||||
private final BigDecimal totalPaidLate;
|
||||
private final BigDecimal totalOutstanding;
|
||||
private final BigDecimal totalCredits;
|
||||
|
||||
/**
|
||||
* <code>periods</code> is collection of data objects containing specific information to each period of the loan
|
||||
* schedule including disbursement and repayment information.
|
||||
*/
|
||||
private final Collection<LoanSchedulePeriodData> periods;
|
||||
|
||||
private Collection<LoanSchedulePeriodData> futurePeriods;
|
||||
|
||||
public LoanScheduleData(final CurrencyData currency, final Collection<LoanSchedulePeriodData> periods, final Integer loanTermInDays,
|
||||
final BigDecimal totalPrincipalDisbursed, final BigDecimal totalPrincipalExpected, final BigDecimal totalPrincipalPaid,
|
||||
final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged,
|
||||
final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalRepaymentExpected,
|
||||
final BigDecimal totalRepayment, final BigDecimal totalPaidInAdvance, final BigDecimal totalPaidLate,
|
||||
final BigDecimal totalOutstanding, final BigDecimal totalCredits) {
|
||||
this.currency = currency;
|
||||
this.periods = periods;
|
||||
this.loanTermInDays = loanTermInDays;
|
||||
this.totalPrincipalDisbursed = totalPrincipalDisbursed;
|
||||
this.totalPrincipalExpected = totalPrincipalExpected;
|
||||
this.totalPrincipalPaid = totalPrincipalPaid;
|
||||
this.totalInterestCharged = totalInterestCharged;
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
||||
this.totalWaived = totalWaived;
|
||||
this.totalWrittenOff = totalWrittenOff;
|
||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||
this.totalRepayment = totalRepayment;
|
||||
this.totalPaidInAdvance = totalPaidInAdvance;
|
||||
this.totalPaidLate = totalPaidLate;
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
this.totalCredits = totalCredits;
|
||||
}
|
||||
|
||||
public LoanScheduleData(final CurrencyData currency, final Collection<LoanSchedulePeriodData> periods, final Integer loanTermInDays,
|
||||
final BigDecimal totalPrincipalDisbursed, final BigDecimal totalPrincipalExpected, final BigDecimal totalInterestCharged,
|
||||
final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged, final BigDecimal totalRepaymentExpected) {
|
||||
this.currency = currency;
|
||||
this.periods = periods;
|
||||
this.loanTermInDays = loanTermInDays;
|
||||
this.totalPrincipalDisbursed = totalPrincipalDisbursed;
|
||||
this.totalPrincipalExpected = totalPrincipalExpected;
|
||||
this.totalPrincipalPaid = null;
|
||||
this.totalInterestCharged = totalInterestCharged;
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
||||
this.totalWaived = null;
|
||||
this.totalWrittenOff = null;
|
||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||
this.totalRepayment = null;
|
||||
this.totalPaidInAdvance = null;
|
||||
this.totalPaidLate = null;
|
||||
this.totalOutstanding = null;
|
||||
this.totalCredits = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void updateFuturePeriods(Collection<LoanSchedulePeriodData> futurePeriods) {
|
||||
this.futurePeriods = futurePeriods;
|
||||
}
|
||||
}
|
||||
+436
@@ -0,0 +1,436 @@
|
||||
/**
|
||||
* 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.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
|
||||
/**
|
||||
* Immutable data object that represents a period of a loan schedule.
|
||||
*
|
||||
*/
|
||||
@Getter
|
||||
public final class LoanSchedulePeriodData {
|
||||
|
||||
private final Integer period;
|
||||
private final LocalDate fromDate;
|
||||
private final LocalDate dueDate;
|
||||
private final LocalDate obligationsMetOnDate;
|
||||
private final Boolean complete;
|
||||
private final Integer daysInPeriod;
|
||||
private final BigDecimal principalDisbursed;
|
||||
private final BigDecimal principalOriginalDue;
|
||||
private final BigDecimal principalDue;
|
||||
private final BigDecimal principalPaid;
|
||||
private final BigDecimal principalWrittenOff;
|
||||
private final BigDecimal principalOutstanding;
|
||||
private final BigDecimal principalLoanBalanceOutstanding;
|
||||
private final BigDecimal interestOriginalDue;
|
||||
private final BigDecimal interestDue;
|
||||
private final BigDecimal interestPaid;
|
||||
private final BigDecimal interestWaived;
|
||||
private final BigDecimal interestWrittenOff;
|
||||
private final BigDecimal interestOutstanding;
|
||||
private final BigDecimal feeChargesDue;
|
||||
private final BigDecimal feeChargesPaid;
|
||||
private final BigDecimal feeChargesWaived;
|
||||
private final BigDecimal feeChargesWrittenOff;
|
||||
private final BigDecimal feeChargesOutstanding;
|
||||
private final BigDecimal penaltyChargesDue;
|
||||
private final BigDecimal penaltyChargesPaid;
|
||||
private final BigDecimal penaltyChargesWaived;
|
||||
private final BigDecimal penaltyChargesWrittenOff;
|
||||
private final BigDecimal penaltyChargesOutstanding;
|
||||
private final BigDecimal totalOriginalDueForPeriod;
|
||||
private final BigDecimal totalDueForPeriod;
|
||||
private final BigDecimal totalPaidForPeriod;
|
||||
private final BigDecimal totalPaidInAdvanceForPeriod;
|
||||
private final BigDecimal totalPaidLateForPeriod;
|
||||
private final BigDecimal totalWaivedForPeriod;
|
||||
private final BigDecimal totalWrittenOffForPeriod;
|
||||
private final BigDecimal totalOutstandingForPeriod;
|
||||
private final BigDecimal totalOverdue;
|
||||
private final BigDecimal totalActualCostOfLoanForPeriod;
|
||||
private final BigDecimal totalInstallmentAmountForPeriod;
|
||||
private final BigDecimal totalCredits;
|
||||
|
||||
public static LoanSchedulePeriodData disbursementOnlyPeriod(final LocalDate disbursementDate, final BigDecimal principalDisbursed,
|
||||
final BigDecimal feeChargesDueAtTimeOfDisbursement, final boolean isDisbursed) {
|
||||
final Integer periodNumber = null;
|
||||
final LocalDate from = null;
|
||||
return new LoanSchedulePeriodData(periodNumber, from, disbursementDate, principalDisbursed, feeChargesDueAtTimeOfDisbursement,
|
||||
isDisbursed);
|
||||
}
|
||||
|
||||
public static LoanSchedulePeriodData repaymentOnlyPeriod(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final BigDecimal principalDue, final BigDecimal principalOutstanding, final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal feeChargesDueForPeriod, final BigDecimal penaltyChargesDueForPeriod, final BigDecimal totalDueForPeriod,
|
||||
final BigDecimal totalInstallmentAmountForPeriod) {
|
||||
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, principalDue, principalOutstanding,
|
||||
interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod, totalDueForPeriod,
|
||||
totalInstallmentAmountForPeriod);
|
||||
}
|
||||
|
||||
public static LoanSchedulePeriodData repaymentPeriodWithPayments(@SuppressWarnings("unused") final Long loanId,
|
||||
final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate, final LocalDate obligationsMetOnDate,
|
||||
final boolean complete, final BigDecimal principalOriginalDue, final BigDecimal principalPaid,
|
||||
final BigDecimal principalWrittenOff, final BigDecimal principalOutstanding, final BigDecimal outstandingPrincipalBalanceOfLoan,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal interestPaid, final BigDecimal interestWaived,
|
||||
final BigDecimal interestWrittenOff, final BigDecimal interestOutstanding, final BigDecimal feeChargesDue,
|
||||
final BigDecimal feeChargesPaid, final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff,
|
||||
final BigDecimal feeChargesOutstanding, final BigDecimal penaltyChargesDue, final BigDecimal penaltyChargesPaid,
|
||||
final BigDecimal penaltyChargesWaived, final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesOutstanding,
|
||||
final BigDecimal totalDueForPeriod, final BigDecimal totalPaid, final BigDecimal totalPaidInAdvanceForPeriod,
|
||||
final BigDecimal totalPaidLateForPeriod, final BigDecimal totalWaived, final BigDecimal totalWrittenOff,
|
||||
final BigDecimal totalOutstanding, final BigDecimal totalActualCostOfLoanForPeriod,
|
||||
final BigDecimal totalInstallmentAmountForPeriod, final BigDecimal totalCredits) {
|
||||
|
||||
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, obligationsMetOnDate, complete, principalOriginalDue,
|
||||
principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan,
|
||||
interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesDue,
|
||||
feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesDue, penaltyChargesPaid,
|
||||
penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, totalPaid,
|
||||
totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaived, totalWrittenOff, totalOutstanding,
|
||||
totalActualCostOfLoanForPeriod, totalInstallmentAmountForPeriod, totalCredits);
|
||||
}
|
||||
|
||||
public static LoanSchedulePeriodData withPaidDetail(final LoanSchedulePeriodData loanSchedulePeriodData, final boolean complete,
|
||||
final BigDecimal principalPaid, final BigDecimal interestPaid, final BigDecimal feeChargesPaid,
|
||||
final BigDecimal penaltyChargesPaid) {
|
||||
|
||||
return new LoanSchedulePeriodData(loanSchedulePeriodData.period, loanSchedulePeriodData.fromDate, loanSchedulePeriodData.dueDate,
|
||||
loanSchedulePeriodData.obligationsMetOnDate, complete, loanSchedulePeriodData.principalOriginalDue, principalPaid,
|
||||
loanSchedulePeriodData.principalWrittenOff, loanSchedulePeriodData.principalOutstanding,
|
||||
loanSchedulePeriodData.principalLoanBalanceOutstanding, loanSchedulePeriodData.interestDue, interestPaid,
|
||||
loanSchedulePeriodData.interestWaived, loanSchedulePeriodData.interestWrittenOff,
|
||||
loanSchedulePeriodData.interestOutstanding, loanSchedulePeriodData.feeChargesDue, feeChargesPaid,
|
||||
loanSchedulePeriodData.feeChargesWaived, loanSchedulePeriodData.feeChargesWrittenOff,
|
||||
loanSchedulePeriodData.feeChargesOutstanding, loanSchedulePeriodData.penaltyChargesDue, penaltyChargesPaid,
|
||||
loanSchedulePeriodData.penaltyChargesWaived, loanSchedulePeriodData.penaltyChargesWrittenOff,
|
||||
loanSchedulePeriodData.penaltyChargesOutstanding, loanSchedulePeriodData.totalDueForPeriod,
|
||||
loanSchedulePeriodData.totalPaidForPeriod, loanSchedulePeriodData.totalPaidInAdvanceForPeriod,
|
||||
loanSchedulePeriodData.totalPaidLateForPeriod, loanSchedulePeriodData.totalWaivedForPeriod,
|
||||
loanSchedulePeriodData.totalWrittenOffForPeriod, loanSchedulePeriodData.totalOutstandingForPeriod,
|
||||
loanSchedulePeriodData.totalActualCostOfLoanForPeriod, loanSchedulePeriodData.totalInstallmentAmountForPeriod,
|
||||
loanSchedulePeriodData.totalCredits);
|
||||
}
|
||||
|
||||
/*
|
||||
* constructor used for creating period on loan schedule that is only a disbursement (typically first period)
|
||||
*/
|
||||
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final BigDecimal principalDisbursed, final BigDecimal chargesDueAtTimeOfDisbursement, final boolean isDisbursed) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
this.obligationsMetOnDate = null;
|
||||
this.complete = null;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Math.toIntExact(ChronoUnit.DAYS.between(this.fromDate, this.dueDate));
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = principalDisbursed;
|
||||
this.principalOriginalDue = null;
|
||||
this.principalDue = null;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = null;
|
||||
this.principalLoanBalanceOutstanding = principalDisbursed;
|
||||
|
||||
this.interestOriginalDue = null;
|
||||
this.interestDue = null;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = null;
|
||||
|
||||
this.feeChargesDue = chargesDueAtTimeOfDisbursement;
|
||||
if (isDisbursed) {
|
||||
this.feeChargesPaid = chargesDueAtTimeOfDisbursement;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = null;
|
||||
} else {
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = chargesDueAtTimeOfDisbursement;
|
||||
}
|
||||
|
||||
this.penaltyChargesDue = null;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
this.penaltyChargesOutstanding = null;
|
||||
|
||||
this.totalOriginalDueForPeriod = chargesDueAtTimeOfDisbursement;
|
||||
this.totalDueForPeriod = chargesDueAtTimeOfDisbursement;
|
||||
this.totalPaidForPeriod = this.feeChargesPaid;
|
||||
this.totalPaidInAdvanceForPeriod = null;
|
||||
this.totalPaidLateForPeriod = null;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = this.feeChargesOutstanding;
|
||||
this.totalActualCostOfLoanForPeriod = this.feeChargesDue;
|
||||
this.totalInstallmentAmountForPeriod = null;
|
||||
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
this.totalCredits = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/*
|
||||
* used for repayment only period when creating an empty loan schedule for preview etc
|
||||
*/
|
||||
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final BigDecimal principalOriginalDue, final BigDecimal principalOutstanding,
|
||||
final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal feeChargesDueForPeriod,
|
||||
final BigDecimal penaltyChargesDueForPeriod, final BigDecimal totalDueForPeriod, BigDecimal totalInstallmentAmountForPeriod) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
this.obligationsMetOnDate = null;
|
||||
this.complete = null;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Math.toIntExact(ChronoUnit.DAYS.between(this.fromDate, this.dueDate));
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = null;
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = null;
|
||||
this.principalWrittenOff = null;
|
||||
this.principalOutstanding = principalOriginalDue;
|
||||
this.principalLoanBalanceOutstanding = principalOutstanding;
|
||||
|
||||
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = null;
|
||||
this.interestWaived = null;
|
||||
this.interestWrittenOff = null;
|
||||
this.interestOutstanding = interestDueOnPrincipalOutstanding;
|
||||
|
||||
this.feeChargesDue = feeChargesDueForPeriod;
|
||||
this.feeChargesPaid = null;
|
||||
this.feeChargesWaived = null;
|
||||
this.feeChargesWrittenOff = null;
|
||||
this.feeChargesOutstanding = null;
|
||||
|
||||
this.penaltyChargesDue = penaltyChargesDueForPeriod;
|
||||
this.penaltyChargesPaid = null;
|
||||
this.penaltyChargesWaived = null;
|
||||
this.penaltyChargesWrittenOff = null;
|
||||
this.penaltyChargesOutstanding = null;
|
||||
|
||||
this.totalOriginalDueForPeriod = totalDueForPeriod;
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = BigDecimal.ZERO;
|
||||
this.totalPaidInAdvanceForPeriod = null;
|
||||
this.totalPaidLateForPeriod = null;
|
||||
this.totalWaivedForPeriod = null;
|
||||
this.totalWrittenOffForPeriod = null;
|
||||
this.totalOutstandingForPeriod = totalDueForPeriod;
|
||||
this.totalActualCostOfLoanForPeriod = interestDueOnPrincipalOutstanding.add(feeChargesDueForPeriod);
|
||||
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
|
||||
|
||||
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
this.totalCredits = BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used for creating loan schedule periods with full information on expected principal, interest & charges along
|
||||
* with what portion of each is paid.
|
||||
*/
|
||||
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
|
||||
final LocalDate obligationsMetOnDate, final boolean complete, final BigDecimal principalOriginalDue,
|
||||
final BigDecimal principalPaid, final BigDecimal principalWrittenOff, final BigDecimal principalOutstanding,
|
||||
final BigDecimal principalLoanBalanceOutstanding, final BigDecimal interestDueOnPrincipalOutstanding,
|
||||
final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWrittenOff,
|
||||
final BigDecimal interestOutstanding, final BigDecimal feeChargesDue, final BigDecimal feeChargesPaid,
|
||||
final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff, final BigDecimal feeChargesOutstanding,
|
||||
final BigDecimal penaltyChargesDue, final BigDecimal penaltyChargesPaid, final BigDecimal penaltyChargesWaived,
|
||||
final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesOutstanding, final BigDecimal totalDueForPeriod,
|
||||
final BigDecimal totalPaid, final BigDecimal totalPaidInAdvanceForPeriod, final BigDecimal totalPaidLateForPeriod,
|
||||
final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalOutstanding,
|
||||
final BigDecimal totalActualCostOfLoanForPeriod, final BigDecimal totalInstallmentAmountForPeriod,
|
||||
final BigDecimal totalCredits) {
|
||||
this.period = periodNumber;
|
||||
this.fromDate = fromDate;
|
||||
this.dueDate = dueDate;
|
||||
this.obligationsMetOnDate = obligationsMetOnDate;
|
||||
this.complete = complete;
|
||||
if (fromDate != null) {
|
||||
this.daysInPeriod = Math.toIntExact(ChronoUnit.DAYS.between(this.fromDate, this.dueDate));
|
||||
} else {
|
||||
this.daysInPeriod = null;
|
||||
}
|
||||
this.principalDisbursed = null;
|
||||
this.principalOriginalDue = principalOriginalDue;
|
||||
this.principalDue = principalOriginalDue;
|
||||
this.principalPaid = principalPaid;
|
||||
this.principalWrittenOff = principalWrittenOff;
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
this.principalLoanBalanceOutstanding = principalLoanBalanceOutstanding;
|
||||
|
||||
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestDue = interestDueOnPrincipalOutstanding;
|
||||
this.interestPaid = interestPaid;
|
||||
this.interestWaived = interestWaived;
|
||||
this.interestWrittenOff = interestWrittenOff;
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
|
||||
this.feeChargesDue = feeChargesDue;
|
||||
this.feeChargesPaid = feeChargesPaid;
|
||||
this.feeChargesWaived = feeChargesWaived;
|
||||
this.feeChargesWrittenOff = feeChargesWrittenOff;
|
||||
this.feeChargesOutstanding = feeChargesOutstanding;
|
||||
|
||||
this.penaltyChargesDue = penaltyChargesDue;
|
||||
this.penaltyChargesPaid = penaltyChargesPaid;
|
||||
this.penaltyChargesWaived = penaltyChargesWaived;
|
||||
this.penaltyChargesWrittenOff = penaltyChargesWrittenOff;
|
||||
this.penaltyChargesOutstanding = penaltyChargesOutstanding;
|
||||
|
||||
this.totalOriginalDueForPeriod = totalDueForPeriod;
|
||||
this.totalDueForPeriod = totalDueForPeriod;
|
||||
this.totalPaidForPeriod = totalPaid;
|
||||
this.totalPaidInAdvanceForPeriod = totalPaidInAdvanceForPeriod;
|
||||
this.totalPaidLateForPeriod = totalPaidLateForPeriod;
|
||||
this.totalWaivedForPeriod = totalWaived;
|
||||
this.totalWrittenOffForPeriod = totalWrittenOff;
|
||||
this.totalOutstandingForPeriod = totalOutstanding;
|
||||
this.totalActualCostOfLoanForPeriod = totalActualCostOfLoanForPeriod;
|
||||
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
|
||||
|
||||
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
|
||||
this.totalOverdue = this.totalOutstandingForPeriod;
|
||||
} else {
|
||||
this.totalOverdue = null;
|
||||
}
|
||||
this.totalCredits = totalCredits;
|
||||
}
|
||||
|
||||
private BigDecimal defaultToZeroIfNull(final BigDecimal possibleNullValue) {
|
||||
BigDecimal value = BigDecimal.ZERO;
|
||||
if (possibleNullValue != null) {
|
||||
value = possibleNullValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalDisbursed() {
|
||||
return defaultToZeroIfNull(this.principalDisbursed);
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalDue() {
|
||||
return defaultToZeroIfNull(this.principalDue);
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalPaid() {
|
||||
return defaultToZeroIfNull(this.principalPaid);
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalWrittenOff() {
|
||||
return defaultToZeroIfNull(this.principalWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalOutstanding() {
|
||||
return defaultToZeroIfNull(this.principalOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal getInterestDue() {
|
||||
return defaultToZeroIfNull(this.interestDue);
|
||||
}
|
||||
|
||||
public BigDecimal getInterestPaid() {
|
||||
return defaultToZeroIfNull(this.interestPaid);
|
||||
}
|
||||
|
||||
public BigDecimal getInterestWaived() {
|
||||
return defaultToZeroIfNull(this.interestWaived);
|
||||
}
|
||||
|
||||
public BigDecimal getInterestWrittenOff() {
|
||||
return defaultToZeroIfNull(this.interestWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal getInterestOutstanding() {
|
||||
return defaultToZeroIfNull(this.interestOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesDue() {
|
||||
return defaultToZeroIfNull(this.feeChargesDue);
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesWaived() {
|
||||
return defaultToZeroIfNull(this.feeChargesWaived);
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesWrittenOff() {
|
||||
return defaultToZeroIfNull(this.feeChargesWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesPaid() {
|
||||
return defaultToZeroIfNull(this.feeChargesPaid);
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesOutstanding() {
|
||||
return defaultToZeroIfNull(this.feeChargesOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesDue() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesDue);
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesWaived() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesWaived);
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesWrittenOff() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesWrittenOff);
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesPaid() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesPaid);
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesOutstanding() {
|
||||
return defaultToZeroIfNull(this.penaltyChargesOutstanding);
|
||||
}
|
||||
|
||||
public BigDecimal getTotalOverdue() {
|
||||
return defaultToZeroIfNull(this.totalOverdue);
|
||||
}
|
||||
|
||||
public BigDecimal totalOutstandingForPeriod() {
|
||||
return defaultToZeroIfNull(this.totalOutstandingForPeriod);
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AprCalculator {
|
||||
|
||||
public BigDecimal calculateFrom(final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal interestRatePerPeriod,
|
||||
final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType) {
|
||||
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO;
|
||||
switch (interestPeriodFrequencyType) {
|
||||
case DAYS:
|
||||
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(365));
|
||||
break;
|
||||
case WEEKS:
|
||||
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(52));
|
||||
break;
|
||||
case MONTHS:
|
||||
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(12));
|
||||
break;
|
||||
case YEARS:
|
||||
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(1));
|
||||
break;
|
||||
case WHOLE_TERM:
|
||||
final BigDecimal ratePerPeriod = interestRatePerPeriod.divide(BigDecimal.valueOf(numberOfRepayments * repaymentEvery), 8,
|
||||
RoundingMode.HALF_UP);
|
||||
|
||||
switch (repaymentPeriodFrequencyType) {
|
||||
case DAYS:
|
||||
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(365));
|
||||
break;
|
||||
case WEEKS:
|
||||
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(52));
|
||||
break;
|
||||
case MONTHS:
|
||||
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(12));
|
||||
break;
|
||||
case YEARS:
|
||||
defaultAnnualNominalInterestRate = ratePerPeriod.multiply(BigDecimal.valueOf(1));
|
||||
break;
|
||||
case WHOLE_TERM:
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return defaultAnnualNominalInterestRate;
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public final class FinanicalFunctions {
|
||||
|
||||
private FinanicalFunctions() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* PMT calculates a fixed monthly payment to be paid by borrower every 'period' to ensure loan is paid off in full
|
||||
* (with interest).
|
||||
*
|
||||
* This monthly payment c depends upon the monthly interest rate r (expressed as a fraction, not a percentage, i.e.,
|
||||
* divide the quoted yearly percentage rate by 100 and by 12 to obtain the monthly interest rate), the number of
|
||||
* monthly payments N called the loan's term, and the amount borrowed P known as the loan's principal; c is given by
|
||||
* the formula:
|
||||
*
|
||||
* c = (r / (1 - (1 + r)^-N))P
|
||||
*
|
||||
* @param interestRateFraction
|
||||
* @param numberOfPayments
|
||||
* @param principal
|
||||
* @param futureValue
|
||||
* @param type
|
||||
*/
|
||||
public static double pmt(final double interestRateFraction, final double numberOfPayments, final double principal,
|
||||
final double futureValue, final boolean type) {
|
||||
double payment = 0;
|
||||
if (interestRateFraction == 0) {
|
||||
payment = -1 * (futureValue + principal) / numberOfPayments;
|
||||
} else {
|
||||
final double r1 = interestRateFraction + 1;
|
||||
payment = (futureValue + principal * Math.pow(r1, numberOfPayments)) * interestRateFraction
|
||||
/ ((type ? r1 : 1) * (1 - Math.pow(r1, numberOfPayments)));
|
||||
}
|
||||
return payment;
|
||||
}
|
||||
|
||||
public static int nop(final double interestRateFraction, final double emiAmount, final double principal, final double futureValue,
|
||||
final boolean type) {
|
||||
double numberOfPayments = 0;
|
||||
if (interestRateFraction == 0) {
|
||||
numberOfPayments = ((Double) (-1 * (futureValue + principal) / emiAmount)).intValue();
|
||||
} else {
|
||||
final double r1 = interestRateFraction + 1;
|
||||
numberOfPayments = (futureValue + principal * Math.pow(r1, emiAmount)) * interestRateFraction
|
||||
/ ((type ? r1 : 1) * (1 - Math.pow(r1, emiAmount)));
|
||||
}
|
||||
return Double.valueOf(numberOfPayments).intValue();
|
||||
}
|
||||
}
|
||||
+1721
File diff suppressed because it is too large
Load Diff
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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 java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
||||
|
||||
public interface LoanScheduleGenerator {
|
||||
|
||||
LoanScheduleModel generate(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges,
|
||||
HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Loan loan,
|
||||
HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
LocalDate rescheduleFrom);
|
||||
|
||||
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
|
||||
LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO,
|
||||
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
|
||||
|
||||
}
|
||||
+26
@@ -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.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||
|
||||
public interface LoanScheduleGeneratorFactory {
|
||||
|
||||
LoanScheduleGenerator create(InterestMethod interestMethod);
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* Domain representation of a Loan Schedule (not used for persistence)
|
||||
*/
|
||||
public final class LoanScheduleModel {
|
||||
|
||||
private final Collection<LoanScheduleModelPeriod> periods;
|
||||
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;
|
||||
|
||||
public static LoanScheduleModel from(final Collection<LoanScheduleModelPeriod> periods, 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 LoanScheduleModel(periods, applicationCurrency, loanTermInDays, principalDisbursed, totalPrincipalExpected,
|
||||
totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
|
||||
totalOutstanding);
|
||||
}
|
||||
|
||||
public static LoanScheduleModel withOverdueChargeUpdation(final Collection<LoanScheduleModelPeriod> periods,
|
||||
final LoanScheduleModel loanScheduleModel, final BigDecimal totalPenaltyChargesCharged) {
|
||||
|
||||
return new LoanScheduleModel(periods, loanScheduleModel.applicationCurrency, loanScheduleModel.loanTermInDays,
|
||||
loanScheduleModel.totalPrincipalDisbursed, loanScheduleModel.totalPrincipalExpected, loanScheduleModel.totalPrincipalPaid,
|
||||
loanScheduleModel.totalInterestCharged, loanScheduleModel.totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
loanScheduleModel.totalRepaymentExpected, loanScheduleModel.totalOutstanding);
|
||||
}
|
||||
|
||||
public static LoanScheduleModel withLoanScheduleModelPeriods(final Collection<LoanScheduleModelPeriod> periods,
|
||||
final LoanScheduleModel loanScheduleModel) {
|
||||
|
||||
return new LoanScheduleModel(periods, loanScheduleModel.applicationCurrency, loanScheduleModel.loanTermInDays,
|
||||
loanScheduleModel.totalPrincipalDisbursed, loanScheduleModel.totalPrincipalExpected, loanScheduleModel.totalPrincipalPaid,
|
||||
loanScheduleModel.totalInterestCharged, loanScheduleModel.totalFeeChargesCharged,
|
||||
loanScheduleModel.totalPenaltyChargesCharged, loanScheduleModel.totalRepaymentExpected, loanScheduleModel.totalOutstanding);
|
||||
}
|
||||
|
||||
private LoanScheduleModel(final Collection<LoanScheduleModelPeriod> periods, 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.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 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 LoanScheduleModelPeriod 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<LoanScheduleModelPeriod> getPeriods() {
|
||||
return this.periods;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesCharged() {
|
||||
return this.totalPenaltyChargesCharged;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalInterestCharged() {
|
||||
return this.totalInterestCharged;
|
||||
}
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
|
||||
public interface LoanScheduleModelPeriod {
|
||||
|
||||
LoanSchedulePeriodData toData();
|
||||
|
||||
boolean isRepaymentPeriod();
|
||||
|
||||
Integer periodNumber();
|
||||
|
||||
LocalDate periodFromDate();
|
||||
|
||||
LocalDate periodDueDate();
|
||||
|
||||
BigDecimal principalDue();
|
||||
|
||||
BigDecimal interestDue();
|
||||
|
||||
BigDecimal feeChargesDue();
|
||||
|
||||
BigDecimal penaltyChargesDue();
|
||||
|
||||
void addLoanCharges(BigDecimal feeCharge, BigDecimal penaltyCharge);
|
||||
|
||||
boolean isRecalculatedInterestComponent();
|
||||
|
||||
void addPrincipalAmount(Money principalDue);
|
||||
|
||||
void addInterestAmount(Money interestDue);
|
||||
|
||||
Set<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails();
|
||||
|
||||
void setEMIFixedSpecificToInstallmentTrue();
|
||||
|
||||
boolean isEMIFixedSpecificToInstallment();
|
||||
|
||||
BigDecimal rescheduleInterestPortion();
|
||||
|
||||
void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion);
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.time.LocalDate;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
|
||||
public interface PaymentPeriodsInOneYearCalculator {
|
||||
|
||||
Integer calculate(PeriodFrequencyType repaymentFrequencyType);
|
||||
|
||||
double calculatePortionOfRepaymentPeriodInterestChargingGrace(LocalDate repaymentPeriodStartDate, LocalDate scheduledDueDate,
|
||||
LocalDate interestChargedFromLocalDate, PeriodFrequencyType repaymentPeriodFrequencyType, Integer repaidEvery);
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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 org.apache.fineract.organisation.monetary.domain.Money;
|
||||
|
||||
public class PrincipalInterest {
|
||||
|
||||
private final Money principal;
|
||||
private final Money interest;
|
||||
private final Money interestPaymentDueToGrace;
|
||||
private Money rescheduleInterestPortion;
|
||||
|
||||
public PrincipalInterest(final Money principal, final Money interest, final Money interestPaymentDueToGrace) {
|
||||
this.principal = principal;
|
||||
this.interest = interest;
|
||||
this.interestPaymentDueToGrace = interestPaymentDueToGrace;
|
||||
}
|
||||
|
||||
public Money principal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public Money interest() {
|
||||
return this.interest;
|
||||
}
|
||||
|
||||
public Money interestPaymentDueToGrace() {
|
||||
return this.interestPaymentDueToGrace;
|
||||
}
|
||||
|
||||
public Money getRescheduleInterestPortion() {
|
||||
return rescheduleInterestPortion;
|
||||
}
|
||||
|
||||
public void setRescheduleInterestPortion(Money rescheduleInterestPortion) {
|
||||
this.rescheduleInterestPortion = rescheduleInterestPortion;
|
||||
}
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public interface LoanProductConstants {
|
||||
|
||||
String USE_BORROWER_CYCLE_PARAMETER_NAME = "useBorrowerCycle";
|
||||
|
||||
String PRINCIPAL_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME = "principalVariationsForBorrowerCycle";
|
||||
String INTEREST_RATE_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME = "interestRateVariationsForBorrowerCycle";
|
||||
String NUMBER_OF_REPAYMENT_VARIATIONS_FOR_BORROWER_CYCLE_PARAMETER_NAME = "numberOfRepaymentVariationsForBorrowerCycle";
|
||||
|
||||
String DEFAULT_VALUE_PARAMETER_NAME = "defaultValue";
|
||||
String MIN_VALUE_PARAMETER_NAME = "minValue";
|
||||
String MAX_VALUE_PARAMETER_NAME = "maxValue";
|
||||
String VALUE_CONDITION_TYPE_PARAM_NAME = "valueConditionType";
|
||||
String BORROWER_CYCLE_NUMBER_PARAM_NAME = "borrowerCycleNumber";
|
||||
String BORROWER_CYCLE_ID_PARAMETER_NAME = "id";
|
||||
|
||||
String PRINCIPAL_PER_CYCLE_PARAMETER_NAME = "principalPerCycle";
|
||||
String MIN_PRINCIPAL_PER_CYCLE_PARAMETER_NAME = "minPrincipalPerCycle";
|
||||
String MAX_PRINCIPAL_PER_CYCLE_PARAMETER_NAME = "maxPrincipalPerCycle";
|
||||
String PRINCIPAL_VALUE_USAGE_CONDITION_PARAM_NAME = "principalValueUsageCondition";
|
||||
String PRINCIPAL_CYCLE_NUMBERS_PARAM_NAME = "principalCycleNumbers";
|
||||
|
||||
String NUMBER_OF_REPAYMENTS_PER_CYCLE_PARAMETER_NAME = "numberOfRepaymentsPerCycle";
|
||||
String MIN_NUMBER_OF_REPAYMENTS_PER_CYCLE_PARAMETER_NAME = "minNumberOfRepaymentsPerCycle";
|
||||
String MAX_NUMBER_OF_REPAYMENTS_PER_CYCLE_PARAMETER_NAME = "maxNumberOfRepaymentsPerCycle";
|
||||
String REPAYMENT_VALUE_USAGE_CONDITION_PARAM_NAME = "repaymentValueUsageCondition";
|
||||
String REPAYMENT_CYCLE_NUMBER_PARAM_NAME = "repaymentCycleNumber";
|
||||
|
||||
String INTEREST_RATE_PER_PERIOD_PER_CYCLE_PARAMETER_NAME = "interestRatePerPeriodPerCycle";
|
||||
String MIN_INTEREST_RATE_PER_PERIOD_PER_CYCLE_PARAMETER_NAME = "minInterestRatePerPeriodPerCycle";
|
||||
String MAX_INTEREST_RATE_PER_PERIOD_PER_CYCLE_PARAMETER_NAME = "maxInterestRatePerPeriodPerCycle";
|
||||
String INTEREST_RATE_VALUE_USAGE_CONDITION_PARAM_NAME = "interestRateValueUsageCondition";
|
||||
String INTEREST_RATE_CYCLE_NUMBER_PARAM_NAME = "interestRateCycleNumber";
|
||||
|
||||
String PRINCIPAL = "principal";
|
||||
String MIN_PRINCIPAL = "minPrincipal";
|
||||
String MAX_PRINCIPAL = "maxPrincipalValue";
|
||||
|
||||
String INTEREST_RATE_PER_PERIOD = "interestRatePerPeriod";
|
||||
String MIN_INTEREST_RATE_PER_PERIOD = "minInterestRatePerPeriod";
|
||||
String MAX_INTEREST_RATE_PER_PERIOD = "maxInterestRatePerPeriod";
|
||||
|
||||
String NUMBER_OF_REPAYMENTS = "numberOfRepayments";
|
||||
String MIN_NUMBER_OF_REPAYMENTS = "minNumberOfRepayments";
|
||||
String MAX_NUMBER_OF_REPAYMENTS = "maxNumberOfRepayments";
|
||||
|
||||
String VALUE_CONDITION_END_WITH_ERROR = "condition.type.must.end.with.greater.than";
|
||||
String VALUE_CONDITION_START_WITH_ERROR = "condition.type.must.start.with.equal";
|
||||
String SHORT_NAME = "shortName";
|
||||
|
||||
String MULTI_DISBURSE_LOAN_PARAMETER_NAME = "multiDisburseLoan";
|
||||
String MAX_TRANCHE_COUNT_PARAMETER_NAME = "maxTrancheCount";
|
||||
String OUTSTANDING_LOAN_BALANCE_PARAMETER_NAME = "outstandingLoanBalance";
|
||||
|
||||
String GRACE_ON_ARREARS_AGEING_PARAMETER_NAME = "graceOnArrearsAgeing";
|
||||
String OVERDUE_DAYS_FOR_NPA_PARAMETER_NAME = "overdueDaysForNPA";
|
||||
String MINIMUM_DAYS_BETWEEN_DISBURSAL_AND_FIRST_REPAYMENT = "minimumDaysBetweenDisbursalAndFirstRepayment";
|
||||
String ACCOUNT_MOVES_OUT_OF_NPA_ONLY_ON_ARREARS_COMPLETION_PARAM_NAME = "accountMovesOutOfNPAOnlyOnArrearsCompletion";
|
||||
|
||||
// Interest recalculation related
|
||||
String IS_INTEREST_RECALCULATION_ENABLED_PARAMETER_NAME = "isInterestRecalculationEnabled";
|
||||
String DAYS_IN_YEAR_TYPE_PARAMETER_NAME = "daysInYearType";
|
||||
String DAYS_IN_MONTH_TYPE_PARAMETER_NAME = "daysInMonthType";
|
||||
String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod";
|
||||
String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
|
||||
String recalculationRestFrequencyTypeParameterName = "recalculationRestFrequencyType";
|
||||
String recalculationRestFrequencyIntervalParameterName = "recalculationRestFrequencyInterval";
|
||||
String recalculationRestFrequencyWeekdayParamName = "recalculationRestFrequencyDayOfWeekType";
|
||||
String recalculationRestFrequencyNthDayParamName = "recalculationRestFrequencyNthDayType";
|
||||
String recalculationRestFrequencyOnDayParamName = "recalculationRestFrequencyOnDayType";
|
||||
String isArrearsBasedOnOriginalScheduleParamName = "isArrearsBasedOnOriginalSchedule";
|
||||
String preClosureInterestCalculationStrategyParamName = "preClosureInterestCalculationStrategy";
|
||||
String recalculationCompoundingFrequencyTypeParameterName = "recalculationCompoundingFrequencyType";
|
||||
String recalculationCompoundingFrequencyIntervalParameterName = "recalculationCompoundingFrequencyInterval";
|
||||
String recalculationCompoundingFrequencyWeekdayParamName = "recalculationCompoundingFrequencyDayOfWeekType";
|
||||
String recalculationCompoundingFrequencyNthDayParamName = "recalculationCompoundingFrequencyNthDayType";
|
||||
String recalculationCompoundingFrequencyOnDayParamName = "recalculationCompoundingFrequencyOnDayType";
|
||||
String isCompoundingToBePostedAsTransactionParamName = "isCompoundingToBePostedAsTransaction";
|
||||
|
||||
// Guarantee related
|
||||
String holdGuaranteeFundsParamName = "holdGuaranteeFunds";
|
||||
String mandatoryGuaranteeParamName = "mandatoryGuarantee";
|
||||
String minimumGuaranteeFromOwnFundsParamName = "minimumGuaranteeFromOwnFunds";
|
||||
String minimumGuaranteeFromGuarantorParamName = "minimumGuaranteeFromGuarantor";
|
||||
|
||||
String principalThresholdForLastInstallmentParamName = "principalThresholdForLastInstallment";
|
||||
BigDecimal DEFAULT_PRINCIPAL_THRESHOLD_FOR_MULTI_DISBURSE_LOAN = BigDecimal.valueOf(50);
|
||||
BigDecimal DEFAULT_PRINCIPAL_THRESHOLD_FOR_SINGLE_DISBURSE_LOAN = BigDecimal.valueOf(0);
|
||||
// Fixed installment configuration related
|
||||
String canDefineEmiAmountParamName = "canDefineInstallmentAmount";
|
||||
String fixedPrincipalPercentagePerInstallmentParamName = "fixedPrincipalPercentagePerInstallment";
|
||||
|
||||
// Loan Configurable Attributes
|
||||
String allowAttributeOverridesParamName = "allowAttributeOverrides";
|
||||
String amortizationTypeParamName = "amortizationType";
|
||||
String interestTypeParamName = "interestType";
|
||||
String transactionProcessingStrategyCodeParamName = "transactionProcessingStrategyCode";
|
||||
String interestCalculationPeriodTypeParamName = "interestCalculationPeriodType";
|
||||
String inArrearsToleranceParamName = "inArrearsTolerance";
|
||||
String repaymentEveryParamName = "repaymentEvery";
|
||||
String graceOnPrincipalAndInterestPaymentParamName = "graceOnPrincipalAndInterestPayment";
|
||||
String allowCompoundingOnEodParamName = "allowCompoundingOnEod";
|
||||
|
||||
// Variable Installments Settings
|
||||
String allowVariableInstallmentsParamName = "allowVariableInstallments";
|
||||
String minimumGapBetweenInstallments = "minimumGap";
|
||||
String maximumGapBetweenInstallments = "maximumGap";
|
||||
|
||||
String ALLOW_PARTIAL_PERIOD_INTEREST_CALCUALTION_PARAM_NAME = "allowPartialPeriodInterestCalcualtion";
|
||||
|
||||
String CAN_USE_FOR_TOPUP = "canUseForTopup";
|
||||
|
||||
String IS_EQUAL_AMORTIZATION_PARAM = "isEqualAmortization";
|
||||
|
||||
String RATES_PARAM_NAME = "rates";
|
||||
|
||||
// Multiple disbursement related
|
||||
String installmentAmountInMultiplesOfParamName = "installmentAmountInMultiplesOf";
|
||||
String DISALLOW_EXPECTED_DISBURSEMENTS = "disallowExpectedDisbursements";
|
||||
String ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED = "allowApprovedDisbursedAmountsOverApplied";
|
||||
String OVER_APPLIED_CALCULATION_TYPE = "overAppliedCalculationType";
|
||||
String OVER_APPLIED_NUMBER = "overAppliedNumber";
|
||||
String DELINQUENCY_BUCKET_PARAM_NAME = "delinquencyBucketId";
|
||||
|
||||
// repayment events related
|
||||
String DUE_DAYS_FOR_REPAYMENT_EVENT = "dueDaysForRepaymentEvent";
|
||||
String OVER_DUE_DAYS_FOR_REPAYMENT_EVENT = "overDueDaysForRepaymentEvent";
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.io.Serializable;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a transaction strategy option for a loan.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public final class TransactionProcessingStrategyData implements Serializable {
|
||||
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final String code;
|
||||
private final String name;
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
public enum AmortizationMethod {
|
||||
|
||||
EQUAL_PRINCIPAL(0, "amortizationType.equal.principal"), //
|
||||
EQUAL_INSTALLMENTS(1, "amortizationType.equal.installments"), //
|
||||
INVALID(2, "amortizationType.invalid");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
AmortizationMethod(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static AmortizationMethod fromInt(final Integer selectedMethod) {
|
||||
|
||||
if (selectedMethod == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return switch (selectedMethod) {
|
||||
case 0 -> AmortizationMethod.EQUAL_PRINCIPAL;
|
||||
case 1 -> AmortizationMethod.EQUAL_INSTALLMENTS;
|
||||
default -> AmortizationMethod.INVALID;
|
||||
};
|
||||
}
|
||||
|
||||
public boolean isEqualInstallment() {
|
||||
return this.value.equals(AmortizationMethod.EQUAL_INSTALLMENTS.getValue());
|
||||
}
|
||||
|
||||
public boolean isEqualPrincipal() {
|
||||
return this.value.equals(AmortizationMethod.EQUAL_PRINCIPAL.getValue());
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
public enum InterestCalculationPeriodMethod {
|
||||
|
||||
DAILY(0, "interestCalculationPeriodType.daily"), //
|
||||
SAME_AS_REPAYMENT_PERIOD(1, "interestCalculationPeriodType.same.as.repayment.period"), //
|
||||
INVALID(2, "interestCalculationPeriodType.invalid");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
InterestCalculationPeriodMethod(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static InterestCalculationPeriodMethod fromInt(final Integer selectedMethod) {
|
||||
|
||||
return switch (selectedMethod) {
|
||||
case 0 -> InterestCalculationPeriodMethod.DAILY;
|
||||
case 1 -> InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD;
|
||||
default -> InterestCalculationPeriodMethod.INVALID;
|
||||
};
|
||||
}
|
||||
|
||||
public boolean isDaily() {
|
||||
return this.value.equals(InterestCalculationPeriodMethod.DAILY.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
public enum InterestMethod {
|
||||
|
||||
DECLINING_BALANCE(0, "interestType.declining.balance"), FLAT(1, "interestType.flat"), INVALID(2, "interestType.invalid");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
InterestMethod(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static InterestMethod fromInt(final Integer selectedMethod) {
|
||||
|
||||
return switch (selectedMethod) {
|
||||
case 0 -> InterestMethod.DECLINING_BALANCE;
|
||||
case 1 -> InterestMethod.FLAT;
|
||||
default -> InterestMethod.INVALID;
|
||||
};
|
||||
}
|
||||
|
||||
public boolean isDecliningBalance() {
|
||||
return this.value.equals(InterestMethod.DECLINING_BALANCE.getValue());
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/***
|
||||
*
|
||||
* People typically use either of the following settings when defining interest recalculation method:
|
||||
* <ul>
|
||||
* <li>NONE</li>
|
||||
* <li>INTEREST</li>
|
||||
* <li>FEE</li>
|
||||
* <li>INTEREST_AND_FEE</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum InterestRecalculationCompoundingMethod {
|
||||
|
||||
NONE(0, "interestRecalculationCompoundingMethod.none"), //
|
||||
INTEREST(1, "interestRecalculationCompoundingMethod.interest"), //
|
||||
FEE(2, "interestRecalculationCompoundingMethod.fee"), //
|
||||
INTEREST_AND_FEE(3, "interestRecalculationCompoundingMethod.interest.and.fee");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private static final Map<Integer, InterestRecalculationCompoundingMethod> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final InterestRecalculationCompoundingMethod type : InterestRecalculationCompoundingMethod.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static InterestRecalculationCompoundingMethod fromInt(final Integer ruleTypeValue) {
|
||||
return intToEnumMap.get(ruleTypeValue);
|
||||
}
|
||||
|
||||
InterestRecalculationCompoundingMethod(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public boolean isFeeCompoundingEnabled() {
|
||||
return this.getValue().equals(InterestRecalculationCompoundingMethod.FEE.getValue())
|
||||
|| this.getValue().equals(InterestRecalculationCompoundingMethod.INTEREST_AND_FEE.getValue());
|
||||
}
|
||||
|
||||
public boolean isCompoundingEnabled() {
|
||||
return !this.getValue().equals(InterestRecalculationCompoundingMethod.NONE.getValue());
|
||||
}
|
||||
|
||||
public boolean isInterestCompoundingEnabled() {
|
||||
return this.getValue().equals(InterestRecalculationCompoundingMethod.INTEREST.getValue())
|
||||
|| this.getValue().equals(InterestRecalculationCompoundingMethod.INTEREST_AND_FEE.getValue());
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum LoanPreClosureInterestCalculationStrategy {
|
||||
|
||||
NONE(0, "loanPreClosureInterestCalculationStrategy.none"), //
|
||||
TILL_PRE_CLOSURE_DATE(1, "loanPreClosureInterestCalculationStrategy.tillPreClosureDate"), //
|
||||
TILL_REST_FREQUENCY_DATE(2, "loanPreClosureInterestCalculationStrategy.tillRestFrequencyDate");
|
||||
|
||||
// REPAYMENT_PERIOD_DATE(3,
|
||||
// "loanPreClosureInterestCalculationStrategy.repaymentPeriodDate")
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private static final Map<Integer, LoanPreClosureInterestCalculationStrategy> intToEnumMap = new HashMap<>();
|
||||
private static int minValue;
|
||||
private static int maxValue;
|
||||
|
||||
static {
|
||||
int i = 0;
|
||||
for (final LoanPreClosureInterestCalculationStrategy type : LoanPreClosureInterestCalculationStrategy.values()) {
|
||||
if (i == 0) {
|
||||
minValue = type.value;
|
||||
}
|
||||
intToEnumMap.put(type.value, type);
|
||||
if (minValue >= type.value) {
|
||||
minValue = type.value;
|
||||
}
|
||||
if (maxValue < type.value) {
|
||||
maxValue = type.value;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static LoanPreClosureInterestCalculationStrategy fromInt(final Integer ruleTypeValue) {
|
||||
return intToEnumMap.get(ruleTypeValue);
|
||||
}
|
||||
|
||||
LoanPreClosureInterestCalculationStrategy(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static int getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
public static int getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
public boolean calculateTillRestFrequencyEnabled() {
|
||||
return this.getValue().equals(LoanPreClosureInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE.getValue());
|
||||
}
|
||||
|
||||
public boolean calculateTillPreClosureDateEnabled() {
|
||||
return this.getValue().equals(LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue());
|
||||
}
|
||||
}
|
||||
+1612
File diff suppressed because it is too large
Load Diff
+120
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_product_loan_variations_borrower_cycle")
|
||||
public class LoanProductBorrowerCycleVariations extends AbstractPersistableCustom {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "loan_product_id", nullable = false)
|
||||
private LoanProduct loanProduct;
|
||||
|
||||
@Column(name = "borrower_cycle_number", nullable = false)
|
||||
private Integer borrowerCycleNumber;
|
||||
|
||||
@Column(name = "param_type", nullable = false)
|
||||
private Integer paramType;
|
||||
|
||||
@Column(name = "value_condition", nullable = false)
|
||||
private Integer valueConditionType;
|
||||
|
||||
@Column(name = "min_value", scale = 6, precision = 19)
|
||||
private BigDecimal minValue;
|
||||
|
||||
@Column(name = "max_value", scale = 6, precision = 19)
|
||||
private BigDecimal maxValue;
|
||||
|
||||
@Column(name = "default_value", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal defaultValue;
|
||||
|
||||
protected LoanProductBorrowerCycleVariations() {}
|
||||
|
||||
public LoanProductBorrowerCycleVariations(final Integer borrowerCycleNumber, final Integer paramType, final Integer valueConditionType,
|
||||
final BigDecimal minValue, final BigDecimal maxValue, final BigDecimal defaultValue) {
|
||||
this.borrowerCycleNumber = borrowerCycleNumber;
|
||||
this.paramType = paramType;
|
||||
this.valueConditionType = valueConditionType;
|
||||
this.minValue = minValue;
|
||||
this.maxValue = maxValue;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public void updateLoanProduct(final LoanProduct loanProduct) {
|
||||
this.loanProduct = loanProduct;
|
||||
}
|
||||
|
||||
public LoanProductParamType getParamType() {
|
||||
return LoanProductParamType.fromInt(this.paramType);
|
||||
}
|
||||
|
||||
public LoanProductValueConditionType getValueConditionType() {
|
||||
return LoanProductValueConditionType.fromInt(this.valueConditionType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof LoanProductBorrowerCycleVariations)) {
|
||||
return false;
|
||||
}
|
||||
final LoanProductBorrowerCycleVariations other = (LoanProductBorrowerCycleVariations) obj;
|
||||
return Objects.equals(loanProduct, other.loanProduct) && Objects.equals(borrowerCycleNumber, other.borrowerCycleNumber)
|
||||
&& Objects.equals(paramType, other.paramType) && Objects.equals(valueConditionType, other.valueConditionType)
|
||||
&& Objects.equals(minValue, other.minValue) && Objects.equals(maxValue, other.maxValue)
|
||||
&& Objects.equals(defaultValue, other.defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(loanProduct, borrowerCycleNumber, paramType, valueConditionType, minValue, maxValue, defaultValue);
|
||||
}
|
||||
|
||||
public void copy(final LoanProductBorrowerCycleVariations borrowerCycleVariations) {
|
||||
this.defaultValue = borrowerCycleVariations.defaultValue;
|
||||
this.minValue = borrowerCycleVariations.minValue;
|
||||
this.maxValue = borrowerCycleVariations.maxValue;
|
||||
this.valueConditionType = borrowerCycleVariations.valueConditionType;
|
||||
this.borrowerCycleNumber = borrowerCycleVariations.borrowerCycleNumber;
|
||||
}
|
||||
|
||||
public Integer getBorrowerCycleNumber() {
|
||||
return this.borrowerCycleNumber;
|
||||
}
|
||||
|
||||
public BigDecimal getMinValue() {
|
||||
return this.minValue;
|
||||
}
|
||||
|
||||
public BigDecimal getMaxValue() {
|
||||
return this.maxValue;
|
||||
}
|
||||
|
||||
public BigDecimal getDefaultValue() {
|
||||
return this.defaultValue;
|
||||
}
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_product_loan_configurable_attributes")
|
||||
public class LoanProductConfigurableAttributes extends AbstractPersistableCustom implements Serializable {
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "loan_product_id", nullable = false)
|
||||
private LoanProduct loanProduct;
|
||||
|
||||
@Column(name = "amortization_method_enum")
|
||||
private Boolean amortizationType;
|
||||
|
||||
@Column(name = "interest_method_enum")
|
||||
private Boolean interestType;
|
||||
|
||||
@Column(name = "loan_transaction_strategy_code")
|
||||
private Boolean transactionProcessingStrategyCode;
|
||||
|
||||
@Column(name = "interest_calculated_in_period_enum")
|
||||
private Boolean interestCalculationPeriodType;
|
||||
|
||||
@Column(name = "arrearstolerance_amount")
|
||||
private Boolean inArrearsTolerance;
|
||||
|
||||
@Column(name = "repay_every")
|
||||
private Boolean repaymentEvery;
|
||||
|
||||
@Column(name = "moratorium")
|
||||
private Boolean graceOnPrincipalAndInterestPayment;
|
||||
|
||||
@Column(name = "grace_on_arrears_ageing")
|
||||
private Boolean graceOnArrearsAgeing;
|
||||
|
||||
private static final String[] supportedLoanConfigurableAttributes = { LoanProductConstants.amortizationTypeParamName,
|
||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
|
||||
LoanProductConstants.interestCalculationPeriodTypeParamName, LoanProductConstants.inArrearsToleranceParamName,
|
||||
LoanProductConstants.repaymentEveryParamName, LoanProductConstants.graceOnPrincipalAndInterestPaymentParamName,
|
||||
LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME };
|
||||
|
||||
public static LoanProductConfigurableAttributes createFrom(JsonCommand command) {
|
||||
|
||||
final Boolean amortization = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.amortizationTypeParamName).getAsBoolean();
|
||||
final Boolean interestMethod = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.interestTypeParamName).getAsBoolean();
|
||||
final Boolean transactionProcessingStrategy = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.transactionProcessingStrategyCodeParamName).getAsBoolean();
|
||||
final Boolean interestCalcPeriod = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.interestCalculationPeriodTypeParamName).getAsBoolean();
|
||||
final Boolean arrearsTolerance = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.inArrearsToleranceParamName).getAsBoolean();
|
||||
final Boolean repaymentEvery = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.repaymentEveryParamName).getAsBoolean();
|
||||
final Boolean graceOnPrincipalAndInterestPayment = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.graceOnPrincipalAndInterestPaymentParamName).getAsBoolean();
|
||||
final Boolean graceOnArrearsAging = command.parsedJson().getAsJsonObject()
|
||||
.getAsJsonObject(LoanProductConstants.allowAttributeOverridesParamName)
|
||||
.getAsJsonPrimitive(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME).getAsBoolean();
|
||||
|
||||
return new LoanProductConfigurableAttributes(amortization, interestMethod, transactionProcessingStrategy, interestCalcPeriod,
|
||||
arrearsTolerance, repaymentEvery, graceOnPrincipalAndInterestPayment, graceOnArrearsAging);
|
||||
}
|
||||
|
||||
public void updateLoanProduct(final LoanProduct loanProduct) {
|
||||
this.loanProduct = loanProduct;
|
||||
}
|
||||
|
||||
public static LoanProductConfigurableAttributes populateDefaultsForConfigurableAttributes() {
|
||||
final Boolean amortization = true;
|
||||
final Boolean interestMethod = true;
|
||||
final Boolean transactionProcessingStrategy = true;
|
||||
final Boolean interestCalcPeriod = true;
|
||||
final Boolean arrearsTolerance = true;
|
||||
final Boolean repaymentEvery = true;
|
||||
final Boolean graceOnPrincipalAndInterestPayment = true;
|
||||
final Boolean graceOnArrearsAging = true;
|
||||
|
||||
return new LoanProductConfigurableAttributes(amortization, interestMethod, transactionProcessingStrategy, interestCalcPeriod,
|
||||
arrearsTolerance, repaymentEvery, graceOnPrincipalAndInterestPayment, graceOnArrearsAging);
|
||||
}
|
||||
|
||||
public LoanProductConfigurableAttributes(Boolean amortization, Boolean interestMethod, Boolean transactionProcessingStrategyCode,
|
||||
Boolean interestCalcPeriod, Boolean arrearsTolerance, Boolean repaymentEvery, Boolean graceOnPrincipalAndInterestPayment,
|
||||
Boolean graceOnArrearsAging) {
|
||||
this.amortizationType = amortization;
|
||||
this.interestType = interestMethod;
|
||||
this.inArrearsTolerance = arrearsTolerance;
|
||||
this.graceOnArrearsAgeing = graceOnArrearsAging;
|
||||
this.interestCalculationPeriodType = interestCalcPeriod;
|
||||
this.graceOnPrincipalAndInterestPayment = graceOnPrincipalAndInterestPayment;
|
||||
this.repaymentEvery = repaymentEvery;
|
||||
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
|
||||
}
|
||||
|
||||
protected LoanProductConfigurableAttributes() {
|
||||
|
||||
}
|
||||
|
||||
public static String[] getAllowedLoanConfigurableAttributes() {
|
||||
return supportedLoanConfigurableAttributes;
|
||||
}
|
||||
|
||||
public LoanProduct getLoanProduct() {
|
||||
return loanProduct;
|
||||
}
|
||||
|
||||
public Boolean getAmortizationBoolean() {
|
||||
return amortizationType;
|
||||
}
|
||||
|
||||
public Boolean getInterestMethodBoolean() {
|
||||
return interestType;
|
||||
}
|
||||
|
||||
public Boolean getTransactionProcessingStrategyBoolean() {
|
||||
return transactionProcessingStrategyCode;
|
||||
}
|
||||
|
||||
public Boolean getInterestCalcPeriodBoolean() {
|
||||
return interestCalculationPeriodType;
|
||||
}
|
||||
|
||||
public Boolean getArrearsToleranceBoolean() {
|
||||
return inArrearsTolerance;
|
||||
}
|
||||
|
||||
public Boolean getRepaymentEveryBoolean() {
|
||||
return repaymentEvery;
|
||||
}
|
||||
|
||||
public Boolean getGraceOnPrincipalAndInterestPaymentBoolean() {
|
||||
return graceOnPrincipalAndInterestPayment;
|
||||
}
|
||||
|
||||
public Boolean getGraceOnArrearsAgingBoolean() {
|
||||
return graceOnArrearsAgeing;
|
||||
}
|
||||
|
||||
public void setLoanProduct(LoanProduct loanProduct) {
|
||||
this.loanProduct = loanProduct;
|
||||
}
|
||||
|
||||
public void setAmortizationType(Boolean amortizationType) {
|
||||
this.amortizationType = amortizationType;
|
||||
}
|
||||
|
||||
public void setInterestType(Boolean interestType) {
|
||||
this.interestType = interestType;
|
||||
}
|
||||
|
||||
public void setTransactionProcessingStrategyCode(Boolean transactionProcessingStrategyCode) {
|
||||
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
|
||||
}
|
||||
|
||||
public void setInterestCalculationPeriodType(Boolean interestCalculationPeriodType) {
|
||||
this.interestCalculationPeriodType = interestCalculationPeriodType;
|
||||
}
|
||||
|
||||
public void setInArrearsTolerance(Boolean inArrearsTolerance) {
|
||||
this.inArrearsTolerance = inArrearsTolerance;
|
||||
}
|
||||
|
||||
public void setRepaymentEvery(Boolean repaymentEvery) {
|
||||
this.repaymentEvery = repaymentEvery;
|
||||
}
|
||||
|
||||
public void setGraceOnPrincipalAndInterestPayment(Boolean graceOnPrincipalAndInterestPayment) {
|
||||
this.graceOnPrincipalAndInterestPayment = graceOnPrincipalAndInterestPayment;
|
||||
}
|
||||
|
||||
public void setGraceOnArrearsAgeing(Boolean graceOnArrearsAgeing) {
|
||||
this.graceOnArrearsAgeing = graceOnArrearsAgeing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof LoanProductConfigurableAttributes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoanProductConfigurableAttributes that = (LoanProductConfigurableAttributes) o;
|
||||
|
||||
return Objects.equals(loanProduct, that.loanProduct) && Objects.equals(amortizationType, that.amortizationType)
|
||||
&& Objects.equals(interestType, that.interestType)
|
||||
&& Objects.equals(transactionProcessingStrategyCode, that.transactionProcessingStrategyCode)
|
||||
&& Objects.equals(interestCalculationPeriodType, that.interestCalculationPeriodType)
|
||||
&& Objects.equals(inArrearsTolerance, that.inArrearsTolerance) && Objects.equals(repaymentEvery, that.repaymentEvery)
|
||||
&& Objects.equals(graceOnPrincipalAndInterestPayment, that.graceOnPrincipalAndInterestPayment)
|
||||
&& Objects.equals(graceOnArrearsAgeing, that.graceOnArrearsAgeing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(loanProduct, amortizationType, interestType, transactionProcessingStrategyCode, interestCalculationPeriodType,
|
||||
inArrearsTolerance, repaymentEvery, graceOnPrincipalAndInterestPayment, graceOnArrearsAgeing);
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_product_loan_floating_rates")
|
||||
public class LoanProductFloatingRates extends AbstractPersistableCustom {
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "loan_product_id", nullable = false)
|
||||
private LoanProduct loanProduct;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "floating_rates_id", nullable = false)
|
||||
private FloatingRate floatingRate;
|
||||
|
||||
@Column(name = "interest_rate_differential", nullable = false)
|
||||
private BigDecimal interestRateDifferential;
|
||||
|
||||
@Column(name = "min_differential_lending_rate", nullable = false)
|
||||
private BigDecimal minDifferentialLendingRate;
|
||||
|
||||
@Column(name = "default_differential_lending_rate", nullable = false)
|
||||
private BigDecimal defaultDifferentialLendingRate;
|
||||
|
||||
@Column(name = "max_differential_lending_rate", nullable = false)
|
||||
private BigDecimal maxDifferentialLendingRate;
|
||||
|
||||
@Column(name = "is_floating_interest_rate_calculation_allowed", nullable = false)
|
||||
private boolean isFloatingInterestRateCalculationAllowed;
|
||||
|
||||
public LoanProductFloatingRates() {
|
||||
|
||||
}
|
||||
|
||||
public LoanProductFloatingRates(FloatingRate floatingRate, LoanProduct loanProduct, BigDecimal interestRateDifferential,
|
||||
BigDecimal minDifferentialLendingRate, BigDecimal maxDifferentialLendingRate, BigDecimal defaultDifferentialLendingRate,
|
||||
boolean isFloatingInterestRateCalculationAllowed) {
|
||||
this.floatingRate = floatingRate;
|
||||
this.loanProduct = loanProduct;
|
||||
this.interestRateDifferential = interestRateDifferential;
|
||||
this.minDifferentialLendingRate = minDifferentialLendingRate;
|
||||
this.maxDifferentialLendingRate = maxDifferentialLendingRate;
|
||||
this.defaultDifferentialLendingRate = defaultDifferentialLendingRate;
|
||||
this.isFloatingInterestRateCalculationAllowed = isFloatingInterestRateCalculationAllowed;
|
||||
}
|
||||
|
||||
public LoanProduct getLoanProduct() {
|
||||
return this.loanProduct;
|
||||
}
|
||||
|
||||
public FloatingRate getFloatingRate() {
|
||||
return this.floatingRate;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestRateDifferential() {
|
||||
return this.interestRateDifferential;
|
||||
}
|
||||
|
||||
public BigDecimal getMinDifferentialLendingRate() {
|
||||
return this.minDifferentialLendingRate;
|
||||
}
|
||||
|
||||
public BigDecimal getDefaultDifferentialLendingRate() {
|
||||
return this.defaultDifferentialLendingRate;
|
||||
}
|
||||
|
||||
public BigDecimal getMaxDifferentialLendingRate() {
|
||||
return this.maxDifferentialLendingRate;
|
||||
}
|
||||
|
||||
public boolean isFloatingInterestRateCalculationAllowed() {
|
||||
return this.isFloatingInterestRateCalculationAllowed;
|
||||
}
|
||||
|
||||
public Map<? extends String, ?> update(JsonCommand command, FloatingRate floatingRate) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(20);
|
||||
if (floatingRate != null) {
|
||||
final String floatingRatesId = "floatingRatesId";
|
||||
if (this.floatingRate == null || command.isChangeInLongParameterNamed(floatingRatesId, this.floatingRate.getId())) {
|
||||
final long newValue = command.longValueOfParameterNamed(floatingRatesId);
|
||||
actualChanges.put(floatingRatesId, newValue);
|
||||
this.floatingRate = floatingRate;
|
||||
}
|
||||
}
|
||||
|
||||
final String interestRateDifferential = "interestRateDifferential";
|
||||
if (command.isChangeInBigDecimalParameterNamed(interestRateDifferential, this.interestRateDifferential)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateDifferential);
|
||||
actualChanges.put(interestRateDifferential, newValue);
|
||||
this.interestRateDifferential = newValue;
|
||||
}
|
||||
final String minDifferentialLendingRate = "minDifferentialLendingRate";
|
||||
if (command.isChangeInBigDecimalParameterNamed(minDifferentialLendingRate, this.minDifferentialLendingRate)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minDifferentialLendingRate);
|
||||
actualChanges.put(minDifferentialLendingRate, newValue);
|
||||
this.minDifferentialLendingRate = newValue;
|
||||
}
|
||||
final String defaultDifferentialLendingRate = "defaultDifferentialLendingRate";
|
||||
if (command.isChangeInBigDecimalParameterNamed(defaultDifferentialLendingRate, this.defaultDifferentialLendingRate)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(defaultDifferentialLendingRate);
|
||||
actualChanges.put(defaultDifferentialLendingRate, newValue);
|
||||
this.defaultDifferentialLendingRate = newValue;
|
||||
}
|
||||
final String maxDifferentialLendingRate = "maxDifferentialLendingRate";
|
||||
if (command.isChangeInBigDecimalParameterNamed(maxDifferentialLendingRate, this.maxDifferentialLendingRate)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxDifferentialLendingRate);
|
||||
actualChanges.put(maxDifferentialLendingRate, newValue);
|
||||
this.maxDifferentialLendingRate = newValue;
|
||||
}
|
||||
final String isFloatingInterestRateCalculationAllowed = "isFloatingInterestRateCalculationAllowed";
|
||||
if (command.isChangeInBooleanParameterNamed(isFloatingInterestRateCalculationAllowed,
|
||||
this.isFloatingInterestRateCalculationAllowed)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isFloatingInterestRateCalculationAllowed);
|
||||
actualChanges.put(isFloatingInterestRateCalculationAllowed, newValue);
|
||||
this.isFloatingInterestRateCalculationAllowed = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public Collection<FloatingRatePeriodData> fetchInterestRates(final FloatingRateDTO floatingRateDTO) {
|
||||
floatingRateDTO.addInterestRateDiff(this.interestRateDifferential);
|
||||
return floatingRate.fetchInterestRates(floatingRateDTO);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
|
||||
/**
|
||||
* Entity for capturing interest recalculation settings
|
||||
*
|
||||
* @author conflux
|
||||
*/
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_product_loan_guarantee_details")
|
||||
public class LoanProductGuaranteeDetails extends AbstractPersistableCustom {
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "loan_product_id", nullable = false)
|
||||
private LoanProduct loanProduct;
|
||||
|
||||
@Column(name = "mandatory_guarantee", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal mandatoryGuarantee;
|
||||
|
||||
@Column(name = "minimum_guarantee_from_own_funds", scale = 6, precision = 19)
|
||||
private BigDecimal minimumGuaranteeFromOwnFunds;
|
||||
|
||||
@Column(name = "minimum_guarantee_from_guarantor_funds", scale = 6, precision = 19)
|
||||
private BigDecimal minimumGuaranteeFromGuarantor;
|
||||
|
||||
protected LoanProductGuaranteeDetails() {
|
||||
//
|
||||
}
|
||||
|
||||
public static LoanProductGuaranteeDetails createFrom(final JsonCommand command) {
|
||||
|
||||
final BigDecimal mandatoryGuarantee = command.bigDecimalValueOfParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName);
|
||||
final BigDecimal minimumGuaranteeFromGuarantor = command
|
||||
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName);
|
||||
final BigDecimal minimumGuaranteeFromOwnFunds = command
|
||||
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName);
|
||||
|
||||
return new LoanProductGuaranteeDetails(mandatoryGuarantee, minimumGuaranteeFromOwnFunds, minimumGuaranteeFromGuarantor);
|
||||
}
|
||||
|
||||
private LoanProductGuaranteeDetails(final BigDecimal mandatoryGuarantee, final BigDecimal minimumGuaranteeFromOwnFunds,
|
||||
final BigDecimal minimumGuaranteeFromGuarantor) {
|
||||
this.mandatoryGuarantee = mandatoryGuarantee;
|
||||
this.minimumGuaranteeFromGuarantor = minimumGuaranteeFromGuarantor;
|
||||
this.minimumGuaranteeFromOwnFunds = minimumGuaranteeFromOwnFunds;
|
||||
}
|
||||
|
||||
public void updateProduct(final LoanProduct loanProduct) {
|
||||
this.loanProduct = loanProduct;
|
||||
}
|
||||
|
||||
public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName, this.mandatoryGuarantee)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.mandatoryGuaranteeParamName);
|
||||
actualChanges.put(LoanProductConstants.mandatoryGuaranteeParamName, newValue);
|
||||
this.mandatoryGuarantee = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||
this.minimumGuaranteeFromGuarantor)) {
|
||||
final BigDecimal newValue = command
|
||||
.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromGuarantorParamName);
|
||||
actualChanges.put(LoanProductConstants.minimumGuaranteeFromGuarantorParamName, newValue);
|
||||
this.minimumGuaranteeFromGuarantor = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
|
||||
this.minimumGuaranteeFromOwnFunds)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName);
|
||||
actualChanges.put(LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, newValue);
|
||||
this.minimumGuaranteeFromOwnFunds = newValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public BigDecimal getMandatoryGuarantee() {
|
||||
return this.mandatoryGuarantee;
|
||||
}
|
||||
|
||||
public BigDecimal getMinimumGuaranteeFromOwnFunds() {
|
||||
return this.minimumGuaranteeFromOwnFunds;
|
||||
}
|
||||
|
||||
public BigDecimal getMinimumGuaranteeFromGuarantor() {
|
||||
return this.minimumGuaranteeFromGuarantor;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user