You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ad...@apache.org on 2023/04/12 13:03:18 UTC
[fineract] branch develop updated: [FINERACT-1678] Exclude loan IDs from execution context
This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new ace078602 [FINERACT-1678] Exclude loan IDs from execution context
ace078602 is described below
commit ace07860240217c24d40c717026446e9b1f990b2
Author: taskain7 <ta...@gmail.com>
AuthorDate: Wed Apr 12 06:55:50 2023 +0200
[FINERACT-1678] Exclude loan IDs from execution context
---
.../LoanCOBParameter.java} | 23 +++--
.../fineract/cob/loan/AbstractLoanItemReader.java | 2 +-
.../fineract/cob/loan/ApplyLoanLockTasklet.java | 18 +++-
.../fineract/cob/loan/FetchAndLockLoanTasklet.java | 112 ---------------------
.../fineract/cob/loan/InlineCOBLoanItemReader.java | 2 +-
.../InlineLoanCOBBuildExecutionContextTasklet.java | 3 +-
.../apache/fineract/cob/loan/LoanCOBConstant.java | 3 +-
.../cob/loan/LoanCOBManagerConfiguration.java | 33 +++---
.../fineract/cob/loan/LoanCOBPartitioner.java | 37 ++++---
.../cob/loan/LoanCOBWorkerConfiguration.java | 2 +-
.../fineract/cob/loan/LoanIdParameterTasklet.java | 56 +++++++++++
.../fineract/cob/loan/LoanInlineCOBConfig.java | 4 +-
.../apache/fineract/cob/loan/LoanItemReader.java | 18 +++-
.../apache/fineract/cob/loan/LockLoanTasklet.java | 78 ++++++++++++++
.../RetrieveAllNonClosedLoanIdServiceImpl.java | 5 +-
.../fineract/cob/loan/RetrieveLoanIdService.java | 3 +-
.../cob/loan/StayedLockedLoansTasklet.java | 3 +-
.../loanaccount/domain/LoanRepository.java | 21 ++--
.../loan/ApplyLoanLockTaskletStepDefinitions.java | 13 ++-
.../cob/loan/FetchAndLockLoanStepDefinitions.java | 109 +++++++++-----------
.../loan/LoanCOBPartitionerStepDefinitions.java | 29 ++++--
.../cob/loan/LoanItemReaderStepDefinitions.java | 33 ++++--
.../features/cob/loan/cob.loan.reader.feature | 1 -
23 files changed, 348 insertions(+), 260 deletions(-)
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveLoanIdService.java b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanCOBParameter.java
similarity index 61%
copy from fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveLoanIdService.java
copy to fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanCOBParameter.java
index f5a9c7b52..b6e2b5ed9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveLoanIdService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/data/LoanCOBParameter.java
@@ -16,18 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.cob.loan;
+package org.apache.fineract.cob.data;
-import java.time.LocalDate;
-import java.util.List;
-import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
-public interface RetrieveLoanIdService {
-
- List<Long> retrieveLoanIdsNDaysBehind(Long numberOfDays, LocalDate businessDate);
-
- List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDateOrNull(LocalDate businessDate, List<Long> loanIds);
-
- List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsOldestCobProcessed(LocalDate businessDate);
+@AllArgsConstructor
+@Getter
+@NoArgsConstructor
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
+public class LoanCOBParameter {
+ private Long minLoanId;
+ private Long maxLoanId;
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/AbstractLoanItemReader.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/AbstractLoanItemReader.java
index 13ca8d34c..c92fdbf8d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/AbstractLoanItemReader.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/AbstractLoanItemReader.java
@@ -37,7 +37,7 @@ import org.springframework.batch.item.ItemReader;
@RequiredArgsConstructor
public abstract class AbstractLoanItemReader implements ItemReader<Loan> {
- private final LoanRepository loanRepository;
+ protected final LoanRepository loanRepository;
@Setter(AccessLevel.PROTECTED)
private List<Long> alreadyLockedOrProcessedAccounts;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyLoanLockTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyLoanLockTasklet.java
index 66049cf9b..06a23060b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyLoanLockTasklet.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/ApplyLoanLockTasklet.java
@@ -20,17 +20,23 @@ package org.apache.fineract.cob.loan;
import com.google.common.collect.Lists;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.jetbrains.annotations.NotNull;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
@@ -46,11 +52,21 @@ public class ApplyLoanLockTasklet implements Tasklet {
private final LoanAccountLockRepository accountLockRepository;
private final FineractProperties fineractProperties;
private final JdbcTemplate jdbcTemplate;
+ private final LoanRepository loanRepository;
@Override
public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception {
ExecutionContext executionContext = contribution.getStepExecution().getExecutionContext();
- List<Long> loanIds = (List<Long>) executionContext.get(LoanCOBConstant.LOAN_IDS);
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ List<Long> loanIds;
+ if (Objects.isNull(loanCOBParameter)
+ || (Objects.isNull(loanCOBParameter.getMinLoanId()) && Objects.isNull(loanCOBParameter.getMaxLoanId()))
+ || (loanCOBParameter.getMinLoanId().equals(0L) && loanCOBParameter.getMaxLoanId().equals(0L))) {
+ loanIds = Collections.emptyList();
+ } else {
+ loanIds = new ArrayList<>(loanRepository.findAllNonClosedLoansBehindOrNullByMinAndMaxLoanId(loanCOBParameter.getMinLoanId(),
+ loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)));
+ }
List<List<Long>> loanIdPartitions = Lists.partition(loanIds, fineractProperties.getQuery().getInClauseParameterSizeLimit());
List<LoanAccountLock> accountLocks = new ArrayList<>();
loanIdPartitions.forEach(loanIdPartition -> accountLocks.addAll(accountLockRepository.findAllByLoanIdIn(loanIdPartition)));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/FetchAndLockLoanTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/FetchAndLockLoanTasklet.java
deleted file mode 100644
index e7c758677..000000000
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/FetchAndLockLoanTasklet.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.cob.loan;
-
-import com.google.common.collect.Lists;
-import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.fineract.cob.domain.LoanAccountLock;
-import org.apache.fineract.cob.domain.LoanAccountLockRepository;
-import org.apache.fineract.cob.domain.LockOwner;
-import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
-import org.apache.fineract.infrastructure.core.config.FineractProperties;
-import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
-import org.jetbrains.annotations.NotNull;
-import org.springframework.batch.core.StepContribution;
-import org.springframework.batch.core.scope.context.ChunkContext;
-import org.springframework.batch.core.step.tasklet.Tasklet;
-import org.springframework.batch.repeat.RepeatStatus;
-import org.springframework.jdbc.core.JdbcTemplate;
-
-@Slf4j
-@RequiredArgsConstructor
-public class FetchAndLockLoanTasklet implements Tasklet {
-
- private static final Long NUMBER_OF_DAYS_BEHIND = 1L;
-
- private final LoanAccountLockRepository loanAccountLockRepository;
-
- private final RetrieveLoanIdService retrieveLoanIdService;
-
- private final FineractProperties fineractProperties;
-
- private final JdbcTemplate jdbcTemplate;
-
- @Override
- public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception {
- String businessDateParameter = (String) contribution.getStepExecution().getJobExecution().getExecutionContext()
- .get(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME);
- LocalDate businessDate = LocalDate.parse(Objects.requireNonNull(businessDateParameter));
- List<Long> allNonClosedLoanIds = retrieveLoanIdService.retrieveLoanIdsNDaysBehind(NUMBER_OF_DAYS_BEHIND, businessDate);
- if (allNonClosedLoanIds.isEmpty()) {
- contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, Collections.emptyList());
- return RepeatStatus.FINISHED;
- }
- List<Long> remainingIds = new ArrayList<>(allNonClosedLoanIds);
-
- List<List<Long>> remainingIdPartitions = Lists.partition(remainingIds, getInClauseParameterSizeLimit());
- List<LoanAccountLock> loanAccountLocks = new ArrayList<>();
- remainingIdPartitions.forEach(
- remainingIdPartition -> loanAccountLocks.addAll(loanAccountLockRepository.findAllByLoanIdIn(remainingIdPartition)));
-
- List<Long> alreadySoftLockedAccounts = loanAccountLocks.stream()
- .filter(e -> LockOwner.LOAN_COB_PARTITIONING.equals(e.getLockOwner())).map(LoanAccountLock::getLoanId).toList();
- List<Long> alreadyMarkedForInlineCOBLockedAccounts = loanAccountLocks.stream()
- .filter(e -> LockOwner.LOAN_INLINE_COB_PROCESSING.equals(e.getLockOwner())).map(LoanAccountLock::getLoanId).toList();
- List<Long> alreadyMarkedForChunkProcessingLockedAccounts = loanAccountLocks.stream()
- .filter(e -> LockOwner.LOAN_COB_CHUNK_PROCESSING.equals(e.getLockOwner())).map(LoanAccountLock::getLoanId).toList();
-
- // Remove already hard locked accounts
- remainingIds.removeAll(alreadyMarkedForChunkProcessingLockedAccounts);
- remainingIds.removeAll(alreadyMarkedForInlineCOBLockedAccounts);
-
- List<Long> lockableLoanAccounts = new ArrayList<>(remainingIds);
- lockableLoanAccounts.removeAll(alreadySoftLockedAccounts);
-
- applySoftLock(lockableLoanAccounts);
-
- contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, remainingIds);
-
- return RepeatStatus.FINISHED;
- }
-
- private void applySoftLock(List<Long> accountsToLock) {
- LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
- jdbcTemplate.batchUpdate("""
- INSERT INTO m_loan_account_locks (loan_id, version, lock_owner, lock_placed_on, lock_placed_on_cob_business_date)
- VALUES (?, ?, ?, ?, ?)
- """, accountsToLock, getInClauseParameterSizeLimit(), (ps, id) -> {
- ps.setLong(1, id);
- ps.setLong(2, 1);
- ps.setString(3, LockOwner.LOAN_COB_PARTITIONING.name());
- ps.setObject(4, DateUtils.getOffsetDateTimeOfTenant());
- ps.setObject(5, cobBusinessDate);
- });
- }
-
- private int getInClauseParameterSizeLimit() {
- return fineractProperties.getQuery().getInClauseParameterSizeLimit();
- }
-}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineCOBLoanItemReader.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineCOBLoanItemReader.java
index 4da7b1398..deaa9aaee 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineCOBLoanItemReader.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineCOBLoanItemReader.java
@@ -36,7 +36,7 @@ public class InlineCOBLoanItemReader extends AbstractLoanItemReader {
@SuppressWarnings({ "unchecked" })
public void beforeStep(@NotNull StepExecution stepExecution) {
ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
- List<Long> loanIds = (List<Long>) executionContext.get(LoanCOBConstant.LOAN_IDS);
+ List<Long> loanIds = (List<Long>) executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER);
setRemainingData(new ArrayList<>(loanIds));
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java
index 276d7c702..3eb01ef41 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java
@@ -58,7 +58,8 @@ public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet {
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
Set<BusinessStepNameAndOrder> cobBusinessSteps = cobBusinessStepService.getCOBBusinessSteps(LoanCOBBusinessStep.class,
LoanCOBConstant.LOAN_COB_JOB_NAME);
- contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext));
+ contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
+ getLoanIdsFromJobParameters(chunkContext));
contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_STEPS, cobBusinessSteps);
String businessDateString = getBusinessDateFromJobParameters(chunkContext);
contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, businessDateString);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBConstant.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBConstant.java
index 35563e02b..d7e5fedd7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBConstant.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBConstant.java
@@ -23,11 +23,10 @@ public final class LoanCOBConstant {
public static final String JOB_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_IDS = "loanIds";
+ 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 ALREADY_LOCKED_BY_INLINE_COB_OR_PROCESSED_LOAN_IDS = "alreadyLockedOrProcessedLoanIds";
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";
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
index 27a9cf91c..bb944c509 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBManagerConfiguration.java
@@ -18,12 +18,10 @@
*/
package org.apache.fineract.cob.loan;
-import java.util.List;
import org.apache.fineract.cob.COBBusinessStepService;
import org.apache.fineract.cob.common.CustomJobParameterResolver;
-import org.apache.fineract.cob.domain.LoanAccountLockRepository;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.listener.COBExecutionListenerRunner;
-import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.springbatch.PropertyService;
@@ -74,23 +72,19 @@ public class LoanCOBManagerConfiguration {
@Autowired
private RetrieveLoanIdService retrieveLoanIdService;
@Autowired
- private LoanAccountLockRepository accountLockRepository;
- @Autowired
private BusinessEventNotifierService businessEventNotifierService;
@Autowired
private CustomJobParameterResolver customJobParameterResolver;
@Autowired
private LoanRepository loanRepository;
- @Autowired
- private FineractProperties fineractProperties;
@Autowired
private JdbcTemplate jdbcTemplate;
@Bean
@JobScope
- public LoanCOBPartitioner partitioner(@Value("#{jobExecutionContext['loanIds']}") List<Long> loanIds) {
- return new LoanCOBPartitioner(propertyService, cobBusinessStepService, jobOperator, jobExplorer, loanIds);
+ public LoanCOBPartitioner partitioner(@Value("#{jobExecutionContext['loanIds']}") LoanCOBParameter minAndMaxLoanId) {
+ return new LoanCOBPartitioner(propertyService, cobBusinessStepService, jobOperator, jobExplorer, minAndMaxLoanId);
}
@Bean
@@ -100,8 +94,13 @@ public class LoanCOBManagerConfiguration {
}
@Bean
- public Step fetchAndLockStep() {
- return localStepBuilderFactory.get("Fetch and Lock loan accounts - Step").tasklet(fetchAndLockLoanTasklet()).build();
+ public Step loanIdParameterStep() {
+ return localStepBuilderFactory.get("Set loan ID parameter - Step").tasklet(loanIdParameterTasklet()).build();
+ }
+
+ @Bean
+ public Step lockStep() {
+ return localStepBuilderFactory.get("Lock loan accounts - Step").tasklet(lockLoanTasklet()).build();
}
@Bean
@@ -117,8 +116,14 @@ public class LoanCOBManagerConfiguration {
@Bean
@JobScope
- public FetchAndLockLoanTasklet fetchAndLockLoanTasklet() {
- return new FetchAndLockLoanTasklet(accountLockRepository, retrieveLoanIdService, fineractProperties, jdbcTemplate);
+ public LoanIdParameterTasklet loanIdParameterTasklet() {
+ return new LoanIdParameterTasklet(retrieveLoanIdService);
+ }
+
+ @Bean
+ @JobScope
+ public LockLoanTasklet lockLoanTasklet() {
+ return new LockLoanTasklet(jdbcTemplate);
}
@Bean
@@ -138,7 +143,7 @@ public class LoanCOBManagerConfiguration {
return jobBuilderFactory.get(JobName.LOAN_COB.name()) //
.listener(new COBExecutionListenerRunner(applicationContext, JobName.LOAN_COB.name())) //
.start(resolveCustomJobParametersStep()) //
- .next(fetchAndLockStep()).next(loanCOBStep()).next(stayedLockedStep()) //
+ .next(loanIdParameterStep()).next(lockStep()).next(loanCOBStep()).next(stayedLockedStep()) //
.incrementer(new RunIdIncrementer()) //
.build();
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBPartitioner.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBPartitioner.java
index 2a851130a..25733d7cd 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBPartitioner.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBPartitioner.java
@@ -18,15 +18,15 @@
*/
package org.apache.fineract.cob.loan;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.COBBusinessStepService;
import org.apache.fineract.cob.data.BusinessStepNameAndOrder;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.springbatch.PropertyService;
import org.jetbrains.annotations.NotNull;
@@ -49,7 +49,7 @@ public class LoanCOBPartitioner implements Partitioner {
private final JobOperator jobOperator;
private final JobExplorer jobExplorer;
- private final List<Long> loanIds;
+ private final LoanCOBParameter minAndMaxLoanId;
@NotNull
@Override
@@ -67,19 +67,25 @@ public class LoanCOBPartitioner implements Partitioner {
return Map.of();
}
int partitionIndex = 1;
- int remainingSpace = 0;
createNewPartition(partitions, partitionIndex, cobBusinessSteps);
- for (Long loanId : loanIds) {
- if (remainingSpace == partitionSize) {
- partitionIndex++;
- createNewPartition(partitions, partitionIndex, cobBusinessSteps);
- remainingSpace = 0;
- }
- String key = PARTITION_PREFIX + partitionIndex;
- ExecutionContext executionContext = partitions.get(key);
- List<Long> data = (List<Long>) executionContext.get(LoanCOBConstant.LOAN_IDS);
- data.add(loanId);
- remainingSpace++;
+ if (!Objects.isNull(minAndMaxLoanId)) {
+ long remainingLoanIdCount = minAndMaxLoanId.getMaxLoanId() - minAndMaxLoanId.getMinLoanId() + 1;
+ long startLoanId = minAndMaxLoanId.getMinLoanId();
+ long endLoanId;
+ do {
+ String key = PARTITION_PREFIX + partitionIndex;
+ ExecutionContext executionContext = partitions.get(key);
+ if (remainingLoanIdCount > partitionSize) {
+ endLoanId = startLoanId + partitionSize - 1;
+ partitionIndex++;
+ createNewPartition(partitions, partitionIndex, cobBusinessSteps);
+ } else {
+ endLoanId = minAndMaxLoanId.getMaxLoanId();
+ }
+ executionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, new LoanCOBParameter(startLoanId, endLoanId));
+ startLoanId = startLoanId + partitionSize;
+ remainingLoanIdCount = minAndMaxLoanId.getMaxLoanId() - endLoanId;
+ } while (remainingLoanIdCount > 0);
}
return partitions;
}
@@ -87,7 +93,6 @@ public class LoanCOBPartitioner implements Partitioner {
private void createNewPartition(Map<String, ExecutionContext> partitions, int partitionIndex,
Set<BusinessStepNameAndOrder> cobBusinessSteps) {
ExecutionContext executionContext = new ExecutionContext();
- executionContext.put(LoanCOBConstant.LOAN_IDS, new ArrayList<Long>());
executionContext.put(LoanCOBConstant.BUSINESS_STEPS, cobBusinessSteps);
executionContext.put("partition", PARTITION_PREFIX + partitionIndex);
partitions.put(PARTITION_PREFIX + partitionIndex, executionContext);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java
index 3cc751867..252fb9dce 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java
@@ -123,7 +123,7 @@ public class LoanCOBWorkerConfiguration {
@Bean
public ApplyLoanLockTasklet applyLock() {
- return new ApplyLoanLockTasklet(accountLockRepository, fineractProperties, jdbcTemplate);
+ return new ApplyLoanLockTasklet(accountLockRepository, fineractProperties, jdbcTemplate, loanRepository);
}
@Bean
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanIdParameterTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanIdParameterTasklet.java
new file mode 100644
index 000000000..a463503b9
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanIdParameterTasklet.java
@@ -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.cob.loan;
+
+import java.time.LocalDate;
+import java.util.Objects;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.cob.data.LoanCOBParameter;
+import org.springframework.batch.core.StepContribution;
+import org.springframework.batch.core.scope.context.ChunkContext;
+import org.springframework.batch.core.step.tasklet.Tasklet;
+import org.springframework.batch.repeat.RepeatStatus;
+
+@Slf4j
+@RequiredArgsConstructor
+public class LoanIdParameterTasklet implements Tasklet {
+
+ private static final Long NUMBER_OF_DAYS_BEHIND = 1L;
+
+ private final RetrieveLoanIdService retrieveLoanIdService;
+
+ @Override
+ public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
+ String businessDateParameter = (String) contribution.getStepExecution().getJobExecution().getExecutionContext()
+ .get(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME);
+ LocalDate businessDate = LocalDate.parse(Objects.requireNonNull(businessDateParameter));
+ LoanCOBParameter minAndMaxLoanId = retrieveLoanIdService.retrieveMinAndMaxLoanIdsNDaysBehind(NUMBER_OF_DAYS_BEHIND, businessDate);
+ if (Objects.isNull(minAndMaxLoanId)
+ || (Objects.isNull(minAndMaxLoanId.getMinLoanId()) && Objects.isNull(minAndMaxLoanId.getMaxLoanId()))) {
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
+ new LoanCOBParameter(0L, 0L));
+ return RepeatStatus.FINISHED;
+ }
+
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER, minAndMaxLoanId);
+
+ return RepeatStatus.FINISHED;
+ }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java
index 64dcecfcb..78a9aa28d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java
@@ -121,8 +121,8 @@ public class LoanInlineCOBConfig {
@Bean
public ExecutionContextPromotionListener inlineCobPromotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
- listener.setKeys(
- new String[] { LoanCOBConstant.LOAN_IDS, LoanCOBConstant.BUSINESS_STEPS, LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME });
+ listener.setKeys(new String[] { LoanCOBConstant.LOAN_COB_PARAMETER, LoanCOBConstant.BUSINESS_STEPS,
+ LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME });
return listener;
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanItemReader.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanItemReader.java
index ecb737e83..8dd6b3b2d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanItemReader.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanItemReader.java
@@ -19,7 +19,12 @@
package org.apache.fineract.cob.loan;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import org.apache.fineract.cob.data.LoanCOBParameter;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.jetbrains.annotations.NotNull;
import org.springframework.batch.core.StepExecution;
@@ -35,8 +40,17 @@ public class LoanItemReader extends AbstractLoanItemReader {
@BeforeStep
@SuppressWarnings({ "unchecked" })
public void beforeStep(@NotNull StepExecution stepExecution) {
- ExecutionContext executionContext = stepExecution.getExecutionContext();
- List<Long> loanIds = (List<Long>) executionContext.get(LoanCOBConstant.LOAN_IDS);
+ ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) executionContext.get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ List<Long> loanIds;
+ if (Objects.isNull(loanCOBParameter)
+ || (Objects.isNull(loanCOBParameter.getMinLoanId()) && Objects.isNull(loanCOBParameter.getMaxLoanId()))
+ || (loanCOBParameter.getMinLoanId().equals(0L) && loanCOBParameter.getMaxLoanId().equals(0L))) {
+ loanIds = Collections.emptyList();
+ } else {
+ loanIds = loanRepository.findAllNonClosedLoansBehindOrNullByMinAndMaxLoanId(loanCOBParameter.getMinLoanId(),
+ loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+ }
setRemainingData(new ArrayList<>(loanIds));
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LockLoanTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LockLoanTasklet.java
new file mode 100644
index 000000000..efe944f65
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LockLoanTasklet.java
@@ -0,0 +1,78 @@
+/**
+ * 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 java.time.LocalDate;
+import java.util.Objects;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.cob.data.LoanCOBParameter;
+import org.apache.fineract.cob.domain.LockOwner;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.batch.core.StepContribution;
+import org.springframework.batch.core.scope.context.ChunkContext;
+import org.springframework.batch.core.step.tasklet.Tasklet;
+import org.springframework.batch.repeat.RepeatStatus;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+@Slf4j
+@RequiredArgsConstructor
+public class LockLoanTasklet implements Tasklet {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ @Override
+ public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception {
+ String businessDateParameter = (String) contribution.getStepExecution().getJobExecution().getExecutionContext()
+ .get(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME);
+ LocalDate businessDate = LocalDate.parse(Objects.requireNonNull(businessDateParameter));
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution().getExecutionContext()
+ .get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ if (Objects.isNull(loanCOBParameter)
+ || (Objects.isNull(loanCOBParameter.getMinLoanId()) && Objects.isNull(loanCOBParameter.getMaxLoanId()))) {
+ loanCOBParameter = new LoanCOBParameter(0L, 0L);
+ }
+ applySoftLock(businessDate, loanCOBParameter);
+
+ return RepeatStatus.FINISHED;
+ }
+
+ private void applySoftLock(LocalDate businessDate, LoanCOBParameter loanCOBParameter) {
+ LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+ jdbcTemplate.update("""
+ INSERT INTO m_loan_account_locks (loan_id, version, lock_owner, lock_placed_on, lock_placed_on_cob_business_date)
+ SELECT loan.id, ?, ?, ?, ? FROM m_loan loan
+ WHERE loan.id NOT IN (SELECT loan_id FROM m_loan_account_locks)
+ AND loan.id BETWEEN ? AND ?
+ AND loan.loan_status_id IN (100,200,300,303,304)
+ AND (? = loan.last_closed_business_date OR loan.last_closed_business_date IS NULL)
+ """, ps -> {
+ ps.setLong(1, 1);
+ ps.setString(2, LockOwner.LOAN_COB_PARTITIONING.name());
+ ps.setObject(3, DateUtils.getOffsetDateTimeOfTenant());
+ ps.setObject(4, cobBusinessDate);
+ ps.setObject(5, loanCOBParameter.getMinLoanId());
+ ps.setObject(6, loanCOBParameter.getMaxLoanId());
+ ps.setObject(7, businessDate);
+ });
+ }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveAllNonClosedLoanIdServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveAllNonClosedLoanIdServiceImpl.java
index 24a484e0c..c175b2f7b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveAllNonClosedLoanIdServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveAllNonClosedLoanIdServiceImpl.java
@@ -21,6 +21,7 @@ package org.apache.fineract.cob.loan;
import java.time.LocalDate;
import java.util.List;
import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
@@ -30,8 +31,8 @@ public class RetrieveAllNonClosedLoanIdServiceImpl implements RetrieveLoanIdServ
private final LoanRepository loanRepository;
@Override
- public List<Long> retrieveLoanIdsNDaysBehind(Long numberOfDays, LocalDate businessDate) {
- return loanRepository.findAllNonClosedLoanIdsByLastClosedBusinessDate(businessDate.minusDays(numberOfDays));
+ public LoanCOBParameter retrieveMinAndMaxLoanIdsNDaysBehind(Long numberOfDays, LocalDate businessDate) {
+ return loanRepository.findMinAndMaxNonClosedLoanIdsByLastClosedBusinessDate(businessDate.minusDays(numberOfDays));
}
@Override
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveLoanIdService.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveLoanIdService.java
index f5a9c7b52..b89fad5d7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveLoanIdService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/RetrieveLoanIdService.java
@@ -20,11 +20,12 @@ package org.apache.fineract.cob.loan;
import java.time.LocalDate;
import java.util.List;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
public interface RetrieveLoanIdService {
- List<Long> retrieveLoanIdsNDaysBehind(Long numberOfDays, LocalDate businessDate);
+ LoanCOBParameter retrieveMinAndMaxLoanIdsNDaysBehind(Long numberOfDays, LocalDate businessDate);
List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDateOrNull(LocalDate businessDate, List<Long> loanIds);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java
index f34d80739..471098921 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/StayedLockedLoansTasklet.java
@@ -53,7 +53,8 @@ public class StayedLockedLoansTasklet implements Tasklet {
private LoanAccountsStayedLockedData buildLoanAccountData() {
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
- List<LoanIdAndExternalIdAndAccountNo> stayedLockedLoanAccounts = loanRepository.findAllStayedLockedByLoanIds(cobBusinessDate);
+ List<LoanIdAndExternalIdAndAccountNo> stayedLockedLoanAccounts = loanRepository
+ .findAllStayedLockedByCobBusinessDate(cobBusinessDate);
List<LoanAccountStayedLockedData> loanAccounts = new ArrayList<>();
stayedLockedLoanAccounts.forEach(loanAccount -> {
loanAccounts.add(new LoanAccountStayedLockedData(loanAccount.getId(), loanAccount.getExternalId(), loanAccount.getAccountNo()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
index 08e3cd0ef..8204618c7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
@@ -74,7 +75,8 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
String FIND_ALL_NON_CLOSED = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304)";
- String FIND_ALL_NON_CLOSED_LOANS_BY_LAST_CLOSED_BUSINESS_DATE = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304) and (:businessDate = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";
+ String FIND_MIN_AND_MAX_NON_CLOSED_LOAN_IDS_BY_LAST_CLOSED_BUSINESS_DATE = "select new org.apache.fineract.cob.data.LoanCOBParameter(min(loan.id), max(loan.id)) from Loan loan where loan.loanStatus in (100,200,300,303,304) "
+ + "and (:businessDate = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";
String FIND_NON_CLOSED_LOAN_THAT_BELONGS_TO_CLIENT = "select loan from Loan loan where loan.id = :loanId and loan.loanStatus = 300 and loan.client.id = :clientId";
@@ -89,9 +91,12 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
String FIND_ALL_NON_CLOSED_LOANS_BEHIND_OR_NULL_BY_LOAN_IDS = "select loan.id, loan.lastClosedBusinessDate from Loan loan where loan.id IN :loanIds and loan.loanStatus in (100,200,300,303,304) and (loan.lastClosedBusinessDate < :cobBusinessDate or "
+ "loan.lastClosedBusinessDate is null)";
+ String FIND_ALL_NON_CLOSED_LOANS_BEHIND_OR_NULL_BY_MIN_AND_MAX_LOAN_ID = "select loan.id from Loan loan where loan.id BETWEEN :minLoanId and :maxLoanId and loan.loanStatus in (100,200,300,303,304) and (loan.lastClosedBusinessDate < "
+ + ":cobBusinessDate or loan.lastClosedBusinessDate is null)";
+
String FIND_ALL_NON_CLOSED_LOANS_BEHIND_BY_LOAN_IDS = "select loan.id, loan.lastClosedBusinessDate from Loan loan where loan.id IN :loanIds and loan.loanStatus in (100,200,300,303,304) and loan.lastClosedBusinessDate < :cobBusinessDate";
- String FIND_ALL_STAYED_LOCKED_BY_LOAN_IDS = "select loan.id, loan.externalId, loan.accountNumber from LoanAccountLock lock left join Loan loan on lock.loanId = loan.id where lock.lockPlacedOnCobBusinessDate = :cobBusinessDate";
+ String FIND_ALL_STAYED_LOCKED_BY_COB_BUSINESS_DATE = "select loan.id, loan.externalId, loan.accountNumber from LoanAccountLock lock left join Loan loan on lock.loanId = loan.id where lock.lockPlacedOnCobBusinessDate = :cobBusinessDate";
@Query(FIND_GROUP_LOANS_DISBURSED_AFTER)
List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") LocalDate disbursementDate, @Param("groupId") Long groupId,
@@ -189,8 +194,8 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
@Query(FIND_ID_BY_EXTERNAL_ID)
Long findIdByExternalId(@Param("externalId") ExternalId externalId);
- @Query(FIND_ALL_NON_CLOSED_LOANS_BY_LAST_CLOSED_BUSINESS_DATE)
- List<Long> findAllNonClosedLoanIdsByLastClosedBusinessDate(@Param("businessDate") LocalDate businessDate);
+ @Query(FIND_MIN_AND_MAX_NON_CLOSED_LOAN_IDS_BY_LAST_CLOSED_BUSINESS_DATE)
+ LoanCOBParameter findMinAndMaxNonClosedLoanIdsByLastClosedBusinessDate(@Param("businessDate") LocalDate businessDate);
@Query(FIND_ALL_NON_CLOSED_LOANS_BEHIND_BY_LOAN_IDS)
List<LoanIdAndLastClosedBusinessDate> findAllNonClosedLoansBehindByLoanIds(@Param("cobBusinessDate") LocalDate cobBusinessDate,
@@ -200,10 +205,14 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
List<LoanIdAndLastClosedBusinessDate> findAllNonClosedLoansBehindOrNullByLoanIds(@Param("cobBusinessDate") LocalDate cobBusinessDate,
@Param("loanIds") List<Long> loanIds);
+ @Query(FIND_ALL_NON_CLOSED_LOANS_BEHIND_OR_NULL_BY_MIN_AND_MAX_LOAN_ID)
+ List<Long> findAllNonClosedLoansBehindOrNullByMinAndMaxLoanId(@Param("minLoanId") Long minLoanId, @Param("maxLoanId") Long maxLoanId,
+ @Param("cobBusinessDate") LocalDate cobBusinessDate);
+
@Query(FIND_OLDEST_COB_PROCESSED_LOAN)
List<LoanIdAndLastClosedBusinessDate> findOldestCOBProcessedLoan(@Param("cobBusinessDate") LocalDate cobBusinessDate);
- @Query(FIND_ALL_STAYED_LOCKED_BY_LOAN_IDS)
- List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByLoanIds(@Param("cobBusinessDate") LocalDate cobBusinessDate);
+ @Query(FIND_ALL_STAYED_LOCKED_BY_COB_BUSINESS_DATE)
+ List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(@Param("cobBusinessDate") LocalDate cobBusinessDate);
}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java
index bc7271c8e..47165937e 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/ApplyLoanLockTaskletStepDefinitions.java
@@ -20,6 +20,8 @@ package org.apache.fineract.cob.loan;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -27,9 +29,9 @@ import static org.mockito.Mockito.verify;
import io.cucumber.java8.En;
import java.time.LocalDate;
import java.time.ZoneId;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
@@ -37,6 +39,7 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.batch.core.StepContribution;
@@ -53,7 +56,9 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
private FineractProperties fineractProperties = mock(FineractProperties.class);
private JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
private FineractProperties.FineractQueryProperties fineractQueryProperties = mock(FineractProperties.FineractQueryProperties.class);
- private ApplyLoanLockTasklet applyLoanLockTasklet = new ApplyLoanLockTasklet(accountLockRepository, fineractProperties, jdbcTemplate);
+ private LoanRepository loanRepository = mock(LoanRepository.class);
+ private ApplyLoanLockTasklet applyLoanLockTasklet = new ApplyLoanLockTasklet(accountLockRepository, fineractProperties, jdbcTemplate,
+ loanRepository);
private RepeatStatus resultItem;
private StepContribution stepContribution;
@@ -65,7 +70,9 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
ThreadLocalContextUtil.setBusinessDates(businessDateMap);
StepExecution stepExecution = new StepExecution("test", null);
ExecutionContext executionContext = new ExecutionContext();
- executionContext.put(LoanCOBConstant.LOAN_IDS, new ArrayList<>(List.of(1L, 2L, 3L, 4L)));
+ executionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, new LoanCOBParameter(1L, 4L));
+ lenient().when(this.loanRepository.findAllNonClosedLoansBehindOrNullByMinAndMaxLoanId(anyLong(), anyLong(), any()))
+ .thenReturn(List.of(1L, 2L, 3L, 4L));
stepExecution.setExecutionContext(executionContext);
this.stepContribution = new StepContribution(stepExecution);
diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/FetchAndLockLoanStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/FetchAndLockLoanStepDefinitions.java
index 3f5afdab0..51ef56fa7 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/FetchAndLockLoanStepDefinitions.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/FetchAndLockLoanStepDefinitions.java
@@ -20,8 +20,6 @@ package org.apache.fineract.cob.loan;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
@@ -33,6 +31,7 @@ import java.time.ZoneId;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
@@ -46,17 +45,17 @@ import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.PreparedStatementSetter;
public class FetchAndLockLoanStepDefinitions implements En {
private final LoanAccountLockRepository loanAccountLockRepository = mock(LoanAccountLockRepository.class);
- private final RetrieveLoanIdService retrieveLoanIdService = mock(RetrieveLoanIdService.class);
private final FineractProperties fineractProperties = mock(FineractProperties.class);
private final FineractProperties.FineractQueryProperties fineractQueryProperties = mock(
FineractProperties.FineractQueryProperties.class);
StepContribution contribution;
- private FetchAndLockLoanTasklet fetchAndLockLoanTasklet;
+ private LockLoanTasklet lockLoanTasklet;
private String action;
private RepeatStatus result;
private JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
@@ -69,105 +68,87 @@ public class FetchAndLockLoanStepDefinitions implements En {
ThreadLocalContextUtil.setBusinessDates(businessDateMap);
this.action = action;
+ JobExecution jobExecution = new JobExecution(1L);
+ StepExecution stepExecution = new StepExecution("step", jobExecution);
+ contribution = new StepContribution(stepExecution);
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME,
+ LocalDate.now(ZoneId.systemDefault()).toString());
+
if ("empty loanIds".equals(action)) {
- lenient().when(retrieveLoanIdService.retrieveLoanIdsNDaysBehind(anyLong(), any())).thenReturn(Collections.emptyList());
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
+ new LoanCOBParameter(0L, 0L));
} else if ("good".equals(action)) {
- lenient().when(retrieveLoanIdService.retrieveLoanIdsNDaysBehind(anyLong(), any())).thenReturn(List.of(1L, 2L, 3L));
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
+ new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(Collections.emptyList());
} else if ("soft lock".equals(action)) {
- lenient().when(retrieveLoanIdService.retrieveLoanIdsNDaysBehind(anyLong(), any())).thenReturn(List.of(1L, 2L, 3L));
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
+ new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(
List.of(new LoanAccountLock(1L, LockOwner.LOAN_COB_PARTITIONING, LocalDate.now(ZoneId.systemDefault()))));
} else if ("inline cob".equals(action)) {
- lenient().when(retrieveLoanIdService.retrieveLoanIdsNDaysBehind(anyLong(), any())).thenReturn(List.of(1L, 2L, 3L));
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
+ new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(
List.of(new LoanAccountLock(2L, LockOwner.LOAN_INLINE_COB_PROCESSING, LocalDate.now(ZoneId.systemDefault()))));
} else if ("chunk processing".equals(action)) {
- lenient().when(retrieveLoanIdService.retrieveLoanIdsNDaysBehind(anyLong(), any())).thenReturn(List.of(1L, 2L, 3L));
+ contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.LOAN_COB_PARAMETER,
+ new LoanCOBParameter(1L, 3L));
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
lenient().when(loanAccountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(
List.of(new LoanAccountLock(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()))));
}
- JobExecution jobExecution = new JobExecution(1L);
- StepExecution stepExecution = new StepExecution("step", jobExecution);
- contribution = new StepContribution(stepExecution);
- contribution.getStepExecution().getJobExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME,
- LocalDate.now(ZoneId.systemDefault()).toString());
- fetchAndLockLoanTasklet = new FetchAndLockLoanTasklet(loanAccountLockRepository, retrieveLoanIdService, fineractProperties,
- jdbcTemplate);
+ lockLoanTasklet = new LockLoanTasklet(jdbcTemplate);
});
When("FetchAndLockLoanTasklet.execute method executed", () -> {
- result = this.fetchAndLockLoanTasklet.execute(contribution, null);
+ result = this.lockLoanTasklet.execute(contribution, null);
});
Then("FetchAndLockLoanTasklet.execute result should match", () -> {
if ("empty steps".equals(action)) {
assertEquals(RepeatStatus.FINISHED, result);
} else if ("good".equals(action)) {
- verify(jdbcTemplate).batchUpdate(anyString(), any(), anyInt(), any());
+ verify(jdbcTemplate).update(anyString(), (PreparedStatementSetter) any());
assertEquals(RepeatStatus.FINISHED, result);
- assertEquals(3,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .size());
- assertEquals(1L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(0));
- assertEquals(2L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(1));
- assertEquals(3L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(2));
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
+ .getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
+ assertEquals(1L, loanCOBParameter.getMinLoanId());
+ assertEquals(3L, loanCOBParameter.getMaxLoanId());
} else if ("soft lock".equals(action)) {
- verify(jdbcTemplate).batchUpdate(anyString(), any(), anyInt(), any());
+ verify(jdbcTemplate).update(anyString(), (PreparedStatementSetter) any());
assertEquals(RepeatStatus.FINISHED, result);
- assertEquals(3,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .size());
- assertEquals(1L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(0));
- assertEquals(2L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(1));
- assertEquals(3L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(2));
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
+ .getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
+ assertEquals(1L, loanCOBParameter.getMinLoanId());
+ assertEquals(3L, loanCOBParameter.getMaxLoanId());
} else if ("inline cob".equals(action)) {
- verify(jdbcTemplate).batchUpdate(anyString(), any(), anyInt(), any());
+ verify(jdbcTemplate).update(anyString(), (PreparedStatementSetter) any());
assertEquals(RepeatStatus.FINISHED, result);
- assertEquals(2,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .size());
- assertEquals(1L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(0));
- assertEquals(3L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(1));
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
+ .getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
+ assertEquals(1L, loanCOBParameter.getMinLoanId());
+ assertEquals(3L, loanCOBParameter.getMaxLoanId());
} else if ("chunk processing".equals(action)) {
- verify(jdbcTemplate).batchUpdate(anyString(), any(), anyInt(), any());
+ verify(jdbcTemplate).update(anyString(), (PreparedStatementSetter) any());
assertEquals(RepeatStatus.FINISHED, result);
- assertEquals(2,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .size());
- assertEquals(1L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(0));
- assertEquals(2L,
- ((List) contribution.getStepExecution().getJobExecution().getExecutionContext().get(LoanCOBConstant.LOAN_IDS))
- .get(1));
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
+ .getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ assertEquals(2, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
+ assertEquals(1L, loanCOBParameter.getMinLoanId());
+ assertEquals(3L, loanCOBParameter.getMaxLoanId());
}
});
-
}
}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanCOBPartitionerStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanCOBPartitionerStepDefinitions.java
index 03a045ac3..012dbd317 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanCOBPartitionerStepDefinitions.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanCOBPartitionerStepDefinitions.java
@@ -28,11 +28,11 @@ import com.google.gson.Gson;
import io.cucumber.java8.En;
import java.util.Collections;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.fineract.cob.COBBusinessStepService;
import org.apache.fineract.cob.data.BusinessStepNameAndOrder;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.springbatch.PropertyService;
@@ -50,7 +50,7 @@ public class LoanCOBPartitionerStepDefinitions implements En {
JobExplorer jobExplorer = mock(JobExplorer.class);
private final Gson gson = GoogleGsonSerializerHelper.createSimpleGson();
- List<Long> loanIds;
+ LoanCOBParameter loanIds;
private LoanCOBPartitioner loanCOBPartitioner;
private Set<BusinessStepNameAndOrder> cobBusinessSteps = new HashSet<>();
@@ -68,17 +68,17 @@ public class LoanCOBPartitionerStepDefinitions implements En {
.thenReturn(Collections.emptySet());
lenient().when(jobExplorer.findRunningJobExecutions(JobName.LOAN_COB.name())).thenReturn(Set.of(new JobExecution(3L)));
lenient().when(jobOperator.stop(3L)).thenReturn(Boolean.TRUE);
- loanIds = Collections.emptyList();
+ loanIds = null;
} else if ("empty loanIds".equals(action)) {
cobBusinessSteps.add(new BusinessStepNameAndOrder("Business step", 1L));
lenient().when(cobBusinessStepService.getCOBBusinessSteps(LoanCOBBusinessStep.class, LoanCOBConstant.LOAN_COB_JOB_NAME))
.thenReturn(cobBusinessSteps);
- loanIds = Collections.emptyList();
+ loanIds = null;
} else if ("good".equals(action)) {
cobBusinessSteps.add(new BusinessStepNameAndOrder("Business step", 1L));
lenient().when(cobBusinessStepService.getCOBBusinessSteps(LoanCOBBusinessStep.class, LoanCOBConstant.LOAN_COB_JOB_NAME))
.thenReturn(cobBusinessSteps);
- loanIds = List.of(1L, 2L, 3L);
+ loanIds = new LoanCOBParameter(1L, 3L);
}
loanCOBPartitioner = new LoanCOBPartitioner(propertyService, cobBusinessStepService, jobOperator, jobExplorer, loanIds);
});
@@ -101,16 +101,21 @@ public class LoanCOBPartitionerStepDefinitions implements En {
businessSteps.stream().findFirst().get().getStepOrder());
assertEquals(cobBusinessSteps.stream().findFirst().get().getStepName(),
businessSteps.stream().findFirst().get().getStepName());
- assertEquals(2, ((List) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "1").get(LoanCOBConstant.LOAN_IDS)).size());
- assertEquals(1L, ((List) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "1").get(LoanCOBConstant.LOAN_IDS)).get(0));
- assertEquals(2L, ((List) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "1").get(LoanCOBConstant.LOAN_IDS)).get(1));
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "1")
+ .get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ assertEquals(1, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
+ assertEquals(1L, loanCOBParameter.getMinLoanId());
+ assertEquals(2L, loanCOBParameter.getMaxLoanId());
assertTrue(resultItem.containsKey(LoanCOBPartitioner.PARTITION_PREFIX + "2"));
assertEquals(cobBusinessSteps.stream().findFirst().get().getStepOrder(),
businessSteps.stream().findFirst().get().getStepOrder());
assertEquals(cobBusinessSteps.stream().findFirst().get().getStepName(),
businessSteps.stream().findFirst().get().getStepName());
- assertEquals(1, ((List) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "2").get(LoanCOBConstant.LOAN_IDS)).size());
- assertEquals(3L, ((List) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "2").get(LoanCOBConstant.LOAN_IDS)).get(0));
+ loanCOBParameter = (LoanCOBParameter) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "2")
+ .get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ assertEquals(0, loanCOBParameter.getMaxLoanId() - loanCOBParameter.getMinLoanId());
+ assertEquals(3L, loanCOBParameter.getMinLoanId());
+ assertEquals(3L, loanCOBParameter.getMaxLoanId());
} else if ("empty loanIds".equals(action)) {
verify(jobOperator, Mockito.times(0)).stop(Mockito.anyLong());
assertEquals(1, resultItem.size());
@@ -121,7 +126,9 @@ public class LoanCOBPartitionerStepDefinitions implements En {
businessSteps.stream().findFirst().get().getStepOrder());
assertEquals(cobBusinessSteps.stream().findFirst().get().getStepName(),
businessSteps.stream().findFirst().get().getStepName());
- assertEquals(0, ((List) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "1").get(LoanCOBConstant.LOAN_IDS)).size());
+ LoanCOBParameter loanCOBParameter = (LoanCOBParameter) resultItem.get(LoanCOBPartitioner.PARTITION_PREFIX + "1")
+ .get(LoanCOBConstant.LOAN_COB_PARAMETER);
+ assertEquals(null, loanCOBParameter);
}
});
}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java
index c2b0a8700..b35b0ec38 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/LoanItemReaderStepDefinitions.java
@@ -21,15 +21,23 @@ package org.apache.fineract.cob.loan;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import com.google.common.base.Splitter;
import io.cucumber.java8.En;
+import java.time.LocalDate;
+import java.time.ZoneId;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Optional;
+import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.exceptions.LoanReadException;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.springframework.batch.core.JobExecution;
@@ -53,18 +61,29 @@ public class LoanItemReaderStepDefinitions implements En {
jobExecution.setExecutionContext(jobExecutionContext);
StepExecution stepExecution = new StepExecution("test", jobExecution);
ExecutionContext stepExecutionContext = new ExecutionContext();
- List<Long> splitAccounts;
- if (loanIds.isEmpty()) {
- splitAccounts = new ArrayList<>();
- } else {
+ Long minLoanId = null;
+ Long maxLoanId = null;
+ List<Long> splitAccounts = new ArrayList<>();
+ if (!loanIds.isEmpty()) {
List<String> splitStr = Splitter.on(',').splitToList(loanIds);
splitAccounts = splitStr.stream().map(Long::parseLong).toList();
+ minLoanId = splitAccounts.get(0);
+ maxLoanId = splitAccounts.get(splitAccounts.size() - 1);
}
- stepExecutionContext.put(LoanCOBConstant.LOAN_IDS, new ArrayList<>(splitAccounts));
- stepExecution.setExecutionContext(stepExecutionContext);
+ stepExecutionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, new LoanCOBParameter(minLoanId, maxLoanId));
+ jobExecution.setExecutionContext(stepExecutionContext);
+
+ lenient().when(this.loanRepository.findAllNonClosedLoansBehindOrNullByMinAndMaxLoanId(anyLong(), anyLong(), any()))
+ .thenReturn(splitAccounts);
+
+ HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>();
+ LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
+ businessDates.put(BusinessDateType.BUSINESS_DATE, businessDate);
+ businessDates.put(BusinessDateType.COB_DATE, businessDate.minusDays(1));
+ ThreadLocalContextUtil.setBusinessDates(businessDates);
+
loanItemReader.beforeStep(stepExecution);
- lenient().when(this.loanRepository.findById(0L)).thenReturn(Optional.empty());
lenient().when(this.loanRepository.findById(1L)).thenReturn(Optional.of(loan));
lenient().when(this.loanRepository.findById(-1L)).thenThrow(new RuntimeException("fail"));
diff --git a/fineract-provider/src/test/resources/features/cob/loan/cob.loan.reader.feature b/fineract-provider/src/test/resources/features/cob/loan/cob.loan.reader.feature
index e775f3a86..2453f779a 100644
--- a/fineract-provider/src/test/resources/features/cob/loan/cob.loan.reader.feature
+++ b/fineract-provider/src/test/resources/features/cob/loan/cob.loan.reader.feature
@@ -48,4 +48,3 @@ Feature: COB Reader
Examples:
|loanIds|
|-1 |
- |0 |