diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java index 160eee62f..3fff306df 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java @@ -18,8 +18,14 @@ */ package org.apache.fineract.cob.common; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.cob.loan.LoanCOBConstant; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.useradministration.domain.AppUser; @@ -41,11 +47,18 @@ public class InitialisationTasklet implements Tasklet { @Override public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception { + HashMap businessDates = ThreadLocalContextUtil.getBusinessDates(); AppUser user = userRepository.fetchSystemUser(); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), new NullAuthoritiesMapper().mapAuthorities(user.getAuthorities())); SecurityContextHolder.getContext().setAuthentication(auth); ThreadLocalContextUtil.setActionContext(ActionContext.COB); + String businessDateString = Objects.requireNonNull((String) chunkContext.getStepContext().getStepExecution().getJobExecution() + .getExecutionContext().get(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME)); + LocalDate businessDate = LocalDate.parse(businessDateString, DateTimeFormatter.ISO_DATE); + businessDates.put(BusinessDateType.COB_DATE, businessDate); + businessDates.put(BusinessDateType.BUSINESS_DATE, businessDate.plusDays(1)); + ThreadLocalContextUtil.setBusinessDates(businessDates); return RepeatStatus.FINISHED; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java index cb84aa1fc..b24b2b9a4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java @@ -20,12 +20,16 @@ package org.apache.fineract.cob.loan; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.TreeMap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.cob.COBBusinessStepService; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; @@ -37,14 +41,11 @@ 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.stereotype.Component; @Slf4j @RequiredArgsConstructor -@Component public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet { - private final GoogleGsonSerializerHelper gsonFactory; private final COBBusinessStepService cobBusinessStepService; private final CustomJobParameterRepository customJobParameterRepository; @@ -52,15 +53,30 @@ public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + HashMap businessDates = ThreadLocalContextUtil.getBusinessDates(); ThreadLocalContextUtil.setActionContext(ActionContext.COB); TreeMap cobBusinessStepMap = cobBusinessStepService.getCOBBusinessStepMap(LoanCOBBusinessStep.class, LoanCOBConstant.LOAN_COB_JOB_NAME); contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext)); contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_STEP_MAP, cobBusinessStepMap); - + String businessDateString = getBusinessDateFromJobParameters(chunkContext); + contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, businessDateString); + LocalDate businessDate = LocalDate.parse(businessDateString, DateTimeFormatter.ISO_DATE); + businessDates.put(BusinessDateType.COB_DATE, businessDate); + businessDates.put(BusinessDateType.BUSINESS_DATE, businessDate.plusDays(1)); + ThreadLocalContextUtil.setBusinessDates(businessDates); return RepeatStatus.FINISHED; } + private String getBusinessDateFromJobParameters(ChunkContext chunkContext) { + Long customJobParameterId = (Long) chunkContext.getStepContext().getJobParameters() + .get(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME); + CustomJobParameter customJobParameter = customJobParameterRepository.findById(customJobParameterId) + .orElseThrow(() -> new LoanNotFoundException(customJobParameterId)); + String parameterJson = customJobParameter.getParameterJson(); + return gson.fromJson(parameterJson, new TypeToken() {}.getType()); + } + private List getLoanIdsFromJobParameters(ChunkContext chunkContext) { Long customJobParameterId = (Long) chunkContext.getStepContext().getJobParameters() .get(SpringBatchJobConstants.CUSTOM_JOB_PARAMETER_ID_KEY); diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java index 71bf56714..a23bcc1c4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanInlineCOBConfig.java @@ -22,7 +22,6 @@ import org.apache.fineract.cob.COBBusinessStepService; import org.apache.fineract.cob.common.ResetContextTasklet; import org.apache.fineract.cob.domain.LoanAccountLockRepository; import org.apache.fineract.cob.listener.InlineCOBLoanItemListener; -import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameterRepository; import org.apache.fineract.infrastructure.jobs.service.JobName; import org.apache.fineract.infrastructure.springbatch.PropertyService; @@ -60,12 +59,10 @@ public class LoanInlineCOBConfig { private TransactionTemplate transactionTemplate; @Autowired private CustomJobParameterRepository loanIdListRepository; - @Autowired - private GoogleGsonSerializerHelper googleGsonSerializerHelper; @Bean public InlineLoanCOBBuildExecutionContextTasklet inlineLoanCOBBuildExecutionContextTasklet() { - return new InlineLoanCOBBuildExecutionContextTasklet(googleGsonSerializerHelper, cobBusinessStepService, loanIdListRepository); + return new InlineLoanCOBBuildExecutionContextTasklet(cobBusinessStepService, loanIdListRepository); } @Bean @@ -124,7 +121,8 @@ public class LoanInlineCOBConfig { @Bean public ExecutionContextPromotionListener inlineCobPromotionListener() { ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener(); - listener.setKeys(new String[] { LoanCOBConstant.LOAN_IDS, LoanCOBConstant.BUSINESS_STEP_MAP }); + listener.setKeys( + new String[] { LoanCOBConstant.LOAN_IDS, LoanCOBConstant.BUSINESS_STEP_MAP, LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME }); return listener; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java index 5cb920edf..4ce8f9efb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java @@ -21,6 +21,8 @@ package org.apache.fineract.cob.service; import static org.springframework.transaction.TransactionDefinition.PROPAGATION_REQUIRES_NEW; import com.google.gson.Gson; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -102,7 +104,9 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService getJobParametersMap(List loanIds) { + private Map getJobParametersMap(List loanIds, LocalDate businessDate) { // TODO: refactor for a more generic solution String parameterJson = gson.toJson(loanIds); CustomJobParameter loanIdsJobParameter = new CustomJobParameter(); loanIdsJobParameter.setParameterJson(parameterJson); Long loanIdsJobParameterId = customJobParameterRepository.saveAndFlush(loanIdsJobParameter).getId(); + CustomJobParameter businessDateJobParameter = new CustomJobParameter(); + businessDateJobParameter.setParameterJson(gson.toJson(businessDate.format(DateTimeFormatter.ISO_DATE))); + Long businessDateJobParameterId = customJobParameterRepository.saveAndFlush(businessDateJobParameter).getId(); Map jobParameterMap = new HashMap<>(); jobParameterMap.put(SpringBatchJobConstants.CUSTOM_JOB_PARAMETER_ID_KEY, new JobParameter(loanIdsJobParameterId)); - String businessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE).toString(); - jobParameterMap.put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, new JobParameter(businessDate)); + jobParameterMap.put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, new JobParameter(businessDateJobParameterId)); return jobParameterMap; } diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java index cf4a41fe5..80f831f41 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/common/InitialisationTaskletStepDefinitions.java @@ -24,21 +24,34 @@ import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import io.cucumber.java8.En; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import org.apache.fineract.cob.loan.LoanCOBConstant; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.domain.ActionContext; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.scope.context.StepContext; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.security.core.context.SecurityContextHolder; public class InitialisationTaskletStepDefinitions implements En { + private static final LocalDate TODAY = LocalDate.now(ZoneId.systemDefault()); + private AppUserRepositoryWrapper userRepository = mock(AppUserRepositoryWrapper.class); private InitialisationTasklet initialisationTasklet = new InitialisationTasklet(userRepository); private AppUser appUser = mock(AppUser.class); private RepeatStatus resultItem; + private ChunkContext chunkContext; public InitialisationTaskletStepDefinitions() { Given("/^The InitialisationTasklet.execute method with action (.*)$/", (String action) -> { @@ -48,16 +61,29 @@ public class InitialisationTaskletStepDefinitions implements En { } else { lenient().when(this.userRepository.fetchSystemUser()).thenReturn(appUser); } - + HashMap businessDates = new HashMap<>(); + LocalDate businessDate = TODAY; + LocalDate cobBusinessDate = businessDate.minusDays(1); + businessDates.put(BusinessDateType.BUSINESS_DATE, businessDate); + businessDates.put(BusinessDateType.COB_DATE, cobBusinessDate); + ThreadLocalContextUtil.setBusinessDates(businessDates); + JobExecution jobExecution = new JobExecution(1L); + jobExecution.getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, + cobBusinessDate.format(DateTimeFormatter.ISO_DATE)); + StepExecution stepExecution = new StepExecution("step", jobExecution); + StepContext stepContext = new StepContext(stepExecution); + chunkContext = new ChunkContext(stepContext); }); When("InitialisationTasklet.execute method executed", () -> { - resultItem = this.initialisationTasklet.execute(null, null); + resultItem = this.initialisationTasklet.execute(null, chunkContext); }); Then("InitialisationTasklet.execute result should match", () -> { assertEquals(RepeatStatus.FINISHED, resultItem); assertEquals(appUser, SecurityContextHolder.getContext().getAuthentication().getPrincipal()); + assertEquals(TODAY, ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.BUSINESS_DATE)); + assertEquals(TODAY.minusDays(1), ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)); ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); }); @@ -65,6 +91,8 @@ public class InitialisationTaskletStepDefinitions implements En { assertThrows(RuntimeException.class, () -> { resultItem = this.initialisationTasklet.execute(null, null); }); + assertEquals(TODAY, ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.BUSINESS_DATE)); + assertEquals(TODAY.minusDays(1), ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)); ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); }); }