Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.apache.fineract.cob.domain;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
Expand Down Expand Up @@ -49,4 +50,6 @@ public interface LoanAccountLockRepository
@Override
void removeByLockOwnerInAndErrorIsNotNullAndLockPlacedOnCobBusinessDateIsNotNull(List<LockOwner> lockOwners);

void deleteByLockOwnerAndErrorIsNullAndLockPlacedOnCobBusinessDate(LockOwner lockOwner, LocalDate cobBusinessDate);

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.apache.fineract.cob.COBBusinessStepService;
import org.apache.fineract.cob.common.CustomJobParameterResolver;
import org.apache.fineract.cob.conditions.BatchManagerCondition;
import org.apache.fineract.cob.domain.LoanAccountLockRepository;
import org.apache.fineract.cob.listener.COBExecutionListenerRunner;
import org.apache.fineract.cob.service.RetrieveLoanIdService;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
Expand Down Expand Up @@ -76,6 +77,8 @@ public class LoanCOBManagerConfiguration {
private BusinessEventNotifierService businessEventNotifierService;
@Autowired
private CustomJobParameterResolver customJobParameterResolver;
@Autowired
private LoanAccountLockRepository loanAccountLockRepository;

@Bean
@StepScope
Expand Down Expand Up @@ -103,6 +106,12 @@ public Step stayedLockedStep() {
.build();
}

@Bean
public Step unlockProcessedLoansStep() {
return new StepBuilder("Unlock processed loans - Step", jobRepository).tasklet(unlockProcessedLoansTasklet(), transactionManager)
.build();
}

@Bean
public ResolveLoanCOBCustomJobParametersTasklet resolveCustomJobParametersTasklet() {
return new ResolveLoanCOBCustomJobParametersTasklet(customJobParameterResolver);
Expand All @@ -113,13 +122,19 @@ public StayedLockedLoansTasklet stayedLockedTasklet() {
return new StayedLockedLoansTasklet(businessEventNotifierService, retrieveIdService);
}

@Bean
public UnlockProcessedLoansTasklet unlockProcessedLoansTasklet() {
return new UnlockProcessedLoansTasklet(loanAccountLockRepository);
}

@Bean(name = "loanCOBJob")
public Job loanCOBJob(LoanCOBPartitioner partitioner) {
return new JobBuilder(JobName.LOAN_COB.name(), jobRepository) //
.listener(new COBExecutionListenerRunner(applicationContext, JobName.LOAN_COB.name())) //
.start(resolveCustomJobParametersStep()) //
.next(loanCOBStep(partitioner)) //
.next(stayedLockedStep()) //
.next(unlockProcessedLoansStep()) //
.incrementer(new RunIdIncrementer()) //
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* 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 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.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
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 UnlockProcessedLoansTasklet implements Tasklet {

private final LoanAccountLockRepository loanAccountLockRepository;

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
log.debug("Removing orphaned locks for successfully processed loans on COB date: {}", cobBusinessDate);
loanAccountLockRepository.deleteByLockOwnerAndErrorIsNullAndLockPlacedOnCobBusinessDate(LockOwner.LOAN_COB_CHUNK_PROCESSING,
cobBusinessDate);
return RepeatStatus.FINISHED;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* 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 static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import io.cucumber.java8.En;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.HashMap;
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.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
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;

public class UnlockProcessedLoansTaskletStepDefinitions implements En {

private LoanAccountLockRepository loanAccountLockRepository = mock(LoanAccountLockRepository.class);
private UnlockProcessedLoansTasklet tasklet = new UnlockProcessedLoansTasklet(loanAccountLockRepository);
private RepeatStatus resultItem;
private StepContribution stepContribution;
private LocalDate cobDate;

public UnlockProcessedLoansTaskletStepDefinitions() {
Given("The UnlockProcessedLoansTasklet.execute method is called", () -> {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
HashMap<BusinessDateType, LocalDate> businessDateMap = new HashMap<>();
cobDate = LocalDate.now(ZoneId.systemDefault());
businessDateMap.put(BusinessDateType.COB_DATE, cobDate);
ThreadLocalContextUtil.setBusinessDates(businessDateMap);
JobExecution jobExecution = new JobExecution(1L, null);
StepExecution stepExecution = new StepExecution("test", jobExecution);
stepContribution = new StepContribution(stepExecution);
});

When("UnlockProcessedLoansTasklet.execute method executed", () -> {
try {
resultItem = tasklet.execute(stepContribution, null);
} finally {
ThreadLocalContextUtil.reset();
}
});

Then("UnlockProcessedLoansTasklet.execute result should match", () -> {
assertEquals(RepeatStatus.FINISHED, resultItem);
verify(loanAccountLockRepository, Mockito.times(1))
.deleteByLockOwnerAndErrorIsNullAndLockPlacedOnCobBusinessDate(LockOwner.LOAN_COB_CHUNK_PROCESSING, cobDate);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#
# 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.
#
Feature: COB Unlock Processed Loans Step
@cob
Scenario: UnlockProcessedLoansTasklet - run test
Given The UnlockProcessedLoansTasklet.execute method is called
When UnlockProcessedLoansTasklet.execute method executed
Then UnlockProcessedLoansTasklet.execute result should match
Loading