FINERACT-1932: Fineract modularization - fineract-cob

This commit is contained in:
Jose Alberto Hernandez
2025-07-29 21:46:39 +02:00
committed by Arnold Gálovics
parent e090da2a01
commit 7452ea2552
85 changed files with 458 additions and 130 deletions
+2
View File
@@ -28,6 +28,7 @@ buildscript {
[ [
'fineract-api', 'fineract-api',
'fineract-core', 'fineract-core',
'fineract-cob',
'fineract-validation', 'fineract-validation',
'fineract-command', 'fineract-command',
'fineract-accounting', 'fineract-accounting',
@@ -58,6 +59,7 @@ buildscript {
'fineract-api', 'fineract-api',
'fineract-client', 'fineract-client',
'fineract-core', 'fineract-core',
'fineract-cob',
'fineract-validation', 'fineract-validation',
'fineract-command', 'fineract-command',
'fineract-accounting', 'fineract-accounting',
+1
View File
@@ -19,6 +19,7 @@
dependencies { dependencies {
implementation(project(':fineract-core')) implementation(project(':fineract-core'))
implementation(project(':fineract-cob'))
implementation(project(':fineract-loan')) implementation(project(':fineract-loan'))
implementation(project(':fineract-provider')) implementation(project(':fineract-provider'))
implementation('org.springframework.boot:spring-boot-starter-data-jpa') implementation('org.springframework.boot:spring-boot-starter-data-jpa')
@@ -19,6 +19,7 @@
dependencies { dependencies {
implementation(project(':fineract-core')) implementation(project(':fineract-core'))
implementation(project(':fineract-cob'))
implementation(project(':fineract-loan')) implementation(project(':fineract-loan'))
implementation(project(':fineract-provider')) implementation(project(':fineract-provider'))
implementation(project(':custom:acme:loan:cob')) implementation(project(':custom:acme:loan:cob'))
+76
View File
@@ -0,0 +1,76 @@
/**
* 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 COB'
apply plugin: 'java'
apply plugin: 'eclipse'
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'
compileJava {
dependsOn ':fineract-avro-schemas:buildJavaSdk'
options.compilerArgs += ['-parameters']
}
// 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-cob/bin/main")
}
if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
sourceSets {
test {
java {
exclude '**/core/boot/tests/**'
}
}
}
}
+133
View File
@@ -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.
*/
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(project(path: ':fineract-avro-schemas'))
implementation(project(path: ':fineract-command'))
implementation(project(path: ':fineract-validation'))
implementation(project(path: ':fineract-core'))
// implementation dependencies are directly used (compiled against) in src/main (and src/test)
implementation(
'org.springframework.boot:spring-boot-starter-web',
'org.springframework.boot:spring-boot-starter-security',
'org.springframework.boot:spring-boot-starter-validation',
'org.springframework.boot:spring-boot-starter-batch',
'org.springframework.batch:spring-batch-integration',
'jakarta.ws.rs:jakarta.ws.rs-api',
'org.glassfish.jersey.media:jersey-media-multipart',
'org.apache.avro:avro',
'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-jakarta',
'com.squareup.retrofit2:converter-gson',
'org.springdoc:springdoc-openapi-starter-webmvc-ui',
'org.mapstruct:mapstruct',
'io.github.resilience4j:resilience4j-spring-boot3',
'org.apache.httpcomponents:httpcore',
)
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'
}
implementation('org.springframework.boot:spring-boot-starter-jersey') {
exclude group: 'org.glassfish.hk2.external', module: 'aopalliance-repackaged'
exclude group: 'org.glassfish.hk2', module: 'hk2-runlevel'
exclude group: 'org.hibernate.validator', module: 'hibernate-validator'
exclude group: 'jakarta.activation', module: 'jakarta.activation-api'
}
implementation('org.dom4j:dom4j') {
exclude group: 'javax.xml.bind'
}
implementation ('jakarta.xml.bind:jakarta.xml.bind-api') {
exclude group: 'jakarta.activation'
}
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'
}
runtimeOnly('org.glassfish.jaxb:jaxb-runtime') {
exclude group: 'com.sun.activation'
}
// runtimeOnly dependencies are things that Fineract code has no direct compile time dependency on, but which must be present at run-time
runtimeOnly(
'org.apache.bval:org.apache.bval.bundle',
// Although fineract (at the time of writing) doesn't have any compile time dep. on httpclient,
// it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility
'org.apache.httpcomponents:httpclient'
)
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor'
implementation 'ch.qos.logback.contrib:logback-json-classic'
implementation 'ch.qos.logback.contrib:logback-jackson'
implementation 'org.codehaus.janino:janino'
implementation 'org.apache.commons:commons-math3'
implementation 'io.github.classgraph:classgraph'
// testCompile dependencies are ONLY used in src/test, not src/main.
// Do NOT repeat dependencies which are ALREADY in implementation or runtimeOnly!
//
testImplementation( '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'
}
implementation ('org.mnode.ical4j:ical4j') {
exclude group: 'commons-logging'
exclude group: 'javax.activation'
exclude group: 'com.sun.mail', module: 'javax.mail'
}
implementation ('org.quartz-scheduler:quartz') {
exclude group: 'com.zaxxer', module: 'HikariCP-java7'
}
testImplementation ('org.mockito:mockito-inline')
implementation('org.apache.avro:avro')
implementation(
project(path: ':fineract-avro-schemas')
)
}
@@ -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.cob;
public class COBConstant {
public static final String BUSINESS_STEPS = "businessSteps";
public static final String BUSINESS_DATE_PARAMETER_NAME = "BusinessDate";
public static final String IS_CATCH_UP_PARAMETER_NAME = "IS_CATCH_UP";
public static final String COB_CUSTOM_JOB_PARAMETER_KEY = "CUSTOM_JOB_PARAMETER_ID";
public static final Long NUMBER_OF_DAYS_BEHIND = 1L;
protected COBConstant() {
}
}
@@ -20,7 +20,7 @@ package org.apache.fineract.cob.data;
import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.domain.ExternalId;
public interface LoanIdAndExternalIdAndAccountNo { public interface COBIdAndExternalIdAndAccountNo {
Long getId(); Long getId();
@@ -20,7 +20,7 @@ package org.apache.fineract.cob.data;
import java.time.LocalDate; import java.time.LocalDate;
public interface LoanIdAndLastClosedBusinessDate { public interface COBIdAndLastClosedBusinessDate {
Long getId(); Long getId();
@@ -29,8 +29,8 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@EqualsAndHashCode @EqualsAndHashCode
public class LoanCOBParameter { public class COBParameter {
private Long minLoanId; private Long minAccountId;
private Long maxLoanId; private Long maxAccountId;
} }
@@ -23,7 +23,7 @@ import lombok.Data;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class LoanCOBPartition { public class COBPartition {
private Long minId; private Long minId;
private Long maxId; private Long maxId;
@@ -18,13 +18,13 @@
*/ */
package org.apache.fineract.cob.exceptions; package org.apache.fineract.cob.exceptions;
public class LoanAccountLockCannotBeOverruledException extends RuntimeException { public class AccountLockCannotBeOverruledException extends RuntimeException {
public LoanAccountLockCannotBeOverruledException(String message) { public AccountLockCannotBeOverruledException(String message) {
super(message); super(message);
} }
public LoanAccountLockCannotBeOverruledException(String message, Exception e) { public AccountLockCannotBeOverruledException(String message, Exception e) {
super(message, e); super(message, e);
} }
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.apache.fineract.infrastructure.core.exceptionmapper; package org.apache.fineract.core.exceptionmapper;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.apache.fineract.infrastructure.core.exceptionmapper; package org.apache.fineract.core.exceptionmapper;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<!-- This file is only used for static weaving, nothing more. -->
<!-- You can find the runtime configuration in the JPAConfig class -->
<persistence-unit name="jpa-pu" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- Core Module Entities -->
<class>org.apache.fineract.useradministration.domain.Role</class>
<class>org.apache.fineract.portfolio.fund.domain.Fund</class>
<class>org.apache.fineract.infrastructure.documentmanagement.domain.Image</class>
<class>org.apache.fineract.organisation.workingdays.domain.WorkingDays</class>
<class>org.apache.fineract.useradministration.domain.Permission</class>
<class>org.apache.fineract.useradministration.domain.AppUserClientMapping</class>
<class>org.apache.fineract.commands.domain.CommandSource</class>
<class>org.apache.fineract.useradministration.domain.AppUser</class>
<class>org.apache.fineract.accounting.glaccount.domain.GLAccount</class>
<class>org.apache.fineract.organisation.monetary.domain.OrganisationCurrency</class>
<class>org.apache.fineract.organisation.staff.domain.Staff</class>
<class>org.apache.fineract.portfolio.rate.domain.Rate</class>
<class>org.apache.fineract.organisation.monetary.domain.ApplicationCurrency</class>
<class>org.apache.fineract.portfolio.calendar.domain.CalendarInstance</class>
<class>org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail</class>
<class>org.apache.fineract.portfolio.calendar.domain.Calendar</class>
<class>org.apache.fineract.portfolio.calendar.domain.CalendarHistory</class>
<class>org.apache.fineract.portfolio.client.domain.ClientIdentifier</class>
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket</class>
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange</class>
<class>org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory</class>
<class>org.apache.fineract.portfolio.group.domain.Group</class>
<class>org.apache.fineract.portfolio.client.domain.Client</class>
<class>org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEventConfiguration</class>
<class>org.apache.fineract.portfolio.group.domain.GroupRole</class>
<class>org.apache.fineract.portfolio.paymenttype.domain.PaymentType</class>
<class>org.apache.fineract.portfolio.group.domain.GroupLevel</class>
<class>org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEvent</class>
<class>org.apache.fineract.organisation.office.domain.Office</class>
<class>org.apache.fineract.organisation.holiday.domain.Holiday</class>
<class>org.apache.fineract.infrastructure.cache.domain.PlatformCache</class>
<class>org.apache.fineract.infrastructure.codes.domain.Code</class>
<class>org.apache.fineract.infrastructure.businessdate.domain.BusinessDate</class>
<class>org.apache.fineract.infrastructure.codes.domain.CodeValue</class>
<!-- Command Module Entities -->
<class>org.apache.fineract.command.persistence.domain.CommandEntity</class>
<class>org.apache.fineract.command.persistence.converter.JsonAttributeConverter</class>
<!-- Validation Module Entities -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.weaving" value="static" />
</properties>
</persistence-unit>
</persistence>
@@ -9,7 +9,7 @@ It is very easy to add your own business steps to Fineract's default steps:
.Business Step Interface .Business Step Interface
[source,java] [source,java]
---- ----
include::{rootdir}/fineract-core/src/main/java/org/apache/fineract/cob/COBBusinessStep.java[lines=19..] include::{rootdir}/fineract-cob/src/main/java/org/apache/fineract/cob/COBBusinessStep.java[lines=19..]
---- ----
== Business Step Implementation == Business Step Implementation
+1
View File
@@ -25,6 +25,7 @@ dependencies {
// implementation dependencies are directly used (compiled against) in src/main (and src/test) // implementation dependencies are directly used (compiled against) in src/main (and src/test)
// //
implementation(project(path: ':fineract-core')) implementation(project(path: ':fineract-core'))
implementation(project(path: ':fineract-cob'))
implementation(project(path: ':fineract-accounting')) implementation(project(path: ':fineract-accounting'))
implementation(project(path: ':fineract-charge')) implementation(project(path: ':fineract-charge'))
implementation(project(path: ':fineract-loan')) implementation(project(path: ':fineract-loan'))
+1
View File
@@ -25,6 +25,7 @@ dependencies {
// implementation dependencies are directly used (compiled against) in src/main (and src/test) // implementation dependencies are directly used (compiled against) in src/main (and src/test)
// //
implementation(project(path: ':fineract-core')) implementation(project(path: ':fineract-core'))
implementation(project(path: ':fineract-cob'))
implementation(project(path: ':fineract-accounting')) implementation(project(path: ':fineract-accounting'))
implementation(project(path: ':fineract-charge')) implementation(project(path: ':fineract-charge'))
implementation(project(path: ':fineract-rates')) implementation(project(path: ':fineract-rates'))
@@ -23,7 +23,7 @@ import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider; import jakarta.ws.rs.ext.Provider;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException; import org.apache.fineract.cob.exceptions.AccountLockCannotBeOverruledException;
import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.exception.ErrorHandler; import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -31,10 +31,10 @@ import org.springframework.stereotype.Component;
@Provider @Provider
@Component @Component
@Slf4j @Slf4j
public class LoanAccountLockCannotBeOverruledExceptionMapper implements ExceptionMapper<LoanAccountLockCannotBeOverruledException> { public class LoanAccountLockCannotBeOverruledExceptionMapper implements ExceptionMapper<AccountLockCannotBeOverruledException> {
@Override @Override
public Response toResponse(LoanAccountLockCannotBeOverruledException exception) { public Response toResponse(AccountLockCannotBeOverruledException exception) {
final String globalisationMessageCode = "error.msg.invalid.request.body"; final String globalisationMessageCode = "error.msg.invalid.request.body";
final String defaultUserMessage = exception.getMessage(); final String defaultUserMessage = exception.getMessage();
log.warn("Exception occurred", ErrorHandler.findMostSpecificException(exception)); log.warn("Exception occurred", ErrorHandler.findMostSpecificException(exception));
@@ -23,9 +23,9 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.apache.fineract.accounting.common.AccountingRuleType; import org.apache.fineract.accounting.common.AccountingRuleType;
import org.apache.fineract.cob.data.COBIdAndExternalIdAndAccountNo;
import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.data.LoanDataForExternalTransfer; import org.apache.fineract.cob.data.LoanDataForExternalTransfer;
import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.portfolio.accountdetails.domain.AccountType; import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
@@ -230,11 +230,11 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
List<Long> findIdsByExternalIds(@Param("externalIds") List<ExternalId> externalIds); List<Long> findIdsByExternalIds(@Param("externalIds") List<ExternalId> externalIds);
@Query(FIND_ALL_LOANS_BEHIND_BY_LOAN_IDS_AND_STATUSES) @Query(FIND_ALL_LOANS_BEHIND_BY_LOAN_IDS_AND_STATUSES)
List<LoanIdAndLastClosedBusinessDate> findAllLoansBehindByLoanIdsAndStatuses(@Param("cobBusinessDate") LocalDate cobBusinessDate, List<COBIdAndLastClosedBusinessDate> findAllLoansBehindByLoanIdsAndStatuses(@Param("cobBusinessDate") LocalDate cobBusinessDate,
@Param("loanIds") List<Long> loanIds, @Param("loanStatuses") Collection<LoanStatus> loanStatuses); @Param("loanIds") List<Long> loanIds, @Param("loanStatuses") Collection<LoanStatus> loanStatuses);
@Query(FIND_ALL_LOANS_BEHIND_OR_NULL_BY_LOAN_IDS_AND_STATUSES) @Query(FIND_ALL_LOANS_BEHIND_OR_NULL_BY_LOAN_IDS_AND_STATUSES)
List<LoanIdAndLastClosedBusinessDate> findAllLoansBehindOrNullByLoanIdsAndStatuses(@Param("cobBusinessDate") LocalDate cobBusinessDate, List<COBIdAndLastClosedBusinessDate> findAllLoansBehindOrNullByLoanIdsAndStatuses(@Param("cobBusinessDate") LocalDate cobBusinessDate,
@Param("loanIds") List<Long> loanIds, @Param("loanStatuses") Collection<LoanStatus> loanStatuses); @Param("loanIds") List<Long> loanIds, @Param("loanStatuses") Collection<LoanStatus> loanStatuses);
@Query(FIND_ALL_LOANS_BY_LAST_CLOSED_BUSINESS_DATE_AND_MIN_AND_MAX_LOAN_ID_AND_STATUSES) @Query(FIND_ALL_LOANS_BY_LAST_CLOSED_BUSINESS_DATE_AND_MIN_AND_MAX_LOAN_ID_AND_STATUSES)
@@ -248,11 +248,11 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
@Param("loanStatuses") Collection<LoanStatus> loanStatuses); @Param("loanStatuses") Collection<LoanStatus> loanStatuses);
@Query(FIND_OLDEST_COB_PROCESSED_LOAN) @Query(FIND_OLDEST_COB_PROCESSED_LOAN)
List<LoanIdAndLastClosedBusinessDate> findOldestCOBProcessedLoan(@Param("cobBusinessDate") LocalDate cobBusinessDate, List<COBIdAndLastClosedBusinessDate> findOldestCOBProcessedLoan(@Param("cobBusinessDate") LocalDate cobBusinessDate,
@Param("loanStatuses") Collection<LoanStatus> loanStatuses); @Param("loanStatuses") Collection<LoanStatus> loanStatuses);
@Query(FIND_ALL_STAYED_LOCKED_BY_COB_BUSINESS_DATE) @Query(FIND_ALL_STAYED_LOCKED_BY_COB_BUSINESS_DATE)
List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(@Param("cobBusinessDate") LocalDate cobBusinessDate); List<COBIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(@Param("cobBusinessDate") LocalDate cobBusinessDate);
@Query(FIND_ALL_LOAN_IDS_BY_STATUS) @Query(FIND_ALL_LOAN_IDS_BY_STATUS)
List<Long> findLoanIdByStatus(@Param("loanStatus") LoanStatus loanStatus); List<Long> findLoanIdByStatus(@Param("loanStatus") LoanStatus loanStatus);
+1
View File
@@ -25,6 +25,7 @@ dependencies {
} }
implementation(project(path: ':fineract-core')) implementation(project(path: ':fineract-core'))
implementation(project(path: ':fineract-cob'))
implementation(project(path: ':fineract-command')) implementation(project(path: ':fineract-command'))
implementation(project(path: ':fineract-validation')) implementation(project(path: ':fineract-validation'))
implementation(project(path: ':fineract-accounting')) implementation(project(path: ':fineract-accounting'))
@@ -35,7 +35,7 @@ import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.data.LoanCOBPartition; import org.apache.fineract.cob.data.COBPartition;
import org.apache.fineract.cob.loan.LoanCOBConstant; import org.apache.fineract.cob.loan.LoanCOBConstant;
import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.cob.loan.RetrieveLoanIdService;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
@@ -85,7 +85,7 @@ public class InternalCOBApiResource implements InitializingBean {
public String getCobPartitions(@Context final UriInfo uriInfo, @PathParam("partitionSize") int partitionSize) { public String getCobPartitions(@Context final UriInfo uriInfo, @PathParam("partitionSize") int partitionSize) {
LocalDate businessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.BUSINESS_DATE); LocalDate businessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.BUSINESS_DATE);
log.info("RetrieveLoanCOBPartitions is called with partitionSize {} for {}", partitionSize, businessDate); log.info("RetrieveLoanCOBPartitions is called with partitionSize {} for {}", partitionSize, businessDate);
List<LoanCOBPartition> loanCOBPartitions = retrieveLoanIdService.retrieveLoanCOBPartitions(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND, List<COBPartition> loanCOBPartitions = retrieveLoanIdService.retrieveLoanCOBPartitions(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND,
businessDate, false, partitionSize); businessDate, false, partitionSize);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return toApiJsonSerializerForList.serialize(settings, loanCOBPartitions); return toApiJsonSerializerForList.serialize(settings, loanCOBPartitions);
@@ -29,7 +29,7 @@ import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.common.CustomJobParameterResolver; import org.apache.fineract.cob.common.CustomJobParameterResolver;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock; import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LockOwner; import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.cob.exceptions.LoanLockCannotBeAppliedException; import org.apache.fineract.cob.exceptions.LoanLockCannotBeAppliedException;
@@ -61,11 +61,11 @@ public class ApplyLoanLockTasklet implements Tasklet {
throws LoanLockCannotBeAppliedException { throws LoanLockCannotBeAppliedException {
ExecutionContext executionContext = contribution.getStepExecution().getExecutionContext(); ExecutionContext executionContext = contribution.getStepExecution().getExecutionContext();
long numberOfExecutions = contribution.getStepExecution().getCommitCount(); long numberOfExecutions = contribution.getStepExecution().getCommitCount();
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER); COBParameter loanCOBParameter = (COBParameter) executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER);
List<Long> loanIds; List<Long> loanIds;
if (Objects.isNull(loanCOBParameter) if (Objects.isNull(loanCOBParameter)
|| (Objects.isNull(loanCOBParameter.getMinLoanId()) && Objects.isNull(loanCOBParameter.getMaxLoanId())) || (Objects.isNull(loanCOBParameter.getMinAccountId()) && Objects.isNull(loanCOBParameter.getMaxAccountId()))
|| (loanCOBParameter.getMinLoanId().equals(0L) && loanCOBParameter.getMaxLoanId().equals(0L))) { || (loanCOBParameter.getMinAccountId().equals(0L) && loanCOBParameter.getMaxAccountId().equals(0L))) {
loanIds = Collections.emptyList(); loanIds = Collections.emptyList();
} else { } else {
loanIds = new ArrayList<>( loanIds = new ArrayList<>(
@@ -18,24 +18,20 @@
*/ */
package org.apache.fineract.cob.loan; package org.apache.fineract.cob.loan;
public final class LoanCOBConstant { import org.apache.fineract.cob.COBConstant;
public final class LoanCOBConstant extends COBConstant {
public static final String JOB_NAME = "LOAN_COB"; public static final String JOB_NAME = "LOAN_COB";
public static final String JOB_HUMAN_READABLE_NAME = "Loan COB"; public static final String JOB_HUMAN_READABLE_NAME = "Loan COB";
public static final String LOAN_COB_JOB_NAME = "LOAN_CLOSE_OF_BUSINESS"; public static final String LOAN_COB_JOB_NAME = "LOAN_CLOSE_OF_BUSINESS";
public static final String LOAN_COB_PARAMETER = "loanCobParameter"; public static final String LOAN_COB_PARAMETER = "loanCobParameter";
public static final String BUSINESS_STEPS = "businessSteps";
public static final String LOAN_COB_WORKER_STEP = "loanCOBWorkerStep"; public static final String LOAN_COB_WORKER_STEP = "loanCOBWorkerStep";
public static final String INLINE_LOAN_COB_JOB_NAME = "INLINE_LOAN_COB"; public static final String INLINE_LOAN_COB_JOB_NAME = "INLINE_LOAN_COB";
public static final String BUSINESS_DATE_PARAMETER_NAME = "BusinessDate";
public static final String IS_CATCH_UP_PARAMETER_NAME = "IS_CATCH_UP";
public static final String LOAN_IDS_PARAMETER_NAME = "LoanIds"; public static final String LOAN_IDS_PARAMETER_NAME = "LoanIds";
public static final String LOAN_COB_PARTITIONER_STEP = "Loan COB partition - Step"; public static final String LOAN_COB_PARTITIONER_STEP = "Loan COB partition - Step";
public static final String LOAN_COB_CUSTOM_JOB_PARAMETER_KEY = "CUSTOM_JOB_PARAMETER_ID";
public static final Long NUMBER_OF_DAYS_BEHIND = 1L;
private LoanCOBConstant() { private LoanCOBConstant() {
@@ -29,8 +29,8 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.COBBusinessStepService; import org.apache.fineract.cob.COBBusinessStepService;
import org.apache.fineract.cob.data.BusinessStepNameAndOrder; import org.apache.fineract.cob.data.BusinessStepNameAndOrder;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.data.LoanCOBPartition; import org.apache.fineract.cob.data.COBPartition;
import org.apache.fineract.infrastructure.jobs.service.JobName; import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.springbatch.PropertyService; import org.apache.fineract.infrastructure.springbatch.PropertyService;
import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecution;
@@ -81,13 +81,13 @@ public class LoanCOBPartitioner implements Partitioner {
} }
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
sw.start(); sw.start();
List<LoanCOBPartition> loanCOBPartitions = new ArrayList<>( List<COBPartition> loanCOBPartitions = new ArrayList<>(
retrieveLoanIdService.retrieveLoanCOBPartitions(numberOfDays, businessDate, isCatchUp != null && isCatchUp, partitionSize)); retrieveLoanIdService.retrieveLoanCOBPartitions(numberOfDays, businessDate, isCatchUp != null && isCatchUp, partitionSize));
sw.stop(); sw.stop();
// if there is no loan to be closed, we still would like to create at least one partition // if there is no loan to be closed, we still would like to create at least one partition
if (loanCOBPartitions.size() == 0) { if (loanCOBPartitions.size() == 0) {
loanCOBPartitions.add(new LoanCOBPartition(0L, 0L, 1L, 0L)); loanCOBPartitions.add(new COBPartition(0L, 0L, 1L, 0L));
} }
log.info( log.info(
"LoanCOBPartitioner found {} loans to be processed as part of COB. {} partitions were created using partition size {}. RetrieveLoanCOBPartitions was executed in {} ms.", "LoanCOBPartitioner found {} loans to be processed as part of COB. {} partitions were created using partition size {}. RetrieveLoanCOBPartitions was executed in {} ms.",
@@ -96,15 +96,15 @@ public class LoanCOBPartitioner implements Partitioner {
.collect(Collectors.toMap(l -> PARTITION_PREFIX + l.getPageNo(), l -> createNewPartition(cobBusinessSteps, l))); .collect(Collectors.toMap(l -> PARTITION_PREFIX + l.getPageNo(), l -> createNewPartition(cobBusinessSteps, l)));
} }
private long getLoanCount(List<LoanCOBPartition> loanCOBPartitions) { private long getLoanCount(List<COBPartition> loanCOBPartitions) {
return loanCOBPartitions.stream().map(LoanCOBPartition::getCount).reduce(0L, Long::sum); return loanCOBPartitions.stream().map(COBPartition::getCount).reduce(0L, Long::sum);
} }
private ExecutionContext createNewPartition(Set<BusinessStepNameAndOrder> cobBusinessSteps, LoanCOBPartition loanCOBPartition) { private ExecutionContext createNewPartition(Set<BusinessStepNameAndOrder> cobBusinessSteps, COBPartition loanCOBPartition) {
ExecutionContext executionContext = new ExecutionContext(); ExecutionContext executionContext = new ExecutionContext();
executionContext.put(LoanCOBConstant.BUSINESS_STEPS, cobBusinessSteps); executionContext.put(LoanCOBConstant.BUSINESS_STEPS, cobBusinessSteps);
executionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, executionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER,
new LoanCOBParameter(loanCOBPartition.getMinId(), loanCOBPartition.getMaxId())); new COBParameter(loanCOBPartition.getMinId(), loanCOBPartition.getMaxId()));
executionContext.put("partition", PARTITION_PREFIX + loanCOBPartition.getPageNo()); executionContext.put("partition", PARTITION_PREFIX + loanCOBPartition.getPageNo());
return executionContext; return executionContext;
} }
@@ -25,7 +25,7 @@ import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.common.CustomJobParameterResolver; import org.apache.fineract.cob.common.CustomJobParameterResolver;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock; import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LockOwner; import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
@@ -53,11 +53,11 @@ public class LoanItemReader extends AbstractLoanItemReader {
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
public void beforeStep(@NonNull StepExecution stepExecution) { public void beforeStep(@NonNull StepExecution stepExecution) {
ExecutionContext executionContext = stepExecution.getExecutionContext(); ExecutionContext executionContext = stepExecution.getExecutionContext();
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER); COBParameter loanCOBParameter = (COBParameter) executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER);
List<Long> loanIds; List<Long> loanIds;
if (Objects.isNull(loanCOBParameter) if (Objects.isNull(loanCOBParameter)
|| (Objects.isNull(loanCOBParameter.getMinLoanId()) && Objects.isNull(loanCOBParameter.getMaxLoanId())) || (Objects.isNull(loanCOBParameter.getMinAccountId()) && Objects.isNull(loanCOBParameter.getMaxAccountId()))
|| (loanCOBParameter.getMinLoanId().equals(0L) && loanCOBParameter.getMaxLoanId().equals(0L))) { || (loanCOBParameter.getMinAccountId().equals(0L) && loanCOBParameter.getMaxAccountId().equals(0L))) {
loanIds = Collections.emptyList(); loanIds = Collections.emptyList();
} else { } else {
loanIds = retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, loanIds = retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter,
@@ -26,10 +26,10 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBIdAndExternalIdAndAccountNo;
import org.apache.fineract.cob.data.LoanCOBPartition; import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate; import org.apache.fineract.cob.data.COBPartition;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
@@ -49,8 +49,7 @@ public class RetrieveAllNonClosedLoanIdServiceImpl implements RetrieveLoanIdServ
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Override @Override
public List<LoanCOBPartition> retrieveLoanCOBPartitions(Long numberOfDays, LocalDate businessDate, boolean isCatchUp, public List<COBPartition> retrieveLoanCOBPartitions(Long numberOfDays, LocalDate businessDate, boolean isCatchUp, int partitionSize) {
int partitionSize) {
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
sql.append("select min(id) as min, max(id) as max, page, count(id) as count from "); sql.append("select min(id) as min, max(id) as max, page, count(id) as count from ");
sql.append(" (select floor(((row_number() over(order by id))-1) / :pageSize) as page, t.* from "); sql.append(" (select floor(((row_number() over(order by id))-1) / :pageSize) as page, t.* from ");
@@ -71,43 +70,43 @@ public class RetrieveAllNonClosedLoanIdServiceImpl implements RetrieveLoanIdServ
return namedParameterJdbcTemplate.query(sql.toString(), parameters, RetrieveAllNonClosedLoanIdServiceImpl::mapRow); return namedParameterJdbcTemplate.query(sql.toString(), parameters, RetrieveAllNonClosedLoanIdServiceImpl::mapRow);
} }
private static LoanCOBPartition mapRow(ResultSet rs, int rowNum) throws SQLException { private static COBPartition mapRow(ResultSet rs, int rowNum) throws SQLException {
return new LoanCOBPartition(rs.getLong("min"), rs.getLong("max"), rs.getLong("page"), rs.getLong("count")); return new COBPartition(rs.getLong("min"), rs.getLong("max"), rs.getLong("page"), rs.getLong("count"));
} }
@Override @Override
public List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDate(LocalDate businessDate, List<Long> loanIds) { public List<COBIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDate(LocalDate businessDate, List<Long> loanIds) {
return loanRepository.findAllLoansBehindByLoanIdsAndStatuses(businessDate, loanIds, NON_CLOSED_LOAN_STATUSES); return loanRepository.findAllLoansBehindByLoanIdsAndStatuses(businessDate, loanIds, NON_CLOSED_LOAN_STATUSES);
} }
@Override @Override
public List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDateOrNull(LocalDate businessDate, List<Long> loanIds) { public List<COBIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDateOrNull(LocalDate businessDate, List<Long> loanIds) {
return loanRepository.findAllLoansBehindOrNullByLoanIdsAndStatuses(businessDate, loanIds, NON_CLOSED_LOAN_STATUSES); return loanRepository.findAllLoansBehindOrNullByLoanIdsAndStatuses(businessDate, loanIds, NON_CLOSED_LOAN_STATUSES);
} }
@Override @Override
public List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsOldestCobProcessed(LocalDate businessDate) { public List<COBIdAndLastClosedBusinessDate> retrieveLoanIdsOldestCobProcessed(LocalDate businessDate) {
return loanRepository.findOldestCOBProcessedLoan(businessDate, NON_CLOSED_LOAN_STATUSES); return loanRepository.findOldestCOBProcessedLoan(businessDate, NON_CLOSED_LOAN_STATUSES);
} }
@Override @Override
public List<Long> retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(LoanCOBParameter loanCOBParameter, public List<Long> retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(COBParameter loanCOBParameter,
boolean isCatchUp) { boolean isCatchUp) {
if (isCatchUp) { if (isCatchUp) {
return loanRepository.findAllLoansByLastClosedBusinessDateNotNullAndMinAndMaxLoanIdAndStatuses( return loanRepository.findAllLoansByLastClosedBusinessDateNotNullAndMinAndMaxLoanIdAndStatuses(
loanCOBParameter.getMinLoanId(), loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil loanCOBParameter.getMinAccountId(), loanCOBParameter.getMaxAccountId(), ThreadLocalContextUtil
.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND), .getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND),
NON_CLOSED_LOAN_STATUSES); NON_CLOSED_LOAN_STATUSES);
} else { } else {
return loanRepository.findAllLoansByLastClosedBusinessDateAndMinAndMaxLoanIdAndStatuses( return loanRepository.findAllLoansByLastClosedBusinessDateAndMinAndMaxLoanIdAndStatuses(
loanCOBParameter.getMinLoanId(), loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil loanCOBParameter.getMinAccountId(), loanCOBParameter.getMaxAccountId(), ThreadLocalContextUtil
.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND), .getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND),
NON_CLOSED_LOAN_STATUSES); NON_CLOSED_LOAN_STATUSES);
} }
} }
@Override @Override
public List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(LocalDate cobBusinessDate) { public List<COBIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(LocalDate cobBusinessDate) {
return loanRepository.findAllStayedLockedByCobBusinessDate(cobBusinessDate); return loanRepository.findAllStayedLockedByCobBusinessDate(cobBusinessDate);
} }
@@ -20,24 +20,24 @@ package org.apache.fineract.cob.loan;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBIdAndExternalIdAndAccountNo;
import org.apache.fineract.cob.data.LoanCOBPartition; import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate; import org.apache.fineract.cob.data.COBPartition;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
public interface RetrieveLoanIdService { public interface RetrieveLoanIdService {
List<LoanCOBPartition> retrieveLoanCOBPartitions(Long numberOfDays, LocalDate businessDate, boolean isCatchUp, int partitionSize); List<COBPartition> retrieveLoanCOBPartitions(Long numberOfDays, LocalDate businessDate, boolean isCatchUp, int partitionSize);
List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDate(LocalDate businessDate, List<Long> loanIds); List<COBIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDate(LocalDate businessDate, List<Long> loanIds);
List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDateOrNull(LocalDate businessDate, List<Long> loanIds); List<COBIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDateOrNull(LocalDate businessDate, List<Long> loanIds);
List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsOldestCobProcessed(LocalDate businessDate); List<COBIdAndLastClosedBusinessDate> retrieveLoanIdsOldestCobProcessed(LocalDate businessDate);
List<Long> retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(LoanCOBParameter loanCOBParameter, boolean isCatchUp); List<Long> retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(COBParameter loanCOBParameter, boolean isCatchUp);
List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(@Param("cobBusinessDate") LocalDate cobBusinessDate); List<COBIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(@Param("cobBusinessDate") LocalDate cobBusinessDate);
} }
@@ -23,9 +23,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.data.COBIdAndExternalIdAndAccountNo;
import org.apache.fineract.cob.data.LoanAccountStayedLockedData; import org.apache.fineract.cob.data.LoanAccountStayedLockedData;
import org.apache.fineract.cob.data.LoanAccountsStayedLockedData; import org.apache.fineract.cob.data.LoanAccountsStayedLockedData;
import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
@@ -52,7 +52,7 @@ public class StayedLockedLoansTasklet implements Tasklet {
private LoanAccountsStayedLockedData buildLoanAccountData() { private LoanAccountsStayedLockedData buildLoanAccountData() {
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE); LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
List<LoanIdAndExternalIdAndAccountNo> stayedLockedLoanAccounts = retrieveLoanIdService List<COBIdAndExternalIdAndAccountNo> stayedLockedLoanAccounts = retrieveLoanIdService
.findAllStayedLockedByCobBusinessDate(cobBusinessDate); .findAllStayedLockedByCobBusinessDate(cobBusinessDate);
List<LoanAccountStayedLockedData> loanAccounts = new ArrayList<>(); List<LoanAccountStayedLockedData> loanAccounts = new ArrayList<>();
stayedLockedLoanAccounts.forEach(loanAccount -> { stayedLockedLoanAccounts.forEach(loanAccount -> {
@@ -27,7 +27,7 @@ import java.util.Set;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition; import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate; import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.loan.LoanCOBConstant; import org.apache.fineract.cob.loan.LoanCOBConstant;
import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.cob.loan.RetrieveLoanIdService;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
@@ -70,7 +70,7 @@ public class AsyncLoanCOBExecutorServiceImpl implements AsyncLoanCOBExecutorServ
try { try {
ThreadLocalContextUtil.init(context); ThreadLocalContextUtil.init(context);
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE); LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
List<LoanIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDate = retrieveLoanIdService List<COBIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDate = retrieveLoanIdService
.retrieveLoanIdsOldestCobProcessed(cobBusinessDate); .retrieveLoanIdsOldestCobProcessed(cobBusinessDate);
LocalDate oldestCOBProcessedDate = !loanIdAndLastClosedBusinessDate.isEmpty() LocalDate oldestCOBProcessedDate = !loanIdAndLastClosedBusinessDate.isEmpty()
@@ -37,11 +37,11 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition; import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate; import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.domain.LoanAccountLock; import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LoanAccountLockRepository; import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner; import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException; import org.apache.fineract.cob.exceptions.AccountLockCannotBeOverruledException;
import org.apache.fineract.cob.loan.LoanCOBConstant; import org.apache.fineract.cob.loan.LoanCOBConstant;
import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.cob.loan.RetrieveLoanIdService;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
@@ -101,7 +101,7 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
@Override @Override
@Transactional(propagation = Propagation.NOT_SUPPORTED) @Transactional(propagation = Propagation.NOT_SUPPORTED)
public CommandProcessingResult executeInlineJob(JsonCommand command, String jobName) throws LoanAccountLockCannotBeOverruledException { public CommandProcessingResult executeInlineJob(JsonCommand command, String jobName) throws AccountLockCannotBeOverruledException {
List<Long> loanIds = dataParser.parseExecution(command); List<Long> loanIds = dataParser.parseExecution(command);
validateLoanIdsListSize(loanIds); validateLoanIdsListSize(loanIds);
execute(loanIds, jobName); execute(loanIds, jobName);
@@ -111,7 +111,7 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
@Override @Override
public void execute(List<Long> loanIds, String jobName) { public void execute(List<Long> loanIds, String jobName) {
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE); LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
List<LoanIdAndLastClosedBusinessDate> loansToBeProcessed = getLoansToBeProcessed(loanIds, cobBusinessDate); List<COBIdAndLastClosedBusinessDate> loansToBeProcessed = getLoansToBeProcessed(loanIds, cobBusinessDate);
LocalDate executingBusinessDate = getOldestCOBBusinessDate(loansToBeProcessed).plusDays(1); LocalDate executingBusinessDate = getOldestCOBBusinessDate(loansToBeProcessed).plusDays(1);
if (!loansToBeProcessed.isEmpty()) { if (!loansToBeProcessed.isEmpty()) {
while (!DateUtils.isAfter(executingBusinessDate, cobBusinessDate)) { while (!DateUtils.isAfter(executingBusinessDate, cobBusinessDate)) {
@@ -121,7 +121,7 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
} }
} }
private List<Long> getLoanIdsToBeProcessed(List<LoanIdAndLastClosedBusinessDate> loansToBeProcessed, LocalDate executingBusinessDate) { private List<Long> getLoanIdsToBeProcessed(List<COBIdAndLastClosedBusinessDate> loansToBeProcessed, LocalDate executingBusinessDate) {
List<Long> loanIdsToBeProcessed = new ArrayList<>(); List<Long> loanIdsToBeProcessed = new ArrayList<>();
loansToBeProcessed.forEach(loan -> { loansToBeProcessed.forEach(loan -> {
if (loan.getLastClosedBusinessDate() != null) { if (loan.getLastClosedBusinessDate() != null) {
@@ -159,16 +159,16 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
} }
} }
private LocalDate getOldestCOBBusinessDate(List<LoanIdAndLastClosedBusinessDate> loans) { private LocalDate getOldestCOBBusinessDate(List<COBIdAndLastClosedBusinessDate> loans) {
LoanIdAndLastClosedBusinessDate oldestLoan = loans.stream().min(Comparator COBIdAndLastClosedBusinessDate oldestLoan = loans.stream().min(Comparator
.comparing(LoanIdAndLastClosedBusinessDate::getLastClosedBusinessDate, Comparator.nullsLast(Comparator.naturalOrder()))) .comparing(COBIdAndLastClosedBusinessDate::getLastClosedBusinessDate, Comparator.nullsLast(Comparator.naturalOrder())))
.orElse(null); .orElse(null);
return oldestLoan != null && oldestLoan.getLastClosedBusinessDate() != null ? oldestLoan.getLastClosedBusinessDate() return oldestLoan != null && oldestLoan.getLastClosedBusinessDate() != null ? oldestLoan.getLastClosedBusinessDate()
: ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(1); : ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(1);
} }
private List<LoanIdAndLastClosedBusinessDate> getLoansToBeProcessed(List<Long> loanIds, LocalDate cobBusinessDate) { private List<COBIdAndLastClosedBusinessDate> getLoansToBeProcessed(List<Long> loanIds, LocalDate cobBusinessDate) {
List<LoanIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDates = new ArrayList<>(); List<COBIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDates = new ArrayList<>();
List<List<Long>> partitions = Lists.partition(loanIds, fineractProperties.getQuery().getInClauseParameterSizeLimit()); List<List<Long>> partitions = Lists.partition(loanIds, fineractProperties.getQuery().getInClauseParameterSizeLimit());
partitions.forEach(partition -> loanIdAndLastClosedBusinessDates partitions.forEach(partition -> loanIdAndLastClosedBusinessDates
.addAll(retrieveLoanIdService.retrieveLoanIdsBehindDateOrNull(cobBusinessDate, partition))); .addAll(retrieveLoanIdService.retrieveLoanIdsBehindDateOrNull(cobBusinessDate, partition)));
@@ -194,7 +194,7 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
if (!alreadyLockedLoanIds.isEmpty()) { if (!alreadyLockedLoanIds.isEmpty()) {
String message = "There is a hard lock on the loan account without any error, so it can't be overruled."; String message = "There is a hard lock on the loan account without any error, so it can't be overruled.";
String loanIdsMessage = " Locked loan IDs: " + alreadyLockedLoanIds; String loanIdsMessage = " Locked loan IDs: " + alreadyLockedLoanIds;
throw new LoanAccountLockCannotBeOverruledException(message + loanIdsMessage); throw new AccountLockCannotBeOverruledException(message + loanIdsMessage);
} }
return loanAccountLocks; return loanAccountLocks;
@@ -229,7 +229,7 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
loanAccountLockRepository.saveAndFlush(loanAccountLock); loanAccountLockRepository.saveAndFlush(loanAccountLock);
} catch (Exception e) { } catch (Exception e) {
log.error("Error updating lock on loan account. Locked loan ID: {}", loanAccountLock.getLoanId(), e); log.error("Error updating lock on loan account. Locked loan ID: {}", loanAccountLock.getLoanId(), e);
throw new LoanAccountLockCannotBeOverruledException( throw new AccountLockCannotBeOverruledException(
"Error updating lock on loan account. Locked loan ID: %s".formatted(loanAccountLock.getLoanId()), e); "Error updating lock on loan account. Locked loan ID: %s".formatted(loanAccountLock.getLoanId()), e);
} }
}); });
@@ -24,7 +24,7 @@ import org.apache.fineract.cob.loan.LoanCOBBusinessStep;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class BusinessStepCategoryServiceImpl implements BusinessStepCategoryService { public class LoanBusinessStepCategoryServiceImpl implements BusinessStepCategoryService {
private static final Map<BusinessStepCategory, Class<? extends COBBusinessStep>> businessSteps = Map.of(BusinessStepCategory.LOAN, private static final Map<BusinessStepCategory, Class<? extends COBBusinessStep>> businessSteps = Map.of(BusinessStepCategory.LOAN,
LoanCOBBusinessStep.class); LoanCOBBusinessStep.class);
@@ -22,8 +22,8 @@ import java.time.LocalDate;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition; import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition;
import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.data.IsCatchUpRunningDTO; import org.apache.fineract.cob.data.IsCatchUpRunningDTO;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO; import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
import org.apache.fineract.cob.loan.LoanCOBConstant; import org.apache.fineract.cob.loan.LoanCOBConstant;
import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.cob.loan.RetrieveLoanIdService;
@@ -51,13 +51,13 @@ public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService {
@Override @Override
public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() { public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
List<LoanIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDate = retrieveLoanIdService List<COBIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDate = retrieveLoanIdService
.retrieveLoanIdsOldestCobProcessed(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)); .retrieveLoanIdsOldestCobProcessed(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO(); OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
oldestCOBProcessedLoanDTO.setLoanIds(loanIdAndLastClosedBusinessDate.stream().map(LoanIdAndLastClosedBusinessDate::getId).toList()); oldestCOBProcessedLoanDTO.setLoanIds(loanIdAndLastClosedBusinessDate.stream().map(COBIdAndLastClosedBusinessDate::getId).toList());
oldestCOBProcessedLoanDTO.setCobProcessedDate( oldestCOBProcessedLoanDTO
loanIdAndLastClosedBusinessDate.stream().map(LoanIdAndLastClosedBusinessDate::getLastClosedBusinessDate).findFirst() .setCobProcessedDate(loanIdAndLastClosedBusinessDate.stream().map(COBIdAndLastClosedBusinessDate::getLastClosedBusinessDate)
.orElse(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE))); .findFirst().orElse(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)));
oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)); oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
return oldestCOBProcessedLoanDTO; return oldestCOBProcessedLoanDTO;
} }
@@ -71,8 +71,8 @@ public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService {
@Override @Override
public IsCatchUpRunningDTO isCatchUpRunning() { public IsCatchUpRunningDTO isCatchUpRunning() {
LocalDate runningCatchUpBusinessDate = jobExecutionRepository.getBusinessDateOfRunningJobByExecutionParameter( LocalDate runningCatchUpBusinessDate = jobExecutionRepository.getBusinessDateOfRunningJobByExecutionParameter(
LoanCOBConstant.JOB_NAME, LoanCOBConstant.LOAN_COB_CUSTOM_JOB_PARAMETER_KEY, LoanCOBConstant.IS_CATCH_UP_PARAMETER_NAME, LoanCOBConstant.JOB_NAME, LoanCOBConstant.COB_CUSTOM_JOB_PARAMETER_KEY, LoanCOBConstant.IS_CATCH_UP_PARAMETER_NAME, "true",
"true", LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME); LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME);
return new IsCatchUpRunningDTO(runningCatchUpBusinessDate != null, runningCatchUpBusinessDate); return new IsCatchUpRunningDTO(runningCatchUpBusinessDate != null, runningCatchUpBusinessDate);
} }
} }
@@ -39,7 +39,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.batch.domain.BatchRequest; import org.apache.fineract.batch.domain.BatchRequest;
import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition; import org.apache.fineract.cob.conditions.LoanCOBEnabledCondition;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate; import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.cob.loan.RetrieveLoanIdService;
import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl; import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl;
import org.apache.fineract.cob.service.LoanAccountLockService; import org.apache.fineract.cob.service.LoanAccountLockService;
@@ -195,7 +195,7 @@ public class LoanCOBFilterHelper implements InitializingBean {
} }
public boolean isLoanBehind(List<Long> loanIds) { public boolean isLoanBehind(List<Long> loanIds) {
List<LoanIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDates = new ArrayList<>(); List<COBIdAndLastClosedBusinessDate> loanIdAndLastClosedBusinessDates = new ArrayList<>();
List<List<Long>> partitions = Lists.partition(loanIds, fineractProperties.getQuery().getInClauseParameterSizeLimit()); List<List<Long>> partitions = Lists.partition(loanIds, fineractProperties.getQuery().getInClauseParameterSizeLimit());
partitions.forEach(partition -> loanIdAndLastClosedBusinessDates.addAll(retrieveLoanIdService partitions.forEach(partition -> loanIdAndLastClosedBusinessDates.addAll(retrieveLoanIdService
.retrieveLoanIdsBehindDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE), partition))); .retrieveLoanIdsBehindDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE), partition)));
@@ -52,7 +52,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException; import org.apache.fineract.cob.exceptions.AccountLockCannotBeOverruledException;
import org.apache.fineract.cob.service.LoanAccountLockService; import org.apache.fineract.cob.service.LoanAccountLockService;
import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
@@ -1904,7 +1904,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
} }
if (!lockedLoanIds.isEmpty()) { if (!lockedLoanIds.isEmpty()) {
throw new LoanAccountLockCannotBeOverruledException("There are hard-lcoked loan accounts: " + lockedLoanIds); throw new AccountLockCannotBeOverruledException("There are hard-lcoked loan accounts: " + lockedLoanIds);
} }
this.loanRepositoryWrapper.flush(); this.loanRepositoryWrapper.flush();
@@ -34,7 +34,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.apache.fineract.cob.common.CustomJobParameterResolver; import org.apache.fineract.cob.common.CustomJobParameterResolver;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock; import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LockOwner; import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.cob.exceptions.LoanLockCannotBeAppliedException; import org.apache.fineract.cob.exceptions.LoanLockCannotBeAppliedException;
@@ -76,7 +76,7 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
ThreadLocalContextUtil.setBusinessDates(businessDateMap); ThreadLocalContextUtil.setBusinessDates(businessDateMap);
StepExecution stepExecution = new StepExecution("test", null); StepExecution stepExecution = new StepExecution("test", null);
ExecutionContext executionContext = new ExecutionContext(); ExecutionContext executionContext = new ExecutionContext();
LoanCOBParameter loanCOBParameter = new LoanCOBParameter(1L, 4L); COBParameter loanCOBParameter = new COBParameter(1L, 4L);
executionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, loanCOBParameter); executionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, loanCOBParameter);
lenient().when( lenient().when(
retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false)) retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false))
@@ -28,8 +28,8 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.fineract.cob.COBBusinessStepService; import org.apache.fineract.cob.COBBusinessStepService;
import org.apache.fineract.cob.data.BusinessStepNameAndOrder; import org.apache.fineract.cob.data.BusinessStepNameAndOrder;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.data.LoanCOBPartition; import org.apache.fineract.cob.data.COBPartition;
import org.apache.fineract.infrastructure.jobs.service.JobName; import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.springbatch.PropertyService; import org.apache.fineract.infrastructure.springbatch.PropertyService;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
@@ -68,7 +68,7 @@ class LoanCOBPartitionerTest {
when(cobBusinessStepService.getCOBBusinessSteps(LoanCOBBusinessStep.class, LoanCOBConstant.LOAN_COB_JOB_NAME)) when(cobBusinessStepService.getCOBBusinessSteps(LoanCOBBusinessStep.class, LoanCOBConstant.LOAN_COB_JOB_NAME))
.thenReturn(BUSINESS_STEP_SET); .thenReturn(BUSINESS_STEP_SET);
when(retrieveLoanIdService.retrieveLoanCOBPartitions(1L, BUSINESS_DATE, false, 5)) when(retrieveLoanIdService.retrieveLoanCOBPartitions(1L, BUSINESS_DATE, false, 5))
.thenReturn(List.of(new LoanCOBPartition(1L,10L, 1L, 5L), new LoanCOBPartition(11L,20L, 2L, 4L))); .thenReturn(List.of(new COBPartition(1L,10L, 1L, 5L), new COBPartition(11L,20L, 2L, 4L)));
LoanCOBPartitioner loanCOBPartitioner = new LoanCOBPartitioner(propertyService, cobBusinessStepService, retrieveLoanIdService, jobOperator, jobExplorer, 1L); LoanCOBPartitioner loanCOBPartitioner = new LoanCOBPartitioner(propertyService, cobBusinessStepService, retrieveLoanIdService, jobOperator, jobExplorer, 1L);
loanCOBPartitioner.setBusinessDate(BUSINESS_DATE); loanCOBPartitioner.setBusinessDate(BUSINESS_DATE);
loanCOBPartitioner.setIsCatchUp(false); loanCOBPartitioner.setIsCatchUp(false);
@@ -128,7 +128,7 @@ class LoanCOBPartitionerTest {
private void validatePartitions(Map<String, ExecutionContext> partitions, int index, long min, long max) { private void validatePartitions(Map<String, ExecutionContext> partitions, int index, long min, long max) {
Assertions.assertEquals(BUSINESS_STEP_SET, Assertions.assertEquals(BUSINESS_STEP_SET,
partitions.get(LoanCOBPartitioner.PARTITION_PREFIX + index).get(LoanCOBConstant.BUSINESS_STEPS)); partitions.get(LoanCOBPartitioner.PARTITION_PREFIX + index).get(LoanCOBConstant.BUSINESS_STEPS));
Assertions.assertEquals(new LoanCOBParameter(min, max), Assertions.assertEquals(new COBParameter(min, max),
partitions.get(LoanCOBPartitioner.PARTITION_PREFIX + index).get(LoanCOBConstant.LOAN_COB_PARAMETER)); partitions.get(LoanCOBPartitioner.PARTITION_PREFIX + index).get(LoanCOBConstant.LOAN_COB_PARAMETER));
Assertions.assertEquals("partition_" + index, partitions.get(LoanCOBPartitioner.PARTITION_PREFIX + index).get("partition")); Assertions.assertEquals("partition_" + index, partitions.get(LoanCOBPartitioner.PARTITION_PREFIX + index).get("partition"));
} }
@@ -36,7 +36,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.fineract.cob.common.CustomJobParameterResolver; import org.apache.fineract.cob.common.CustomJobParameterResolver;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock; import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LockOwner; import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.cob.exceptions.LoanReadException; import org.apache.fineract.cob.exceptions.LoanReadException;
@@ -82,7 +82,7 @@ public class LoanItemReaderStepDefinitions implements En {
minLoanId = splitAccounts.get(0); minLoanId = splitAccounts.get(0);
maxLoanId = splitAccounts.get(splitAccounts.size() - 1); maxLoanId = splitAccounts.get(splitAccounts.size() - 1);
} }
LoanCOBParameter loanCOBParameter = new LoanCOBParameter(minLoanId, maxLoanId); COBParameter loanCOBParameter = new COBParameter(minLoanId, maxLoanId);
stepExecutionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, loanCOBParameter); stepExecutionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, loanCOBParameter);
stepExecution.setExecutionContext(stepExecutionContext); stepExecution.setExecutionContext(stepExecutionContext);
@@ -33,7 +33,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import org.apache.fineract.cob.common.CustomJobParameterResolver; import org.apache.fineract.cob.common.CustomJobParameterResolver;
import org.apache.fineract.cob.data.LoanCOBParameter; import org.apache.fineract.cob.data.COBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock; import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LockOwner; import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
@@ -86,7 +86,7 @@ class LoanItemReaderTest {
LoanItemReader loanItemReader = new LoanItemReader(loanRepository, retrieveLoanIdService, customJobParameterResolver, LoanItemReader loanItemReader = new LoanItemReader(loanRepository, retrieveLoanIdService, customJobParameterResolver,
loanLockingService); loanLockingService);
when(stepExecution.getExecutionContext()).thenReturn(executionContext); when(stepExecution.getExecutionContext()).thenReturn(executionContext);
LoanCOBParameter loanCOBParameter = new LoanCOBParameter(1L, 5L); COBParameter loanCOBParameter = new COBParameter(1L, 5L);
when(executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER)).thenReturn(loanCOBParameter); when(executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER)).thenReturn(loanCOBParameter);
when(retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false)) when(retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false))
.thenReturn(new ArrayList<>(List.of(1L, 2L, 3L, 4L, 5L))); .thenReturn(new ArrayList<>(List.of(1L, 2L, 3L, 4L, 5L)));
@@ -114,7 +114,7 @@ class LoanItemReaderTest {
LoanItemReader loanItemReader = new LoanItemReader(loanRepository, retrieveLoanIdService, customJobParameterResolver, LoanItemReader loanItemReader = new LoanItemReader(loanRepository, retrieveLoanIdService, customJobParameterResolver,
loanLockingService); loanLockingService);
when(stepExecution.getExecutionContext()).thenReturn(executionContext); when(stepExecution.getExecutionContext()).thenReturn(executionContext);
LoanCOBParameter loanCOBParameter = new LoanCOBParameter(1L, 5L); COBParameter loanCOBParameter = new COBParameter(1L, 5L);
when(executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER)).thenReturn(loanCOBParameter); when(executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER)).thenReturn(loanCOBParameter);
when(retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false)) when(retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false))
.thenReturn(new ArrayList<>(List.of())); .thenReturn(new ArrayList<>(List.of()));
@@ -135,7 +135,7 @@ class LoanItemReaderTest {
LoanItemReader loanItemReader = new LoanItemReader(loanRepository, retrieveLoanIdService, customJobParameterResolver, LoanItemReader loanItemReader = new LoanItemReader(loanRepository, retrieveLoanIdService, customJobParameterResolver,
loanLockingService); loanLockingService);
when(stepExecution.getExecutionContext()).thenReturn(executionContext); when(stepExecution.getExecutionContext()).thenReturn(executionContext);
LoanCOBParameter loanCOBParameter = new LoanCOBParameter(1L, 100L); COBParameter loanCOBParameter = new COBParameter(1L, 100L);
when(executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER)).thenReturn(loanCOBParameter); when(executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER)).thenReturn(loanCOBParameter);
when(retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false)) when(retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter, false))
.thenReturn(new ArrayList<>(IntStream.rangeClosed(1, 100).boxed().map(Long::valueOf).toList())); .thenReturn(new ArrayList<>(IntStream.rangeClosed(1, 100).boxed().map(Long::valueOf).toList()));
@@ -22,7 +22,7 @@ import static org.mockito.Mockito.times;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import org.apache.fineract.cob.data.LoanCOBPartition; import org.apache.fineract.cob.data.COBPartition;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -48,7 +48,7 @@ public class RetrieveAllNonClosedLoanIdServiceImplTest {
@Captor @Captor
private ArgumentCaptor<SqlParameterSource> paramsCaptor; private ArgumentCaptor<SqlParameterSource> paramsCaptor;
@Captor @Captor
private ArgumentCaptor<RowMapper<LoanCOBPartition>> rowMapper; private ArgumentCaptor<RowMapper<COBPartition>> rowMapper;
@Test @Test
public void testRetrieveLoanCOBPartitionsNoCatchup() { public void testRetrieveLoanCOBPartitionsNoCatchup() {
@@ -34,8 +34,8 @@ import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate; import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.exceptions.LoanAccountLockCannotBeOverruledException; import org.apache.fineract.cob.exceptions.AccountLockCannotBeOverruledException;
import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.cob.loan.RetrieveLoanIdService;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -82,7 +82,7 @@ class InlineLoanCOBExecutorServiceImplTest {
@Test @Test
void shouldExceptionThrownIfLoanIsAlreadyLocked() { void shouldExceptionThrownIfLoanIsAlreadyLocked() {
JsonCommand command = mock(JsonCommand.class); JsonCommand command = mock(JsonCommand.class);
LoanIdAndLastClosedBusinessDate loan = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate loan = mock(COBIdAndLastClosedBusinessDate.class);
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>(); HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>();
LocalDate businessDate = LocalDate.now(ZoneId.systemDefault()); LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
@@ -90,7 +90,7 @@ class InlineLoanCOBExecutorServiceImplTest {
businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1)); businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1));
ThreadLocalContextUtil.setBusinessDates(businessDates); ThreadLocalContextUtil.setBusinessDates(businessDates);
when(transactionTemplate.execute(any())).thenThrow(new LoanAccountLockCannotBeOverruledException("")); when(transactionTemplate.execute(any())).thenThrow(new AccountLockCannotBeOverruledException(""));
when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties); when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
when(fineractProperties.getApi()).thenReturn(fineractApiProperties); when(fineractProperties.getApi()).thenReturn(fineractApiProperties);
when(dataParser.parseExecution(any())).thenReturn(List.of(1L)); when(dataParser.parseExecution(any())).thenReturn(List.of(1L));
@@ -98,15 +98,15 @@ class InlineLoanCOBExecutorServiceImplTest {
when(fineractApiProperties.getBodyItemSizeLimit()).thenReturn(fineractBodyItemSizeLimitProperties); when(fineractApiProperties.getBodyItemSizeLimit()).thenReturn(fineractBodyItemSizeLimitProperties);
when(fineractBodyItemSizeLimitProperties.getInlineLoanCob()).thenReturn(1000); when(fineractBodyItemSizeLimitProperties.getInlineLoanCob()).thenReturn(1000);
when(retrieveLoanIdService.retrieveLoanIdsBehindDateOrNull(any(), anyList())).thenReturn(List.of(loan)); when(retrieveLoanIdService.retrieveLoanIdsBehindDateOrNull(any(), anyList())).thenReturn(List.of(loan));
assertThrows(LoanAccountLockCannotBeOverruledException.class, () -> testObj.executeInlineJob(command, "INLINE_LOAN_COB")); assertThrows(AccountLockCannotBeOverruledException.class, () -> testObj.executeInlineJob(command, "INLINE_LOAN_COB"));
} }
@Test @Test
void shouldListBePartitioned() { void shouldListBePartitioned() {
JsonCommand command = mock(JsonCommand.class); JsonCommand command = mock(JsonCommand.class);
LoanIdAndLastClosedBusinessDate loan1 = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate loan1 = mock(COBIdAndLastClosedBusinessDate.class);
LoanIdAndLastClosedBusinessDate loan2 = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate loan2 = mock(COBIdAndLastClosedBusinessDate.class);
LoanIdAndLastClosedBusinessDate loan3 = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate loan3 = mock(COBIdAndLastClosedBusinessDate.class);
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>(); HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>();
LocalDate businessDate = LocalDate.now(ZoneId.systemDefault()); LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
@@ -114,7 +114,7 @@ class InlineLoanCOBExecutorServiceImplTest {
businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1)); businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1));
ThreadLocalContextUtil.setBusinessDates(businessDates); ThreadLocalContextUtil.setBusinessDates(businessDates);
when(transactionTemplate.execute(any())).thenThrow(new LoanAccountLockCannotBeOverruledException("")); when(transactionTemplate.execute(any())).thenThrow(new AccountLockCannotBeOverruledException(""));
when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties); when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
when(fineractProperties.getApi()).thenReturn(fineractApiProperties); when(fineractProperties.getApi()).thenReturn(fineractApiProperties);
when(dataParser.parseExecution(any())).thenReturn(List.of(1L, 2L, 3L)); when(dataParser.parseExecution(any())).thenReturn(List.of(1L, 2L, 3L));
@@ -122,16 +122,16 @@ class InlineLoanCOBExecutorServiceImplTest {
when(fineractApiProperties.getBodyItemSizeLimit()).thenReturn(fineractBodyItemSizeLimitProperties); when(fineractApiProperties.getBodyItemSizeLimit()).thenReturn(fineractBodyItemSizeLimitProperties);
when(fineractBodyItemSizeLimitProperties.getInlineLoanCob()).thenReturn(1000); when(fineractBodyItemSizeLimitProperties.getInlineLoanCob()).thenReturn(1000);
when(retrieveLoanIdService.retrieveLoanIdsBehindDateOrNull(any(), anyList())).thenReturn(List.of(loan1, loan2, loan3)); when(retrieveLoanIdService.retrieveLoanIdsBehindDateOrNull(any(), anyList())).thenReturn(List.of(loan1, loan2, loan3));
assertThrows(LoanAccountLockCannotBeOverruledException.class, () -> testObj.executeInlineJob(command, "INLINE_LOAN_COB")); assertThrows(AccountLockCannotBeOverruledException.class, () -> testObj.executeInlineJob(command, "INLINE_LOAN_COB"));
verify(retrieveLoanIdService, times(2)).retrieveLoanIdsBehindDateOrNull(any(), anyList()); verify(retrieveLoanIdService, times(2)).retrieveLoanIdsBehindDateOrNull(any(), anyList());
} }
@Test @Test
void shouldOldestCloseBusinessDateReturnWithCorrectDate() void shouldOldestCloseBusinessDateReturnWithCorrectDate()
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
LoanIdAndLastClosedBusinessDate loan1 = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate loan1 = mock(COBIdAndLastClosedBusinessDate.class);
LoanIdAndLastClosedBusinessDate loan2 = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate loan2 = mock(COBIdAndLastClosedBusinessDate.class);
LoanIdAndLastClosedBusinessDate loan3 = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate loan3 = mock(COBIdAndLastClosedBusinessDate.class);
when(loan1.getLastClosedBusinessDate()).thenReturn(null); when(loan1.getLastClosedBusinessDate()).thenReturn(null);
when(loan2.getLastClosedBusinessDate()).thenReturn(LocalDate.of(2023, 1, 10)); when(loan2.getLastClosedBusinessDate()).thenReturn(LocalDate.of(2023, 1, 10));
when(loan3.getLastClosedBusinessDate()).thenReturn(LocalDate.of(2023, 1, 11)); when(loan3.getLastClosedBusinessDate()).thenReturn(LocalDate.of(2023, 1, 11));
@@ -48,7 +48,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate; import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.cob.loan.RetrieveLoanIdService; import org.apache.fineract.cob.loan.RetrieveLoanIdService;
import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl; import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl;
import org.apache.fineract.cob.service.LoanAccountLockService; import org.apache.fineract.cob.service.LoanAccountLockService;
@@ -312,7 +312,7 @@ class LoanCOBApiFilterTest {
businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1)); businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1));
ThreadLocalContextUtil.setBusinessDates(businessDates); ThreadLocalContextUtil.setBusinessDates(businessDates);
LoanIdAndLastClosedBusinessDate result = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate result = mock(COBIdAndLastClosedBusinessDate.class);
given(result.getId()).willReturn(2L); given(result.getId()).willReturn(2L);
given(result.getLastClosedBusinessDate()).willReturn(businessDate.minusDays(2)); given(result.getLastClosedBusinessDate()).willReturn(businessDate.minusDays(2));
given(request.getPathInfo()).willReturn("/v1/loans/2?command=approve"); given(request.getPathInfo()).willReturn("/v1/loans/2?command=approve");
@@ -346,7 +346,7 @@ class LoanCOBApiFilterTest {
businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1)); businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1));
ThreadLocalContextUtil.setBusinessDates(businessDates); ThreadLocalContextUtil.setBusinessDates(businessDates);
LoanIdAndLastClosedBusinessDate result = mock(LoanIdAndLastClosedBusinessDate.class); COBIdAndLastClosedBusinessDate result = mock(COBIdAndLastClosedBusinessDate.class);
given(result.getId()).willReturn(2L); given(result.getId()).willReturn(2L);
given(request.getPathInfo()).willReturn("/v1/loans/2?command=approve"); given(request.getPathInfo()).willReturn("/v1/loans/2?command=approve");
given(request.getMethod()).willReturn(HTTPMethods.POST.value()); given(request.getMethod()).willReturn(HTTPMethods.POST.value());
+1
View File
@@ -25,6 +25,7 @@ dependencies {
// implementation dependencies are directly used (compiled against) in src/main (and src/test) // implementation dependencies are directly used (compiled against) in src/main (and src/test)
// //
implementation(project(path: ':fineract-core')) implementation(project(path: ':fineract-core'))
implementation(project(path: ':fineract-cob'))
implementation(project(path: ':fineract-accounting')) implementation(project(path: ':fineract-accounting'))
implementation(project(path: ':fineract-charge')) implementation(project(path: ':fineract-charge'))
implementation(project(path: ':fineract-rates')) implementation(project(path: ':fineract-rates'))
+1
View File
@@ -48,6 +48,7 @@ buildCache {
rootProject.name='fineract' rootProject.name='fineract'
include ':fineract-core' include ':fineract-core'
include ':fineract-cob'
include ':fineract-validation' include ':fineract-validation'
include ':fineract-command' include ':fineract-command'
include ':fineract-accounting' include ':fineract-accounting'