FINERACT-1724: Use services instead of repositories in COB
This commit is contained in:
+6
-6
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
-2
@@ -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;
|
||||
|
||||
+2
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-18
@@ -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();
|
||||
}
|
||||
|
||||
+2
-3
@@ -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
|
||||
|
||||
+3
-8
@@ -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")
|
||||
|
||||
+4
-8
@@ -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;
|
||||
}
|
||||
|
||||
+4
-2
@@ -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
|
||||
|
||||
+44
@@ -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);
|
||||
}
|
||||
+97
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -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 -> {
|
||||
|
||||
+13
-18
@@ -30,11 +30,10 @@ import io.cucumber.java8.En;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
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.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
@@ -45,36 +44,34 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
public class LoanItemListenerStepDefinitions implements En {
|
||||
|
||||
private LoanAccountLockRepository accountLockRepository = mock(LoanAccountLockRepository.class);
|
||||
private LoanLockingService loanLockingService = mock(LoanLockingService.class);
|
||||
private TransactionTemplate transactionTemplate = spy(TransactionTemplate.class);
|
||||
|
||||
private ChunkProcessingLoanItemListener loanItemListener = new ChunkProcessingLoanItemListener(accountLockRepository,
|
||||
transactionTemplate);
|
||||
private ChunkProcessingLoanItemListener loanItemListener = new ChunkProcessingLoanItemListener(loanLockingService, transactionTemplate);
|
||||
|
||||
private Exception exception;
|
||||
|
||||
private LoanAccountLock loanAccountLock;
|
||||
private Loan loan = mock(Loan.class);
|
||||
private final Loan loan = mock(Loan.class);
|
||||
|
||||
public LoanItemListenerStepDefinitions() {
|
||||
Given("/^The LoanItemListener.onReadError method (.*)$/", (String action) -> {
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
exception = new LoanReadException(1L, new RuntimeException("fail"));
|
||||
loanAccountLock = new LoanAccountLock(1L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()));
|
||||
when(accountLockRepository.findByLoanIdAndLockOwner(1L, LockOwner.LOAN_COB_CHUNK_PROCESSING))
|
||||
.thenReturn(Optional.of(loanAccountLock));
|
||||
when(loanLockingService.findByLoanIdAndLockOwner(1L, LockOwner.LOAN_COB_CHUNK_PROCESSING)).thenReturn(loanAccountLock);
|
||||
transactionTemplate.setTransactionManager(mock(PlatformTransactionManager.class));
|
||||
when(loan.getId()).thenReturn(1L);
|
||||
});
|
||||
|
||||
When("LoanItemListener.onReadError method executed", () -> {
|
||||
this.loanItemListener.onReadError(exception);
|
||||
loanItemListener.onReadError(exception);
|
||||
});
|
||||
|
||||
Then("LoanItemListener.onReadError result should match", () -> {
|
||||
verify(transactionTemplate, Mockito.times(1)).setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
verify(transactionTemplate, Mockito.times(1)).execute(any());
|
||||
verify(accountLockRepository, Mockito.times(1)).findByLoanIdAndLockOwner(1L, LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
verify(loanLockingService, Mockito.times(1)).findByLoanIdAndLockOwner(1L, LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
assertEquals("Loan (id: 1) reading is failed", loanAccountLock.getError());
|
||||
assertNotNull(loanAccountLock.getStacktrace());
|
||||
});
|
||||
@@ -83,20 +80,19 @@ public class LoanItemListenerStepDefinitions implements En {
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
exception = new LoanReadException(1L, new RuntimeException("fail"));
|
||||
loanAccountLock = new LoanAccountLock(2L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()));
|
||||
when(accountLockRepository.findByLoanIdAndLockOwner(2L, LockOwner.LOAN_COB_CHUNK_PROCESSING))
|
||||
.thenReturn(Optional.of(loanAccountLock));
|
||||
when(loanLockingService.findByLoanIdAndLockOwner(2L, LockOwner.LOAN_COB_CHUNK_PROCESSING)).thenReturn(loanAccountLock);
|
||||
when(loan.getId()).thenReturn(2L);
|
||||
transactionTemplate.setTransactionManager(mock(PlatformTransactionManager.class));
|
||||
});
|
||||
|
||||
When("LoanItemListener.onProcessError method executed", () -> {
|
||||
this.loanItemListener.onProcessError(loan, exception);
|
||||
loanItemListener.onProcessError(loan, exception);
|
||||
});
|
||||
|
||||
Then("LoanItemListener.onProcessError result should match", () -> {
|
||||
verify(transactionTemplate, Mockito.times(1)).setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
verify(transactionTemplate, Mockito.times(1)).execute(any());
|
||||
verify(accountLockRepository, Mockito.times(1)).findByLoanIdAndLockOwner(2L, LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
verify(loanLockingService, Mockito.times(1)).findByLoanIdAndLockOwner(2L, LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
assertEquals("Loan (id: 2) processing is failed", loanAccountLock.getError());
|
||||
assertNotNull(loanAccountLock.getStacktrace());
|
||||
});
|
||||
@@ -105,20 +101,19 @@ public class LoanItemListenerStepDefinitions implements En {
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
exception = new LoanReadException(3L, new RuntimeException("fail"));
|
||||
loanAccountLock = new LoanAccountLock(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()));
|
||||
when(accountLockRepository.findByLoanIdAndLockOwner(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING))
|
||||
.thenReturn(Optional.of(loanAccountLock));
|
||||
when(loanLockingService.findByLoanIdAndLockOwner(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING)).thenReturn(loanAccountLock);
|
||||
when(loan.getId()).thenReturn(3L);
|
||||
transactionTemplate.setTransactionManager(mock(PlatformTransactionManager.class));
|
||||
});
|
||||
|
||||
When("LoanItemListener.onWriteError method executed", () -> {
|
||||
this.loanItemListener.onWriteError(exception, List.of(loan));
|
||||
loanItemListener.onWriteError(exception, List.of(loan));
|
||||
});
|
||||
|
||||
Then("LoanItemListener.onWriteError result should match", () -> {
|
||||
verify(transactionTemplate, Mockito.times(1)).setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
verify(transactionTemplate, Mockito.times(1)).execute(any());
|
||||
verify(accountLockRepository, Mockito.times(1)).findByLoanIdAndLockOwner(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
verify(loanLockingService, Mockito.times(1)).findByLoanIdAndLockOwner(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING);
|
||||
assertEquals("Loan (id: 3) writing is failed", loanAccountLock.getError());
|
||||
assertNotNull(loanAccountLock.getStacktrace());
|
||||
});
|
||||
|
||||
+11
-14
@@ -31,7 +31,6 @@ 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;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
@@ -43,18 +42,16 @@ import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter;
|
||||
|
||||
public class ApplyLoanLockTaskletStepDefinitions implements En {
|
||||
|
||||
ArgumentCaptor<List> valueCaptor = ArgumentCaptor.forClass(List.class);
|
||||
private LoanAccountLockRepository accountLockRepository = mock(LoanAccountLockRepository.class);
|
||||
ArgumentCaptor<LockOwner> lockOwnerValueCaptor = ArgumentCaptor.forClass(LockOwner.class);
|
||||
private LoanLockingService loanLockingService = mock(LoanLockingService.class);
|
||||
private FineractProperties fineractProperties = mock(FineractProperties.class);
|
||||
private JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
|
||||
private FineractProperties.FineractQueryProperties fineractQueryProperties = mock(FineractProperties.FineractQueryProperties.class);
|
||||
private RetrieveLoanIdService retrieveLoanIdService = mock(RetrieveLoanIdService.class);
|
||||
private ApplyLoanLockTasklet applyLoanLockTasklet = new ApplyLoanLockTasklet(accountLockRepository, fineractProperties, jdbcTemplate,
|
||||
private ApplyLoanLockTasklet applyLoanLockTasklet = new ApplyLoanLockTasklet(fineractProperties, loanLockingService,
|
||||
retrieveLoanIdService);
|
||||
private RepeatStatus resultItem;
|
||||
private StepContribution stepContribution;
|
||||
@@ -69,15 +66,15 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
|
||||
ExecutionContext executionContext = new ExecutionContext();
|
||||
LoanCOBParameter loanCOBParameter = new LoanCOBParameter(1L, 4L);
|
||||
executionContext.put(LoanCOBConstant.LOAN_COB_PARAMETER, loanCOBParameter);
|
||||
lenient().when(this.retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter))
|
||||
lenient().when(retrieveLoanIdService.retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter))
|
||||
.thenReturn(List.of(1L, 2L, 3L, 4L));
|
||||
stepExecution.setExecutionContext(executionContext);
|
||||
this.stepContribution = new StepContribution(stepExecution);
|
||||
stepContribution = new StepContribution(stepExecution);
|
||||
|
||||
if ("error".equals(action)) {
|
||||
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
|
||||
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
|
||||
lenient().when(this.accountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenThrow(new RuntimeException("fail"));
|
||||
lenient().when(loanLockingService.findAllByLoanIdIn(Mockito.anyList())).thenThrow(new RuntimeException("fail"));
|
||||
} else {
|
||||
LoanAccountLock lock1 = new LoanAccountLock(1L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()));
|
||||
LoanAccountLock lock2 = new LoanAccountLock(2L, LockOwner.LOAN_COB_PARTITIONING, LocalDate.now(ZoneId.systemDefault()));
|
||||
@@ -86,26 +83,26 @@ public class ApplyLoanLockTaskletStepDefinitions implements En {
|
||||
List<LoanAccountLock> accountLocks = List.of(lock1, lock2, lock3);
|
||||
lenient().when(fineractProperties.getQuery()).thenReturn(fineractQueryProperties);
|
||||
lenient().when(fineractQueryProperties.getInClauseParameterSizeLimit()).thenReturn(65000);
|
||||
lenient().when(this.accountLockRepository.findAllByLoanIdIn(Mockito.anyList())).thenReturn(accountLocks);
|
||||
lenient().when(loanLockingService.findAllByLoanIdIn(Mockito.anyList())).thenReturn(accountLocks);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
When("ApplyLoanLockTasklet.execute method executed", () -> {
|
||||
resultItem = this.applyLoanLockTasklet.execute(stepContribution, null);
|
||||
resultItem = applyLoanLockTasklet.execute(stepContribution, null);
|
||||
});
|
||||
|
||||
Then("ApplyLoanLockTasklet.execute result should match", () -> {
|
||||
assertEquals(RepeatStatus.FINISHED, resultItem);
|
||||
verify(this.jdbcTemplate, Mockito.times(1)).batchUpdate(Mockito.anyString(), valueCaptor.capture(), Mockito.anyInt(),
|
||||
Mockito.any(ParameterizedPreparedStatementSetter.class));
|
||||
verify(loanLockingService, Mockito.times(1)).upgradeLock(valueCaptor.capture(), lockOwnerValueCaptor.capture());
|
||||
List<Long> values = valueCaptor.getValue();
|
||||
assertEquals(2L, values.get(0));
|
||||
assertEquals(LockOwner.LOAN_COB_CHUNK_PROCESSING, lockOwnerValueCaptor.getValue());
|
||||
});
|
||||
|
||||
Then("throw exception ApplyLoanLockTasklet.execute method", () -> {
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
resultItem = this.applyLoanLockTasklet.execute(stepContribution, null);
|
||||
resultItem = applyLoanLockTasklet.execute(stepContribution, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+22
-12
@@ -19,8 +19,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.anyString;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -39,26 +37,26 @@ 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.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
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 FineractProperties fineractProperties = mock(FineractProperties.class);
|
||||
private final FineractProperties.FineractQueryProperties fineractQueryProperties = mock(
|
||||
FineractProperties.FineractQueryProperties.class);
|
||||
StepContribution contribution;
|
||||
ArgumentCaptor<LocalDate> dateValueCaptor = ArgumentCaptor.forClass(LocalDate.class);
|
||||
ArgumentCaptor<LoanCOBParameter> loanCOBParameterValueCaptor = ArgumentCaptor.forClass(LoanCOBParameter.class);
|
||||
private LockLoanTasklet lockLoanTasklet;
|
||||
private String action;
|
||||
private RepeatStatus result;
|
||||
private JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
|
||||
private final LoanLockingService loanLockingService = mock(LoanLockingService.class);
|
||||
|
||||
public FetchAndLockLoanStepDefinitions() {
|
||||
Given("/^The FetchAndLockLoanTasklet.execute method with action (.*)$/", (String action) -> {
|
||||
@@ -106,18 +104,21 @@ public class FetchAndLockLoanStepDefinitions implements En {
|
||||
List.of(new LoanAccountLock(3L, LockOwner.LOAN_COB_CHUNK_PROCESSING, LocalDate.now(ZoneId.systemDefault()))));
|
||||
}
|
||||
|
||||
lockLoanTasklet = new LockLoanTasklet(jdbcTemplate);
|
||||
lockLoanTasklet = new LockLoanTasklet(loanLockingService);
|
||||
});
|
||||
|
||||
When("FetchAndLockLoanTasklet.execute method executed", () -> {
|
||||
result = this.lockLoanTasklet.execute(contribution, null);
|
||||
result = 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).update(anyString(), (PreparedStatementSetter) any());
|
||||
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture());
|
||||
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
|
||||
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
|
||||
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
|
||||
assertEquals(RepeatStatus.FINISHED, result);
|
||||
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
|
||||
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
|
||||
@@ -125,7 +126,10 @@ public class FetchAndLockLoanStepDefinitions implements En {
|
||||
assertEquals(1L, loanCOBParameter.getMinLoanId());
|
||||
assertEquals(3L, loanCOBParameter.getMaxLoanId());
|
||||
} else if ("soft lock".equals(action)) {
|
||||
verify(jdbcTemplate).update(anyString(), (PreparedStatementSetter) any());
|
||||
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture());
|
||||
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
|
||||
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
|
||||
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
|
||||
assertEquals(RepeatStatus.FINISHED, result);
|
||||
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
|
||||
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
|
||||
@@ -133,7 +137,10 @@ public class FetchAndLockLoanStepDefinitions implements En {
|
||||
assertEquals(1L, loanCOBParameter.getMinLoanId());
|
||||
assertEquals(3L, loanCOBParameter.getMaxLoanId());
|
||||
} else if ("inline cob".equals(action)) {
|
||||
verify(jdbcTemplate).update(anyString(), (PreparedStatementSetter) any());
|
||||
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture());
|
||||
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
|
||||
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
|
||||
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
|
||||
assertEquals(RepeatStatus.FINISHED, result);
|
||||
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
|
||||
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
|
||||
@@ -141,7 +148,10 @@ public class FetchAndLockLoanStepDefinitions implements En {
|
||||
assertEquals(1L, loanCOBParameter.getMinLoanId());
|
||||
assertEquals(3L, loanCOBParameter.getMaxLoanId());
|
||||
} else if ("chunk processing".equals(action)) {
|
||||
verify(jdbcTemplate).update(anyString(), (PreparedStatementSetter) any());
|
||||
verify(loanLockingService).applySoftLock(dateValueCaptor.capture(), loanCOBParameterValueCaptor.capture());
|
||||
assertEquals(LocalDate.now(ZoneId.systemDefault()).minusDays(1), dateValueCaptor.getValue());
|
||||
assertEquals(1L, loanCOBParameterValueCaptor.getValue().getMinLoanId());
|
||||
assertEquals(3L, loanCOBParameterValueCaptor.getValue().getMaxLoanId());
|
||||
assertEquals(RepeatStatus.FINISHED, result);
|
||||
LoanCOBParameter loanCOBParameter = (LoanCOBParameter) contribution.getStepExecution().getJobExecution()
|
||||
.getExecutionContext().get(LoanCOBConstant.LOAN_COB_PARAMETER);
|
||||
|
||||
+10
-11
@@ -25,17 +25,16 @@ import static org.mockito.Mockito.verify;
|
||||
import io.cucumber.java8.En;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class LoanItemWriterStepDefinitions implements En {
|
||||
|
||||
private LoanAccountLockRepository accountLockRepository = mock(LoanAccountLockRepository.class);
|
||||
private LoanRepository loanRepository = mock(LoanRepository.class);
|
||||
private final LoanLockingService loanLockingService = mock(LoanLockingService.class);
|
||||
private final LoanRepository loanRepository = mock(LoanRepository.class);
|
||||
|
||||
private LoanItemWriter loanItemWriter = new LoanItemWriter(accountLockRepository);
|
||||
private final LoanItemWriter loanItemWriter = new LoanItemWriter(loanLockingService);
|
||||
|
||||
private List<Loan> items;
|
||||
|
||||
@@ -45,24 +44,24 @@ public class LoanItemWriterStepDefinitions implements En {
|
||||
Loan loan = mock(Loan.class);
|
||||
lenient().when(loan.getId()).thenReturn(1L);
|
||||
if (action.equals("error")) {
|
||||
this.items = Collections.emptyList();
|
||||
items = Collections.emptyList();
|
||||
} else {
|
||||
this.items = Collections.singletonList(loan);
|
||||
lenient().doNothing().when(this.accountLockRepository).deleteByLoanIdInAndLockOwner(Mockito.anyList(), Mockito.any());
|
||||
items = Collections.singletonList(loan);
|
||||
lenient().doNothing().when(loanLockingService).deleteByLoanIdInAndLockOwner(Mockito.anyList(), Mockito.any());
|
||||
}
|
||||
this.loanItemWriter.setRepository(loanRepository);
|
||||
loanItemWriter.setRepository(loanRepository);
|
||||
});
|
||||
|
||||
When("LoanItemWriter.write method executed", () -> {
|
||||
this.loanItemWriter.write(items);
|
||||
loanItemWriter.write(items);
|
||||
});
|
||||
|
||||
Then("LoanItemWriter.write result should match", () -> {
|
||||
verify(this.accountLockRepository, Mockito.times(1)).deleteByLoanIdInAndLockOwner(Mockito.any(), Mockito.any());
|
||||
verify(loanLockingService, Mockito.times(1)).deleteByLoanIdInAndLockOwner(Mockito.any(), Mockito.any());
|
||||
});
|
||||
|
||||
Then("LoanItemWriter.write should not call repository", () -> {
|
||||
verify(this.accountLockRepository, Mockito.times(0)).deleteByLoanIdInAndLockOwner(Mockito.any(), Mockito.any());
|
||||
verify(loanLockingService, Mockito.times(0)).deleteByLoanIdInAndLockOwner(Mockito.any(), Mockito.any());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user