FINERACT-1724: Use services instead of repositories in COB

This commit is contained in:
Adam Saghy
2023-04-17 17:50:44 +02:00
parent 234583c8e1
commit 748b775051
22 changed files with 283 additions and 145 deletions
@@ -21,13 +21,12 @@ package org.apache.fineract.cob.listener;
import static org.springframework.transaction.TransactionDefinition.PROPAGATION_REQUIRES_NEW;
import java.util.List;
import java.util.Optional;
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.cob.exceptions.LoanReadException;
import org.apache.fineract.cob.loan.LoanLockingService;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.serialization.ThrowableSerialization;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -46,7 +45,7 @@ import org.springframework.transaction.support.TransactionTemplate;
@RequiredArgsConstructor
public abstract class AbstractLoanItemListener {
private final LoanAccountLockRepository accountLockRepository;
private final LoanLockingService loanLockingService;
private final TransactionTemplate transactionTemplate;
@@ -57,9 +56,10 @@ public abstract class AbstractLoanItemListener {
@Override
protected void doInTransactionWithoutResult(@NotNull TransactionStatus status) {
for (Long loanId : loanIds) {
Optional<LoanAccountLock> loanAccountLock = accountLockRepository.findByLoanIdAndLockOwner(loanId, getLockOwner());
loanAccountLock.ifPresent(
accountLock -> accountLock.setError(String.format(msg, loanId), ThrowableSerialization.serialize(e)));
LoanAccountLock loanAccountLock = loanLockingService.findByLoanIdAndLockOwner(loanId, getLockOwner());
if (loanAccountLock != null) {
loanAccountLock.setError(String.format(msg, loanId), ThrowableSerialization.serialize(e));
}
}
}
});
@@ -18,14 +18,14 @@
*/
package org.apache.fineract.cob.listener;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.cob.loan.LoanLockingService;
import org.springframework.transaction.support.TransactionTemplate;
public class ChunkProcessingLoanItemListener extends AbstractLoanItemListener {
public ChunkProcessingLoanItemListener(LoanAccountLockRepository accountLockRepository, TransactionTemplate transactionTemplate) {
super(accountLockRepository, transactionTemplate);
public ChunkProcessingLoanItemListener(LoanLockingService loanLockingService, TransactionTemplate transactionTemplate) {
super(loanLockingService, transactionTemplate);
}
@Override
@@ -18,14 +18,14 @@
*/
package org.apache.fineract.cob.listener;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.cob.loan.LoanLockingService;
import org.springframework.transaction.support.TransactionTemplate;
public class InlineCOBLoanItemListener extends AbstractLoanItemListener {
public InlineCOBLoanItemListener(LoanAccountLockRepository accountLockRepository, TransactionTemplate transactionTemplate) {
super(accountLockRepository, transactionTemplate);
public InlineCOBLoanItemListener(LoanLockingService loanLockingService, TransactionTemplate transactionTemplate) {
super(loanLockingService, transactionTemplate);
}
@Override
@@ -39,8 +39,6 @@ public abstract class AbstractLoanItemReader implements ItemReader<Loan> {
protected final LoanRepository loanRepository;
@Setter(AccessLevel.PROTECTED)
private List<Long> alreadyLockedOrProcessedAccounts;
@Setter(AccessLevel.PROTECTED)
private List<Long> remainingData;
private Long loanId;
@@ -21,7 +21,6 @@ package org.apache.fineract.cob.loan;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -32,14 +31,14 @@ import org.springframework.batch.item.data.RepositoryItemWriter;
@RequiredArgsConstructor
public abstract class AbstractLoanItemWriter extends RepositoryItemWriter<Loan> {
private final LoanAccountLockRepository accountLockRepository;
private final LoanLockingService loanLockingService;
@Override
public void write(@NotNull List<? extends Loan> items) throws Exception {
if (!items.isEmpty()) {
super.write(items);
List<Long> loanIds = items.stream().map(AbstractPersistableCustom::getId).toList();
accountLockRepository.deleteByLoanIdInAndLockOwner(loanIds, getLockOwner());
loanLockingService.deleteByLoanIdInAndLockOwner(loanIds, getLockOwner());
}
}
@@ -30,25 +30,21 @@ 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.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.service.DateUtils;
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.item.ExecutionContext;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.jdbc.core.JdbcTemplate;
@Slf4j
@RequiredArgsConstructor
public class ApplyLoanLockTasklet implements Tasklet {
private final LoanAccountLockRepository accountLockRepository;
private final FineractProperties fineractProperties;
private final JdbcTemplate jdbcTemplate;
private final LoanLockingService loanLockingService;
private final RetrieveLoanIdService retrieveLoanIdService;
@Override
@@ -64,9 +60,9 @@ public class ApplyLoanLockTasklet implements Tasklet {
loanIds = new ArrayList<>(
retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter));
}
List<List<Long>> loanIdPartitions = Lists.partition(loanIds, fineractProperties.getQuery().getInClauseParameterSizeLimit());
List<List<Long>> loanIdPartitions = Lists.partition(loanIds, getInClauseParameterSizeLimit());
List<LoanAccountLock> accountLocks = new ArrayList<>();
loanIdPartitions.forEach(loanIdPartition -> accountLocks.addAll(accountLockRepository.findAllByLoanIdIn(loanIdPartition)));
loanIdPartitions.forEach(loanIdPartition -> accountLocks.addAll(loanLockingService.findAllByLoanIdIn(loanIdPartition)));
Map<Long, LoanAccountLock> alreadySoftLockedAccountsMap = accountLocks.stream()
.filter(e -> LockOwner.LOAN_COB_PARTITIONING.equals(e.getLockOwner()))
@@ -77,7 +73,7 @@ public class ApplyLoanLockTasklet implements Tasklet {
List<Long> toBeProcessedLoanIds = new ArrayList<>(alreadySoftLockedAccountsMap.keySet());
upgradeToHardLock(toBeProcessedLoanIds);
loanLockingService.upgradeLock(toBeProcessedLoanIds, LockOwner.LOAN_COB_CHUNK_PROCESSING);
toBeProcessedLoanIds.addAll(alreadyLockedByChunkProcessingAccountIds);
List<Long> alreadyLockedByInlineCOBOrProcessedLoanIds = new ArrayList<>(loanIds);
@@ -88,16 +84,6 @@ public class ApplyLoanLockTasklet implements Tasklet {
return RepeatStatus.FINISHED;
}
private void upgradeToHardLock(List<Long> accountsToLock) {
jdbcTemplate.batchUpdate("""
UPDATE m_loan_account_locks SET version= version + 1, lock_owner = ?, lock_placed_on = ? WHERE loan_id = ?
""", accountsToLock, getInClauseParameterSizeLimit(), (ps, id) -> {
ps.setString(1, LockOwner.LOAN_COB_CHUNK_PROCESSING.name());
ps.setObject(2, DateUtils.getOffsetDateTimeOfTenant());
ps.setLong(3, id);
});
}
private int getInClauseParameterSizeLimit() {
return fineractProperties.getQuery().getInClauseParameterSizeLimit();
}
@@ -18,13 +18,12 @@
*/
package org.apache.fineract.cob.loan;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
public class InlineCOBLoanItemWriter extends AbstractLoanItemWriter {
public InlineCOBLoanItemWriter(LoanAccountLockRepository accountLockRepository) {
super(accountLockRepository);
public InlineCOBLoanItemWriter(LoanLockingService loanLockingService) {
super(loanLockingService);
}
@Override
@@ -25,7 +25,6 @@ import org.apache.fineract.cob.listener.COBExecutionListenerRunner;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.springbatch.PropertyService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
@@ -44,7 +43,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
@EnableBatchIntegration
@@ -76,10 +74,7 @@ public class LoanCOBManagerConfiguration {
@Autowired
private CustomJobParameterResolver customJobParameterResolver;
@Autowired
private LoanRepository loanRepository;
@Autowired
private JdbcTemplate jdbcTemplate;
private LoanLockingService loanLockingService;
@Bean
@JobScope
@@ -123,7 +118,7 @@ public class LoanCOBManagerConfiguration {
@Bean
@JobScope
public LockLoanTasklet lockLoanTasklet() {
return new LockLoanTasklet(jdbcTemplate);
return new LockLoanTasklet(loanLockingService);
}
@Bean
@@ -135,7 +130,7 @@ public class LoanCOBManagerConfiguration {
@Bean
@JobScope
public StayedLockedLoansTasklet stayedLockedTasklet() {
return new StayedLockedLoansTasklet(businessEventNotifierService, loanRepository);
return new StayedLockedLoansTasklet(businessEventNotifierService, retrieveLoanIdService);
}
@Bean(name = "loanCOBJob")
@@ -21,7 +21,6 @@ package org.apache.fineract.cob.loan;
import org.apache.fineract.cob.COBBusinessStepService;
import org.apache.fineract.cob.common.InitialisationTasklet;
import org.apache.fineract.cob.common.ResetContextTasklet;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.listener.ChunkProcessingLoanItemListener;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.jobs.service.JobName;
@@ -41,7 +40,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.support.TransactionTemplate;
@Configuration
@@ -62,8 +60,6 @@ public class LoanCOBWorkerConfiguration {
@Autowired
private COBBusinessStepService cobBusinessStepService;
@Autowired
private LoanAccountLockRepository accountLockRepository;
@Autowired
private AppUserRepositoryWrapper userRepository;
@Autowired
private TransactionTemplate transactionTemplate;
@@ -73,7 +69,7 @@ public class LoanCOBWorkerConfiguration {
@Autowired
private FineractProperties fineractProperties;
@Autowired
private JdbcTemplate jdbcTemplate;
private LoanLockingService loanLockingService;
@Bean(name = LoanCOBConstant.LOAN_COB_WORKER_STEP)
public Step loanCOBWorkerStep() {
@@ -120,12 +116,12 @@ public class LoanCOBWorkerConfiguration {
@Bean
public ChunkProcessingLoanItemListener loanItemListener() {
return new ChunkProcessingLoanItemListener(accountLockRepository, transactionTemplate);
return new ChunkProcessingLoanItemListener(loanLockingService, transactionTemplate);
}
@Bean
public ApplyLoanLockTasklet applyLock() {
return new ApplyLoanLockTasklet(accountLockRepository, fineractProperties, jdbcTemplate, retrieveLoanIdService);
return new ApplyLoanLockTasklet(fineractProperties, loanLockingService, retrieveLoanIdService);
}
@Bean
@@ -148,7 +144,7 @@ public class LoanCOBWorkerConfiguration {
@Bean
@StepScope
public LoanItemWriter cobWorkerItemWriter() {
LoanItemWriter repositoryItemWriter = new LoanItemWriter(accountLockRepository);
LoanItemWriter repositoryItemWriter = new LoanItemWriter(loanLockingService);
repositoryItemWriter.setRepository(loanRepository);
return repositoryItemWriter;
}
@@ -59,6 +59,8 @@ public class LoanInlineCOBConfig {
private TransactionTemplate transactionTemplate;
@Autowired
private CustomJobParameterRepository loanIdListRepository;
@Autowired
private LoanLockingService loanLockingService;
@Bean
public InlineLoanCOBBuildExecutionContextTasklet inlineLoanCOBBuildExecutionContextTasklet() {
@@ -103,14 +105,14 @@ public class LoanInlineCOBConfig {
@Bean
public InlineCOBLoanItemWriter inlineCobWorkerItemWriter() {
InlineCOBLoanItemWriter repositoryItemWriter = new InlineCOBLoanItemWriter(accountLockRepository);
InlineCOBLoanItemWriter repositoryItemWriter = new InlineCOBLoanItemWriter(loanLockingService);
repositoryItemWriter.setRepository(loanRepository);
return repositoryItemWriter;
}
@Bean
public InlineCOBLoanItemListener inlineCobLoanItemListener() {
return new InlineCOBLoanItemListener(accountLockRepository, transactionTemplate);
return new InlineCOBLoanItemListener(loanLockingService, transactionTemplate);
}
@Bean
@@ -18,13 +18,12 @@
*/
package org.apache.fineract.cob.loan;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.domain.LockOwner;
public class LoanItemWriter extends AbstractLoanItemWriter {
public LoanItemWriter(LoanAccountLockRepository accountLockRepository) {
super(accountLockRepository);
public LoanItemWriter(LoanLockingService loanLockingService) {
super(loanLockingService);
}
@Override
@@ -0,0 +1,44 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.cob.loan;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
public class LoanLockingConfiguration {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private FineractProperties fineractProperties;
@Autowired
private LoanAccountLockRepository loanAccountLockRepository;
@Bean
@ConditionalOnMissingBean
public LoanLockingService retrieveLoanLockingService() {
return new LoanLockingServiceImpl(jdbcTemplate, fineractProperties, loanAccountLockRepository);
}
}
@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.cob.loan;
import java.time.LocalDate;
import java.util.List;
import org.apache.fineract.cob.data.LoanCOBParameter;
import org.apache.fineract.cob.domain.LoanAccountLock;
import org.apache.fineract.cob.domain.LockOwner;
public interface LoanLockingService {
void applySoftLock(LocalDate lastClosedBusinessDate, LoanCOBParameter loanCOBParameter);
void upgradeLock(List<Long> accountsToLock, LockOwner lockOwner);
void deleteByLoanIdInAndLockOwner(List<Long> loanIds, LockOwner lockOwner);
List<LoanAccountLock> findAllByLoanIdIn(List<Long> loanIds);
LoanAccountLock findByLoanIdAndLockOwner(Long loanId, LockOwner lockOwner);
}
@@ -0,0 +1,97 @@
/**
* 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.List;
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.springframework.jdbc.core.JdbcTemplate;
@RequiredArgsConstructor
@Slf4j
public class LoanLockingServiceImpl implements LoanLockingService {
private final JdbcTemplate jdbcTemplate;
private final FineractProperties fineractProperties;
private final LoanAccountLockRepository loanAccountLockRepository;
@Override
public void applySoftLock(LocalDate lastClosedBusinessDate, 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, lastClosedBusinessDate);
});
}
@Override
public void upgradeLock(List<Long> accountsToLock, LockOwner lockOwner) {
jdbcTemplate.batchUpdate("""
UPDATE m_loan_account_locks SET version= version + 1, lock_owner = ?, lock_placed_on = ? WHERE loan_id = ?
""", accountsToLock, getInClauseParameterSizeLimit(), (ps, id) -> {
ps.setString(1, lockOwner.name());
ps.setObject(2, DateUtils.getOffsetDateTimeOfTenant());
ps.setLong(3, id);
});
}
@Override
public List<LoanAccountLock> findAllByLoanIdIn(List<Long> loanIds) {
return loanAccountLockRepository.findAllByLoanIdIn(loanIds);
}
@Override
public LoanAccountLock findByLoanIdAndLockOwner(Long loanId, LockOwner lockOwner) {
return loanAccountLockRepository.findByLoanIdAndLockOwner(loanId, lockOwner).orElseGet(() -> {
log.warn("There is no lock for loan account with id: {}", loanId);
return null;
});
}
@Override
public void deleteByLoanIdInAndLockOwner(List<Long> loanIds, LockOwner lockOwner) {
loanAccountLockRepository.deleteByLoanIdInAndLockOwner(loanIds, lockOwner);
}
private int getInClauseParameterSizeLimit() {
return fineractProperties.getQuery().getInClauseParameterSizeLimit();
}
}
@@ -23,28 +23,23 @@ 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;
private final LoanLockingService loanLockingService;
@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))
LocalDate lastClosedBusinessDate = LocalDate.parse(Objects.requireNonNull(businessDateParameter))
.minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND);
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution().getExecutionContext()
.get(LoanCOBConstant.LOAN_COB_PARAMETER);
@@ -52,28 +47,8 @@ public class LockLoanTasklet implements Tasklet {
|| (Objects.isNull(loanCOBParameter.getMinLoanId()) && Objects.isNull(loanCOBParameter.getMaxLoanId()))) {
loanCOBParameter = new LoanCOBParameter(0L, 0L);
}
applySoftLock(businessDate, loanCOBParameter);
loanLockingService.applySoftLock(lastClosedBusinessDate, 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);
});
}
}
@@ -22,6 +22,7 @@ import java.time.LocalDate;
import java.util.List;
import lombok.RequiredArgsConstructor;
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.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
@@ -54,4 +55,9 @@ public class RetrieveAllNonClosedLoanIdServiceImpl implements RetrieveLoanIdServ
ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND));
}
@Override
public List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(LocalDate cobBusinessDate) {
return loanRepository.findAllStayedLockedByCobBusinessDate(cobBusinessDate);
}
}
@@ -21,7 +21,9 @@ 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.LoanIdAndExternalIdAndAccountNo;
import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
import org.springframework.data.repository.query.Param;
public interface RetrieveLoanIdService {
@@ -33,4 +35,6 @@ public interface RetrieveLoanIdService {
List<Long> retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(LoanCOBParameter loanCOBParameter);
List<LoanIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(@Param("cobBusinessDate") LocalDate cobBusinessDate);
}
@@ -29,7 +29,6 @@ import org.apache.fineract.cob.data.LoanIdAndExternalIdAndAccountNo;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
@@ -40,7 +39,7 @@ import org.springframework.batch.repeat.RepeatStatus;
public class StayedLockedLoansTasklet implements Tasklet {
private final BusinessEventNotifierService businessEventNotifierService;
private final LoanRepository loanRepository;
private final RetrieveLoanIdService retrieveLoanIdService;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
@@ -53,7 +52,7 @@ public class StayedLockedLoansTasklet implements Tasklet {
private LoanAccountsStayedLockedData buildLoanAccountData() {
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
List<LoanIdAndExternalIdAndAccountNo> stayedLockedLoanAccounts = loanRepository
List<LoanIdAndExternalIdAndAccountNo> stayedLockedLoanAccounts = retrieveLoanIdService
.findAllStayedLockedByCobBusinessDate(cobBusinessDate);
List<LoanAccountStayedLockedData> loanAccounts = new ArrayList<>();
stayedLockedLoanAccounts.forEach(loanAccount -> {