You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2022/09/03 13:24:07 UTC

[fineract] branch develop updated: Loan Delinquency Classification job

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


The following commit(s) were added to refs/heads/develop by this push:
     new 0980aa8ab Loan Delinquency Classification job
0980aa8ab is described below

commit 0980aa8abf7cebd66f9ebc47e0639810023f42c1
Author: Jose Alberto Hernandez <al...@MacBook-Pro.local>
AuthorDate: Thu Aug 25 16:45:30 2022 -0600

    Loan Delinquency Classification job
---
 .../data/LoanDelinquencyTagHistoryData.java        |  2 +-
 .../domain/LoanDelinquencyTagHistory.java          |  5 +--
 .../mapper/LoanDelinquencyTagMapper.java           | 12 ++---
 .../DelinquencyReadPlatformServiceImpl.java        | 10 ++---
 .../DelinquencyWritePlatformServiceImpl.java       |  6 +--
 .../loanaccount/api/LoansApiResource.java          |  3 +-
 .../data/LoanScheduleDelinquencyData.java          |  1 -
 .../SetLoanDelinquencyTagsConfig.java              |  4 +-
 .../SetLoanDelinquencyTagsTasklet.java             |  5 ++-
 .../service/LoanReadPlatformServiceImpl.java       | 15 ++++---
 .../serialization/LoanProductDataValidator.java    |  4 +-
 .../DelinquencyBucketsIntegrationTest.java         | 51 ++++++++++++++++++----
 12 files changed, 74 insertions(+), 44 deletions(-)

diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/data/LoanDelinquencyTagHistoryData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/data/LoanDelinquencyTagHistoryData.java
index ed85ba3d9..191ded56b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/data/LoanDelinquencyTagHistoryData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/data/LoanDelinquencyTagHistoryData.java
@@ -33,7 +33,7 @@ public class LoanDelinquencyTagHistoryData implements Serializable {
 
     private Long id;
     private Long loanId;
-    private String delinquencyRange;
+    private DelinquencyRangeData delinquencyRange;
     private LocalDate addedOnDate;
     private LocalDate liftedOnDate;
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/domain/LoanDelinquencyTagHistory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/domain/LoanDelinquencyTagHistory.java
index 9ea27b0ad..fbba0846e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/domain/LoanDelinquencyTagHistory.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/domain/LoanDelinquencyTagHistory.java
@@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.delinquency.domain;
 import java.time.LocalDate;
 import javax.persistence.Column;
 import javax.persistence.Entity;
-import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
@@ -39,11 +38,11 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 @Table(name = "m_loan_delinquency_tag_history")
 public class LoanDelinquencyTagHistory extends AbstractAuditableWithUTCDateTimeCustom {
 
-    @ManyToOne(fetch = FetchType.LAZY)
+    @ManyToOne
     @JoinColumn(name = "delinquency_range_id", nullable = false)
     private DelinquencyRange delinquencyRange;
 
-    @ManyToOne(fetch = FetchType.LAZY)
+    @ManyToOne
     @JoinColumn(name = "loan_id", nullable = false)
     private Loan loan;
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/mapper/LoanDelinquencyTagMapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/mapper/LoanDelinquencyTagMapper.java
index b95ff4e92..f4fff90ce 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/mapper/LoanDelinquencyTagMapper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/mapper/LoanDelinquencyTagMapper.java
@@ -23,15 +23,15 @@ import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryD
 import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
 
-@Mapper(componentModel = "spring")
+@Mapper(componentModel = "spring", uses = DelinquencyRangeMapper.class)
 public interface LoanDelinquencyTagMapper {
 
-    @Mappings({ @Mapping(target = "id", source = "source.id"), @Mapping(target = "loanId", source = "source.loan.id"),
-            @Mapping(target = "delinquencyRange", source = "source.delinquencyRange.classification"),
-            @Mapping(target = "addedOnDate", source = "source.addedOnDate"),
-            @Mapping(target = "liftedOnDate", source = "source.liftedOnDate") })
+    @Mapping(target = "id", source = "source.id")
+    @Mapping(target = "loanId", source = "source.loan.id")
+    @Mapping(target = "delinquencyRange", source = "source.delinquencyRange")
+    @Mapping(target = "addedOnDate", source = "source.addedOnDate")
+    @Mapping(target = "liftedOnDate", source = "source.liftedOnDate")
     LoanDelinquencyTagHistoryData map(LoanDelinquencyTagHistory source);
 
     List<LoanDelinquencyTagHistoryData> map(List<LoanDelinquencyTagHistory> sources);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
index a7d61d50a..023970b39 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
@@ -35,8 +35,7 @@ import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyBucketMapper;
 import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyRangeMapper;
 import org.apache.fineract.portfolio.delinquency.mapper.LoanDelinquencyTagMapper;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
-import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
-import org.springframework.jdbc.core.JdbcTemplate;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -45,14 +44,13 @@ import org.springframework.transaction.annotation.Transactional;
 @Transactional(readOnly = true)
 public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatformService {
 
-    private final JdbcTemplate jdbcTemplate;
     private final DelinquencyRangeRepository repositoryRange;
     private final DelinquencyBucketRepository repositoryBucket;
     private final LoanDelinquencyTagHistoryRepository repositoryLoanDelinquencyTagHistory;
     private final DelinquencyRangeMapper mapperRange;
     private final DelinquencyBucketMapper mapperBucket;
     private final LoanDelinquencyTagMapper mapperLoanDelinquencyTagHistory;
-    private final LoanAssembler loanAssembler;
+    private final LoanRepository loanRepository;
 
     @Override
     public Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
@@ -82,7 +80,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
 
     @Override
     public DelinquencyRangeData retrieveCurrentDelinquencyTag(Long loanId) {
-        final Loan loan = this.loanAssembler.assembleFrom(loanId);
+        final Loan loan = this.loanRepository.getReferenceById(loanId);
         Optional<LoanDelinquencyTagHistory> optLoanDelinquencyTag = this.repositoryLoanDelinquencyTagHistory.findByLoanAndLiftedOnDate(loan,
                 null);
         if (optLoanDelinquencyTag.isPresent()) {
@@ -93,7 +91,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
 
     @Override
     public Collection<LoanDelinquencyTagHistoryData> retrieveDelinquencyRangeHistory(Long loanId) {
-        final Loan loan = this.loanAssembler.assembleFrom(loanId);
+        final Loan loan = this.loanRepository.getReferenceById(loanId);
         final List<LoanDelinquencyTagHistory> loanDelinquencyTagData = this.repositoryLoanDelinquencyTagHistory
                 .findByLoanOrderByAddedOnDateDesc(loan);
         return mapperLoanDelinquencyTagHistory.map(loanDelinquencyTagData);
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 c97d467e2..644563363 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
@@ -287,10 +287,10 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
 
         } else {
             // Sort the ranges based on the minAgeDays
-            List<DelinquencyRange> ranges = sortDelinquencyRangesByMinAge(delinquencyBucket.getRanges());
+            final List<DelinquencyRange> ranges = sortDelinquencyRangesByMinAge(delinquencyBucket.getRanges());
 
-            for (DelinquencyRange delinquencyRange : ranges) {
-                if (delinquencyRange.getMaximumAgeDays() == null) {
+            for (final DelinquencyRange delinquencyRange : ranges) {
+                if (delinquencyRange.getMaximumAgeDays() == null) { // Last Range in the Bucket
                     if (delinquencyRange.getMinimumAgeDays() <= ageDays) {
                         log.debug("Loan {} with delinquency range {} with {} days", loan.getId(), delinquencyRange.getClassification(),
                                 ageDays);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index 73b4bc084..2a952f657 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -983,8 +983,7 @@ public class LoansApiResource {
         context.authenticatedUser().validateHasReadPermission("DELINQUENCY_TAGS");
         final Collection<LoanDelinquencyTagHistoryData> loanDelinquencyTagHistoryData = this.delinquencyReadPlatformService
                 .retrieveDelinquencyRangeHistory(loanId);
-        ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
-        return this.jsonSerializerTagHistory.serialize(settings, loanDelinquencyTagHistoryData);
+        return this.jsonSerializerTagHistory.serialize(loanDelinquencyTagHistoryData);
     }
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanScheduleDelinquencyData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanScheduleDelinquencyData.java
index 23964fdda..4458ae419 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanScheduleDelinquencyData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanScheduleDelinquencyData.java
@@ -30,7 +30,6 @@ public class LoanScheduleDelinquencyData implements Serializable {
     private final Long loanId;
     private final Long productId;
     private final LocalDate dueDate;
-    private final LocalDate fromDate;
     private final Long ageDays;
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java
index 86ccf2cbb..3334b90ca 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java
@@ -22,7 +22,6 @@ import lombok.AllArgsConstructor;
 import org.apache.fineract.infrastructure.jobs.service.JobName;
 import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
 import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
 import org.springframework.batch.core.Job;
 import org.springframework.batch.core.Step;
 import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
@@ -38,7 +37,6 @@ public class SetLoanDelinquencyTagsConfig {
     private JobBuilderFactory jobs;
     private StepBuilderFactory steps;
 
-    private LoanProductRepository loanProductRepository;
     private DelinquencyWritePlatformService delinquencyWritePlatformService;
     private LoanReadPlatformService loanReadPlatformService;
 
@@ -55,7 +53,7 @@ public class SetLoanDelinquencyTagsConfig {
 
     @Bean
     public SetLoanDelinquencyTagsTasklet setLoanDelinquencyTagsTasklet() {
-        return new SetLoanDelinquencyTagsTasklet(loanProductRepository, delinquencyWritePlatformService, loanReadPlatformService);
+        return new SetLoanDelinquencyTagsTasklet(delinquencyWritePlatformService, loanReadPlatformService);
     }
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java
index caebad057..9bf2d274b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java
@@ -26,7 +26,6 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
 import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
 import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
 import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
 import org.springframework.batch.core.StepContribution;
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.step.tasklet.Tasklet;
@@ -36,16 +35,18 @@ import org.springframework.batch.repeat.RepeatStatus;
 @RequiredArgsConstructor
 public class SetLoanDelinquencyTagsTasklet implements Tasklet {
 
-    private final LoanProductRepository loanProductRepository;
     private final DelinquencyWritePlatformService delinquencyWritePlatformService;
     private final LoanReadPlatformService loanReadPlatformService;
 
     @Override
     public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
+        log.debug("Run job for date {}", DateUtils.getBusinessLocalDate());
         Collection<LoanScheduleDelinquencyData> loanScheduleDelinquencyData = this.loanReadPlatformService
                 .retrieveScheduleDelinquencyData(DateUtils.getBusinessLocalDate());
         log.debug("Were found {} items", loanScheduleDelinquencyData.size());
         for (LoanScheduleDelinquencyData loanDelinquencyData : loanScheduleDelinquencyData) {
+            log.debug("Processing Loan {} with due date {} and {} overdue days", loanDelinquencyData.getLoanId(),
+                    loanDelinquencyData.getDueDate(), loanDelinquencyData.getAgeDays());
             this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData.getLoanId(),
                     loanDelinquencyData.getAgeDays());
         }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 2eab5338b..4835913d5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -1696,7 +1696,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
             return new LoanTermVariationsData(id, LoanEnumerations.loanVariationType(LoanTermVariationType.EMI_AMOUNT),
                     variationApplicableFrom, decimalValue, dateValue, isSpecificToInstallment);
         }
-
     }
 
     @Override
@@ -1704,10 +1703,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
         LoanScheduleDelinquencyMapper mapper = new LoanScheduleDelinquencyMapper(DateUtils.getBusinessLocalDate());
         final StringBuilder sqlBuilder = new StringBuilder(400);
         sqlBuilder.append("select ").append(mapper.schema())
+                // Just get the overdued installments
                 .append(" where loan.loan_status_id=:active and ls.duedate <= :businessLocalDate and ")
-                .append(" mpl.delinquency_bucket_id is not null "); // Jusr the Loan Product linked to delinquency
-                                                                    // bucket
-        sqlBuilder.append(" order by loan.id, ls.duedate ");
+                // Just get the unpaid installments using the completed_derived flag
+                .append(" ls.completed_derived = false and ")
+                // Just the Loan Product linked to delinquency bucket
+                .append(" mpl.delinquency_bucket_id is not null ");
+        sqlBuilder.append(" group by ls.loan_id, loan.product_id ");
         Map<String, Object> paramMap = new HashMap<>(3);
         paramMap.put("active", LoanStatus.ACTIVE.getValue());
         paramMap.put("businessLocalDate", businessLocalDate);
@@ -1894,7 +1896,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
 
         public String schema() {
             final StringBuilder sqlBuilder = new StringBuilder(400);
-            sqlBuilder.append(" loan.id as loanId, ls.duedate as duedate, ls.fromdate as fromdate, loan.product_id as productId ")
+            sqlBuilder.append(" ls.loan_id as loanId, loan.product_id as productId, min(ls.duedate) as duedate ")
                     .append(" from m_loan_repayment_schedule ls left join m_loan loan on loan.id=ls.loan_id ")
                     .append(" left join m_product_loan mpl on mpl.id = loan.product_id ");
             return sqlBuilder.toString();
@@ -1906,9 +1908,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
             final Long loanId = rs.getLong("loanId");
             final Long productId = rs.getLong("productId");
             final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "duedate");
-            final LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromdate");
             final long ageDays = DateUtils.getDifferenceInDays(dueDate, businessDate);
-            return new LoanScheduleDelinquencyData(loanId, productId, dueDate, fromDate, ageDays);
+            return new LoanScheduleDelinquencyData(loanId, productId, dueDate, ageDays);
         }
     }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
index 53cdcabba..1a83d5120 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
@@ -277,8 +277,8 @@ public final class LoanProductDataValidator {
         if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element)) {
             final Long delinquencyBucketId = this.fromApiJsonHelper.extractLongNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
                     element);
-            baseDataValidator.reset().parameter(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME).value(delinquencyBucketId)
-                    .ignoreIfNull().integerGreaterThanZero();
+            baseDataValidator.reset().parameter(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME).value(delinquencyBucketId).notNull()
+                    .integerGreaterThanZero();
         }
 
         // grace validation
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 f7e51cec6..42872d564 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
@@ -21,6 +21,7 @@ package org.apache.fineract.integrationtests;
 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 io.restassured.builder.RequestSpecBuilder;
 import io.restassured.builder.ResponseSpecBuilder;
@@ -36,12 +37,17 @@ import org.apache.fineract.client.models.DeleteDelinquencyRangeResponse;
 import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
 import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
 import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
+import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
+import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
 import org.apache.fineract.client.models.PostDelinquencyBucketResponse;
 import org.apache.fineract.client.models.PostDelinquencyRangeResponse;
 import org.apache.fineract.client.models.PutDelinquencyBucketResponse;
 import org.apache.fineract.client.models.PutDelinquencyRangeResponse;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.integrationtests.common.BusinessDateHelper;
 import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
 import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
@@ -221,6 +227,13 @@ public class DelinquencyBucketsIntegrationTest {
 
     @Test
     public void testLoanClassificationJob() {
+        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);
@@ -253,12 +266,10 @@ public class DelinquencyBucketsIntegrationTest {
         final GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId);
         log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName());
 
-        LocalDate todaysDate = Utils.getLocalDateOfTenant();
-        todaysDate = todaysDate.minusDays(40);
-        final String operationDate = Utils.dateFormatter.format(todaysDate);
+        final String operationDate = Utils.dateFormatter.format(businessDate);
         final String principalAmount = "10000";
 
-        final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(principalAmount).withLoanTermFrequency("12")
+        String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(principalAmount).withLoanTermFrequency("12")
                 .withLoanTermFrequencyAsMonths().withNumberOfRepayments("12").withRepaymentEveryAfter("1")
                 .withRepaymentFrequencyTypeAsMonths() //
                 .withInterestRatePerPeriod("2") //
@@ -271,19 +282,43 @@ public class DelinquencyBucketsIntegrationTest {
         loanTransactionHelper.disburseLoanWithNetDisbursalAmount(operationDate, loanId, principalAmount);
 
         // When
+        // Run first time the Job
         final String jobName = "Loan Delinquency Classification";
         schedulerJobHelper.executeAndAwaitJob(jobName);
 
-        final GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
-        log.info("Loan Delinquency Range {}", getLoansLoanIdResponse.getDelinquencyRange().getClassification());
+        // 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 {}", period.getPeriod(), period.getDueDate());
+            }
+        }
+
+        // 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(getLoansLoanIdResponse);
-        assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected);
+        assertNotNull(secondTestCase);
+        assertEquals(secondTestCase.getClassification(), classificationExpected);
 
+        GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
     }
 
 }