[FINERACT-1678] Exclude loan IDs from execution context
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.cob.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
public class LoanCOBParameter {
|
||||
|
||||
private Long minLoanId;
|
||||
private Long maxLoanId;
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+17
-1
@@ -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)));
|
||||
|
||||
-112
@@ -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();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
+19
-14
@@ -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();
|
||||
}
|
||||
|
||||
+21
-16
@@ -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);
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.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;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -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
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
|
||||
+2
-1
@@ -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()));
|
||||
|
||||
+15
-6
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user