This is an automated email from the ASF dual-hosted git repository. arnold pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract.git
commit f26e14ae0718f81f076ae0ccea69a54835a48d49 Author: Jose Alberto Hernandez <[email protected]> AuthorDate: Mon Sep 5 16:33:29 2022 -0500 Delinquency classification as a Loan COB business step --- .../fineract/cob/loan/InitialisationTasklet.java | 62 ++++++++++++ .../cob/loan/LoanCOBWorkerConfiguration.java | 30 +++++- .../loan/SetLoanDelinquencyTagsBusinessStep.java | 52 ++++++++++ .../service/DelinquencyWritePlatformService.java | 2 - .../DelinquencyWritePlatformServiceImpl.java | 11 --- .../portfolio/loanaccount/domain/Loan.java | 3 +- .../db/changelog/tenant/changelog-tenant.xml | 1 + ...047_add_loan_delinquency_tags_business_step.xml | 32 +++++++ .../BusinessConfigurationApiTest.java | 7 +- .../DelinquencyBucketsIntegrationTest.java | 105 ++++++++++++++++++++- 10 files changed, 283 insertions(+), 22 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InitialisationTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InitialisationTasklet.java new file mode 100644 index 000000000..f352c17b8 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/InitialisationTasklet.java @@ -0,0 +1,62 @@ +/** + * 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 lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.useradministration.domain.AppUser; +import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; +import org.jetbrains.annotations.NotNull; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.StepExecutionListener; +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.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper; +import org.springframework.security.core.context.SecurityContextHolder; + +@Slf4j +@RequiredArgsConstructor +public class InitialisationTasklet implements Tasklet, StepExecutionListener { + + private final AppUserRepositoryWrapper userRepository; + private StepExecution stepExecution; + + @Override + public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception { + AppUser user = userRepository.fetchSystemUser(); + UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), + new NullAuthoritiesMapper().mapAuthorities(user.getAuthorities())); + SecurityContextHolder.getContext().setAuthentication(auth); + return RepeatStatus.FINISHED; + } + + @Override + public void beforeStep(@NotNull StepExecution stepExecution) { + this.stepExecution = stepExecution; + } + + @Override + public ExitStatus afterStep(@NotNull StepExecution stepExecution) { + return ExitStatus.COMPLETED; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java index ddee35820..efe17a38f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/LoanCOBWorkerConfiguration.java @@ -25,10 +25,13 @@ import org.apache.fineract.cob.COBPropertyService; import org.apache.fineract.infrastructure.jobs.service.JobName; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; +import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepScope; +import org.springframework.batch.core.job.builder.FlowBuilder; +import org.springframework.batch.core.job.flow.Flow; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.integration.partition.RemotePartitioningWorkerStepBuilderFactory; import org.springframework.batch.item.ItemProcessor; @@ -57,19 +60,42 @@ public class LoanCOBWorkerConfiguration { private QueueChannel inboundRequests; @Autowired private COBBusinessStepService cobBusinessStepService; + @Autowired + private AppUserRepositoryWrapper userRepository; - @Bean(name = "Loan COB worker") - public Step loanCOBWorkerStep() { + @Bean + public Step loanBusinessStep() { return stepBuilderFactory.get("Loan COB worker").inputChannel(inboundRequests) .<Loan, Loan>chunk(cobPropertyService.getChunkSize(JobName.LOAN_COB.name())).reader(itemReader(null)) .processor(itemProcessor()).writer(itemWriter()).build(); } + @Bean(name = "Loan COB worker") + public Step loanCOBWorkerStep() { + return stepBuilderFactory.get("Loan COB worker - Step").inputChannel(inboundRequests).flow(flow()).build(); + } + @Bean public Job loanCOBWorkerJob() { return jobBuilderFactory.get("Loan COB worker").start(loanCOBWorkerStep()).incrementer(new RunIdIncrementer()).build(); } + @Bean + public Flow flow() { + return new FlowBuilder<Flow>("cobFlow").start(initialisationStep()).next(loanBusinessStep()).next(loanBusinessStep()).build(); + } + + @Bean + public Step initialisationStep() { + return stepBuilderFactory.get("Initalisation - Step").inputChannel(inboundRequests).tasklet(initialiseContext()).build(); + } + + @Bean + @StepScope + public InitialisationTasklet initialiseContext() { + return new InitialisationTasklet(userRepository); + } + @Bean @StepScope public ItemReader<Loan> itemReader(@Value("#{stepExecutionContext['loanIds']}") List<Integer> data) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStep.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStep.java new file mode 100644 index 000000000..d0a1168e8 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStep.java @@ -0,0 +1,52 @@ +/** + * 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 lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class SetLoanDelinquencyTagsBusinessStep implements LoanCOBBusinessStep { + + private final LoanAccountDomainService loanAccountDomainService; + + @Override + public Loan execute(Loan loan) { + log.debug("Set Loan Delinquency Tags Business Step {}", loan.getId()); + loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate()); + return loan; + } + + @Override + public String getEnumStyledName() { + return "LOAN_DELINQUENCY_CLASSIFICATION"; + } + + @Override + public String getHumanReadableName() { + return "Loan Delinquency Classification"; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java index b2ee3bac2..8795ace83 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java @@ -30,8 +30,6 @@ public interface DelinquencyWritePlatformService { CommandProcessingResult deleteDelinquencyRange(Long delinquencyRangeId, JsonCommand command); - CommandProcessingResult setLoanDelinquencyTag(Long loanId, Long delinquencyRangeId, JsonCommand command); - CommandProcessingResult createDelinquencyBucket(JsonCommand command); CommandProcessingResult updateDelinquencyBucket(Long delinquencyBucketId, JsonCommand command); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java index 45fa65f63..4d1dc384c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java @@ -104,12 +104,6 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyRange.getId()).build(); } - @Override - public CommandProcessingResult setLoanDelinquencyTag(Long loanId, Long delinquencyRangeId, JsonCommand command) { - setLoanDelinquencyTag(loanId, delinquencyRangeId); - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(loanId).build(); - } - @Override public CommandProcessingResult createDelinquencyBucket(JsonCommand command) { DelinquencyBucketData data = dataValidatorBucket.validateAndParseUpdate(command); @@ -328,11 +322,6 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat return changes; } - public Map<String, Object> setLoanDelinquencyTag(Long loanId, Long delinquencyRangeId) { - final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId); - return setLoanDelinquencyTag(loan, delinquencyRangeId); - } - public Map<String, Object> setLoanDelinquencyTag(Loan loan, Long delinquencyRangeId) { Map<String, Object> changes = new HashMap<>(); List<LoanDelinquencyTagHistory> loanDelinquencyTagHistory = new ArrayList<>(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index e5bbb38a7..95088b15e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -27,7 +27,6 @@ import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; @@ -3770,7 +3769,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate); } - LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant(); loanTransaction = LoanTransaction.writeoff(this, getOffice(), writtenOffOnLocalDate, txnExternalId); LocalDate lastTransactionDate = getLastUserTransactionDate(); if (lastTransactionDate.isAfter(writtenOffOnLocalDate)) { @@ -6877,4 +6875,5 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } return ageOfOverdueDays; } + } diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 73aee0f7c..d79f96d5c 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -66,4 +66,5 @@ <include file="parts/0044_table_report_query_fix.xml" relativeToChangelogFile="true"/> <include file="parts/0045_external_event_table_data_binary.xml" relativeToChangelogFile="true"/> <include file="parts/0046_external_event_table_schema_info.xml" relativeToChangelogFile="true"/> + <include file="parts/0047_add_loan_delinquency_tags_business_step.xml" relativeToChangelogFile="true"/> </databaseChangeLog> diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0047_add_loan_delinquency_tags_business_step.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0047_add_loan_delinquency_tags_business_step.xml new file mode 100644 index 000000000..aa8416636 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0047_add_loan_delinquency_tags_business_step.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd"> + <changeSet id="1" author="fineract"> + <insert tableName="m_batch_business_steps"> + <column name="job_name" value="LOAN_CLOSE_OF_BUSINESS"/> + <column name="step_name" value="LOAN_DELINQUENCY_CLASSIFICATION"/> + <column name="step_order" value="2"/> + </insert> + </changeSet> +</databaseChangeLog> diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BusinessConfigurationApiTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BusinessConfigurationApiTest.java index 0e10b2253..8f1031396 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BusinessConfigurationApiTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BusinessConfigurationApiTest.java @@ -41,9 +41,10 @@ public class BusinessConfigurationApiTest { private ResponseSpecification responseSpec; private RequestSpecification requestSpec; - private static final String LOAN_JOB_NAME = "LOAN_CLOSE_OF_BUSINESS"; - private static final String LOAN_CATEGORY_NAME = "loan"; - private static final String APPLY_CHARGE_TO_OVERDUE_LOANS = "APPLY_CHARGE_TO_OVERDUE_LOANS"; + public static final String LOAN_JOB_NAME = "LOAN_CLOSE_OF_BUSINESS"; + public static final String LOAN_CATEGORY_NAME = "loan"; + public static final String APPLY_CHARGE_TO_OVERDUE_LOANS = "APPLY_CHARGE_TO_OVERDUE_LOANS"; + public static final String LOAN_DELINQUENCY_CLASSIFICATION = "LOAN_DELINQUENCY_CLASSIFICATION"; @BeforeEach public void setup() { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java index 242156523..1efd1d9af 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java @@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; @@ -46,8 +47,10 @@ import org.apache.fineract.client.models.PostDelinquencyRangeResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PutDelinquencyBucketResponse; import org.apache.fineract.client.models.PutDelinquencyRangeResponse; +import org.apache.fineract.cob.data.JobBusinessStepConfigData; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.integrationtests.common.BusinessDateHelper; +import org.apache.fineract.integrationtests.common.BusinessStepConfigurationHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; import org.apache.fineract.integrationtests.common.SchedulerJobHelper; @@ -237,7 +240,6 @@ public class DelinquencyBucketsIntegrationTest { log.info("Current date {}", businessDate); BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate); - // Given final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); final SchedulerJobHelper schedulerJobHelper = new SchedulerJobHelper(requestSpec); @@ -279,7 +281,6 @@ public class DelinquencyBucketsIntegrationTest { final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(), getLoanProductsProductResponse.getId().toString(), operationDate); - // When // Run first time the Job final String jobName = "Loan Delinquency Classification"; schedulerJobHelper.executeAndAwaitJob(jobName); @@ -320,6 +321,106 @@ public class DelinquencyBucketsIntegrationTest { GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); } + @Test + public void testLoanClassificationStepAsPartOfCOB() { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); + + LocalDate businessDate = Utils.getLocalDateOfTenant(); + businessDate = businessDate.minusDays(57); + log.info("Current date {}", businessDate); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate); + + // Given + final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + final SchedulerJobHelper schedulerJobHelper = new SchedulerJobHelper(requestSpec); + + ArrayList<Integer> rangeIds = new ArrayList<>(); + String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3); + PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, + jsonRange); + rangeIds.add(delinquencyRangeResponse.getResourceId()); + jsonRange = DelinquencyRangesHelper.getAsJSON(4, 60); + // Create + delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange); + rangeIds.add(delinquencyRangeResponse.getResourceId()); + + final GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec, + delinquencyRangeResponse.getResourceId()); + final String classificationExpected = range.getClassification(); + log.info("Expected Delinquency Range classification {}", classificationExpected); + + String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds); + PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, + responseSpec, jsonBucket); + final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec, + delinquencyBucketResponse.getResourceId()); + + // Client and Loan account creation + final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012"); + final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper, + delinquencyBucket.getId()); + assertNotNull(getLoanProductsProductResponse); + log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName()); + assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName()); + + final LocalDate todaysDate = Utils.getLocalDateOfTenant(); + // Older date to have more than one overdue installment + final LocalDate transactionDate = todaysDate.minusDays(65); + String operationDate = Utils.dateFormatter.format(transactionDate); + + // Create Loan Account + final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(), + getLoanProductsProductResponse.getId().toString(), operationDate); + + // COB Step Validation + final JobBusinessStepConfigData jobBusinessStepConfigData = BusinessStepConfigurationHelper + .getConfiguredBusinessStepsByJobName(requestSpec, responseSpec, BusinessConfigurationApiTest.LOAN_JOB_NAME); + assertNotNull(jobBusinessStepConfigData); + assertEquals(BusinessConfigurationApiTest.LOAN_JOB_NAME, jobBusinessStepConfigData.getJobName()); + assertTrue(jobBusinessStepConfigData.getBusinessSteps().size() > 0); + assertTrue(jobBusinessStepConfigData.getBusinessSteps().stream() + .anyMatch(businessStep -> BusinessConfigurationApiTest.LOAN_DELINQUENCY_CLASSIFICATION.equals(businessStep.getStepName()))); + + // Run first time the Loan COB Job + final String jobName = "Loan COB"; + schedulerJobHelper.executeAndAwaitJob(jobName); + + // Get loan details expecting to have not a delinquency classification + GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + final GetDelinquencyRangesResponse firstTestCase = getLoansLoanIdResponse.getDelinquencyRange(); + log.info("Loan Delinquency Range is null {}", (firstTestCase == null)); + GetLoansLoanIdRepaymentSchedule getLoanRepaymentSchedule = getLoansLoanIdResponse.getRepaymentSchedule(); + if (getLoanRepaymentSchedule != null) { + log.info("Loan with {} periods", getLoanRepaymentSchedule.getPeriods().size()); + for (GetLoansLoanIdRepaymentPeriod period : getLoanRepaymentSchedule.getPeriods()) { + log.info("Period number {} for due date {} and outstanding {}", period.getPeriod(), period.getDueDate(), + period.getTotalOutstandingForPeriod()); + } + } + + // Move the Business date to get older the loan and to have an overdue loan + businessDate = businessDate.plusDays(40); + log.info("Current date {}", businessDate); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate); + // Run Second time the Job + schedulerJobHelper.executeAndAwaitJob(jobName); + + // Get loan details expecting to have a delinquency classification + getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + final GetDelinquencyRangesResponse secondTestCase = getLoansLoanIdResponse.getDelinquencyRange(); + log.info("Loan Delinquency Range is {}", secondTestCase.getClassification()); + + // Then + assertNotNull(delinquencyBucketResponse); + assertNotNull(getLoanProductsProductResponse); + assertNull(firstTestCase); + assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName()); + assertNotNull(secondTestCase); + assertEquals(secondTestCase.getClassification(), classificationExpected); + + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); + } + @Test public void testLoanClassificationRealtime() { // Given
