Loan Delinquency Classification job

This commit is contained in:
Jose Alberto Hernandez
2022-09-03 15:24:01 +02:00
committed by Arnold Gálovics
parent 24a199458f
commit 0980aa8abf
12 changed files with 74 additions and 44 deletions
@@ -33,7 +33,7 @@ public class LoanDelinquencyTagHistoryData implements Serializable {
private Long id; private Long id;
private Long loanId; private Long loanId;
private String delinquencyRange; private DelinquencyRangeData delinquencyRange;
private LocalDate addedOnDate; private LocalDate addedOnDate;
private LocalDate liftedOnDate; private LocalDate liftedOnDate;
@@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.delinquency.domain;
import java.time.LocalDate; import java.time.LocalDate;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
@@ -39,11 +38,11 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@Table(name = "m_loan_delinquency_tag_history") @Table(name = "m_loan_delinquency_tag_history")
public class LoanDelinquencyTagHistory extends AbstractAuditableWithUTCDateTimeCustom { public class LoanDelinquencyTagHistory extends AbstractAuditableWithUTCDateTimeCustom {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne
@JoinColumn(name = "delinquency_range_id", nullable = false) @JoinColumn(name = "delinquency_range_id", nullable = false)
private DelinquencyRange delinquencyRange; private DelinquencyRange delinquencyRange;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne
@JoinColumn(name = "loan_id", nullable = false) @JoinColumn(name = "loan_id", nullable = false)
private Loan loan; private Loan loan;
@@ -23,15 +23,15 @@ import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryD
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory; import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
@Mapper(componentModel = "spring") @Mapper(componentModel = "spring", uses = DelinquencyRangeMapper.class)
public interface LoanDelinquencyTagMapper { public interface LoanDelinquencyTagMapper {
@Mappings({ @Mapping(target = "id", source = "source.id"), @Mapping(target = "loanId", source = "source.loan.id"), @Mapping(target = "id", source = "source.id")
@Mapping(target = "delinquencyRange", source = "source.delinquencyRange.classification"), @Mapping(target = "loanId", source = "source.loan.id")
@Mapping(target = "addedOnDate", source = "source.addedOnDate"), @Mapping(target = "delinquencyRange", source = "source.delinquencyRange")
@Mapping(target = "liftedOnDate", source = "source.liftedOnDate") }) @Mapping(target = "addedOnDate", source = "source.addedOnDate")
@Mapping(target = "liftedOnDate", source = "source.liftedOnDate")
LoanDelinquencyTagHistoryData map(LoanDelinquencyTagHistory source); LoanDelinquencyTagHistoryData map(LoanDelinquencyTagHistory source);
List<LoanDelinquencyTagHistoryData> map(List<LoanDelinquencyTagHistory> sources); List<LoanDelinquencyTagHistoryData> map(List<LoanDelinquencyTagHistory> sources);
@@ -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.DelinquencyRangeMapper;
import org.apache.fineract.portfolio.delinquency.mapper.LoanDelinquencyTagMapper; import org.apache.fineract.portfolio.delinquency.mapper.LoanDelinquencyTagMapper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -45,14 +44,13 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional(readOnly = true) @Transactional(readOnly = true)
public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatformService { public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final DelinquencyRangeRepository repositoryRange; private final DelinquencyRangeRepository repositoryRange;
private final DelinquencyBucketRepository repositoryBucket; private final DelinquencyBucketRepository repositoryBucket;
private final LoanDelinquencyTagHistoryRepository repositoryLoanDelinquencyTagHistory; private final LoanDelinquencyTagHistoryRepository repositoryLoanDelinquencyTagHistory;
private final DelinquencyRangeMapper mapperRange; private final DelinquencyRangeMapper mapperRange;
private final DelinquencyBucketMapper mapperBucket; private final DelinquencyBucketMapper mapperBucket;
private final LoanDelinquencyTagMapper mapperLoanDelinquencyTagHistory; private final LoanDelinquencyTagMapper mapperLoanDelinquencyTagHistory;
private final LoanAssembler loanAssembler; private final LoanRepository loanRepository;
@Override @Override
public Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges() { public Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
@@ -82,7 +80,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
@Override @Override
public DelinquencyRangeData retrieveCurrentDelinquencyTag(Long loanId) { 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, Optional<LoanDelinquencyTagHistory> optLoanDelinquencyTag = this.repositoryLoanDelinquencyTagHistory.findByLoanAndLiftedOnDate(loan,
null); null);
if (optLoanDelinquencyTag.isPresent()) { if (optLoanDelinquencyTag.isPresent()) {
@@ -93,7 +91,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
@Override @Override
public Collection<LoanDelinquencyTagHistoryData> retrieveDelinquencyRangeHistory(Long loanId) { 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 final List<LoanDelinquencyTagHistory> loanDelinquencyTagData = this.repositoryLoanDelinquencyTagHistory
.findByLoanOrderByAddedOnDateDesc(loan); .findByLoanOrderByAddedOnDateDesc(loan);
return mapperLoanDelinquencyTagHistory.map(loanDelinquencyTagData); return mapperLoanDelinquencyTagHistory.map(loanDelinquencyTagData);
@@ -287,10 +287,10 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
} else { } else {
// Sort the ranges based on the minAgeDays // Sort the ranges based on the minAgeDays
List<DelinquencyRange> ranges = sortDelinquencyRangesByMinAge(delinquencyBucket.getRanges()); final List<DelinquencyRange> ranges = sortDelinquencyRangesByMinAge(delinquencyBucket.getRanges());
for (DelinquencyRange delinquencyRange : ranges) { for (final DelinquencyRange delinquencyRange : ranges) {
if (delinquencyRange.getMaximumAgeDays() == null) { if (delinquencyRange.getMaximumAgeDays() == null) { // Last Range in the Bucket
if (delinquencyRange.getMinimumAgeDays() <= ageDays) { if (delinquencyRange.getMinimumAgeDays() <= ageDays) {
log.debug("Loan {} with delinquency range {} with {} days", loan.getId(), delinquencyRange.getClassification(), log.debug("Loan {} with delinquency range {} with {} days", loan.getId(), delinquencyRange.getClassification(),
ageDays); ageDays);
@@ -983,8 +983,7 @@ public class LoansApiResource {
context.authenticatedUser().validateHasReadPermission("DELINQUENCY_TAGS"); context.authenticatedUser().validateHasReadPermission("DELINQUENCY_TAGS");
final Collection<LoanDelinquencyTagHistoryData> loanDelinquencyTagHistoryData = this.delinquencyReadPlatformService final Collection<LoanDelinquencyTagHistoryData> loanDelinquencyTagHistoryData = this.delinquencyReadPlatformService
.retrieveDelinquencyRangeHistory(loanId); .retrieveDelinquencyRangeHistory(loanId);
ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.jsonSerializerTagHistory.serialize(loanDelinquencyTagHistoryData);
return this.jsonSerializerTagHistory.serialize(settings, loanDelinquencyTagHistoryData);
} }
} }
@@ -30,7 +30,6 @@ public class LoanScheduleDelinquencyData implements Serializable {
private final Long loanId; private final Long loanId;
private final Long productId; private final Long productId;
private final LocalDate dueDate; private final LocalDate dueDate;
private final LocalDate fromDate;
private final Long ageDays; private final Long ageDays;
} }
@@ -22,7 +22,6 @@ import lombok.AllArgsConstructor;
import org.apache.fineract.infrastructure.jobs.service.JobName; import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService; import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; 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.Job;
import org.springframework.batch.core.Step; import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
@@ -38,7 +37,6 @@ public class SetLoanDelinquencyTagsConfig {
private JobBuilderFactory jobs; private JobBuilderFactory jobs;
private StepBuilderFactory steps; private StepBuilderFactory steps;
private LoanProductRepository loanProductRepository;
private DelinquencyWritePlatformService delinquencyWritePlatformService; private DelinquencyWritePlatformService delinquencyWritePlatformService;
private LoanReadPlatformService loanReadPlatformService; private LoanReadPlatformService loanReadPlatformService;
@@ -55,7 +53,7 @@ public class SetLoanDelinquencyTagsConfig {
@Bean @Bean
public SetLoanDelinquencyTagsTasklet setLoanDelinquencyTagsTasklet() { public SetLoanDelinquencyTagsTasklet setLoanDelinquencyTagsTasklet() {
return new SetLoanDelinquencyTagsTasklet(loanProductRepository, delinquencyWritePlatformService, loanReadPlatformService); return new SetLoanDelinquencyTagsTasklet(delinquencyWritePlatformService, loanReadPlatformService);
} }
} }
@@ -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.delinquency.service.DelinquencyWritePlatformService;
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData; import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; 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.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.core.step.tasklet.Tasklet;
@@ -36,16 +35,18 @@ import org.springframework.batch.repeat.RepeatStatus;
@RequiredArgsConstructor @RequiredArgsConstructor
public class SetLoanDelinquencyTagsTasklet implements Tasklet { public class SetLoanDelinquencyTagsTasklet implements Tasklet {
private final LoanProductRepository loanProductRepository;
private final DelinquencyWritePlatformService delinquencyWritePlatformService; private final DelinquencyWritePlatformService delinquencyWritePlatformService;
private final LoanReadPlatformService loanReadPlatformService; private final LoanReadPlatformService loanReadPlatformService;
@Override @Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
log.debug("Run job for date {}", DateUtils.getBusinessLocalDate());
Collection<LoanScheduleDelinquencyData> loanScheduleDelinquencyData = this.loanReadPlatformService Collection<LoanScheduleDelinquencyData> loanScheduleDelinquencyData = this.loanReadPlatformService
.retrieveScheduleDelinquencyData(DateUtils.getBusinessLocalDate()); .retrieveScheduleDelinquencyData(DateUtils.getBusinessLocalDate());
log.debug("Were found {} items", loanScheduleDelinquencyData.size()); log.debug("Were found {} items", loanScheduleDelinquencyData.size());
for (LoanScheduleDelinquencyData loanDelinquencyData : loanScheduleDelinquencyData) { 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(), this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData.getLoanId(),
loanDelinquencyData.getAgeDays()); loanDelinquencyData.getAgeDays());
} }
@@ -1696,7 +1696,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
return new LoanTermVariationsData(id, LoanEnumerations.loanVariationType(LoanTermVariationType.EMI_AMOUNT), return new LoanTermVariationsData(id, LoanEnumerations.loanVariationType(LoanTermVariationType.EMI_AMOUNT),
variationApplicableFrom, decimalValue, dateValue, isSpecificToInstallment); variationApplicableFrom, decimalValue, dateValue, isSpecificToInstallment);
} }
} }
@Override @Override
@@ -1704,10 +1703,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
LoanScheduleDelinquencyMapper mapper = new LoanScheduleDelinquencyMapper(DateUtils.getBusinessLocalDate()); LoanScheduleDelinquencyMapper mapper = new LoanScheduleDelinquencyMapper(DateUtils.getBusinessLocalDate());
final StringBuilder sqlBuilder = new StringBuilder(400); final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("select ").append(mapper.schema()) sqlBuilder.append("select ").append(mapper.schema())
// Just get the overdued installments
.append(" where loan.loan_status_id=:active and ls.duedate <= :businessLocalDate and ") .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 // Just get the unpaid installments using the completed_derived flag
// bucket .append(" ls.completed_derived = false and ")
sqlBuilder.append(" order by loan.id, ls.duedate "); // 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); Map<String, Object> paramMap = new HashMap<>(3);
paramMap.put("active", LoanStatus.ACTIVE.getValue()); paramMap.put("active", LoanStatus.ACTIVE.getValue());
paramMap.put("businessLocalDate", businessLocalDate); paramMap.put("businessLocalDate", businessLocalDate);
@@ -1894,7 +1896,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public String schema() { public String schema() {
final StringBuilder sqlBuilder = new StringBuilder(400); 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(" 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 "); .append(" left join m_product_loan mpl on mpl.id = loan.product_id ");
return sqlBuilder.toString(); return sqlBuilder.toString();
@@ -1906,9 +1908,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Long loanId = rs.getLong("loanId"); final Long loanId = rs.getLong("loanId");
final Long productId = rs.getLong("productId"); final Long productId = rs.getLong("productId");
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "duedate"); final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "duedate");
final LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromdate");
final long ageDays = DateUtils.getDifferenceInDays(dueDate, businessDate); final long ageDays = DateUtils.getDifferenceInDays(dueDate, businessDate);
return new LoanScheduleDelinquencyData(loanId, productId, dueDate, fromDate, ageDays); return new LoanScheduleDelinquencyData(loanId, productId, dueDate, ageDays);
} }
} }
@@ -277,8 +277,8 @@ public final class LoanProductDataValidator {
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element)) { if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element)) {
final Long delinquencyBucketId = this.fromApiJsonHelper.extractLongNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, final Long delinquencyBucketId = this.fromApiJsonHelper.extractLongNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
element); element);
baseDataValidator.reset().parameter(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME).value(delinquencyBucketId) baseDataValidator.reset().parameter(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME).value(delinquencyBucketId).notNull()
.ignoreIfNull().integerGreaterThanZero(); .integerGreaterThanZero();
} }
// grace validation // grace validation
@@ -21,6 +21,7 @@ package org.apache.fineract.integrationtests;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; 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.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder; 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.GetDelinquencyBucketsResponse;
import org.apache.fineract.client.models.GetDelinquencyRangesResponse; import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; 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.GetLoansLoanIdResponse;
import org.apache.fineract.client.models.PostDelinquencyBucketResponse; import org.apache.fineract.client.models.PostDelinquencyBucketResponse;
import org.apache.fineract.client.models.PostDelinquencyRangeResponse; import org.apache.fineract.client.models.PostDelinquencyRangeResponse;
import org.apache.fineract.client.models.PutDelinquencyBucketResponse; import org.apache.fineract.client.models.PutDelinquencyBucketResponse;
import org.apache.fineract.client.models.PutDelinquencyRangeResponse; 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.ClientHelper;
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
import org.apache.fineract.integrationtests.common.SchedulerJobHelper; import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
@@ -221,6 +227,13 @@ public class DelinquencyBucketsIntegrationTest {
@Test @Test
public void testLoanClassificationJob() { 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 // Given
final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); final LoanTransactionHelper loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
final SchedulerJobHelper schedulerJobHelper = new SchedulerJobHelper(requestSpec); final SchedulerJobHelper schedulerJobHelper = new SchedulerJobHelper(requestSpec);
@@ -253,12 +266,10 @@ public class DelinquencyBucketsIntegrationTest {
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId); final GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId);
log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName()); log.info("Loan Product Bucket Name: {}", getLoanProductsProductResponse.getDelinquencyBucket().getName());
LocalDate todaysDate = Utils.getLocalDateOfTenant(); final String operationDate = Utils.dateFormatter.format(businessDate);
todaysDate = todaysDate.minusDays(40);
final String operationDate = Utils.dateFormatter.format(todaysDate);
final String principalAmount = "10000"; 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") .withLoanTermFrequencyAsMonths().withNumberOfRepayments("12").withRepaymentEveryAfter("1")
.withRepaymentFrequencyTypeAsMonths() // .withRepaymentFrequencyTypeAsMonths() //
.withInterestRatePerPeriod("2") // .withInterestRatePerPeriod("2") //
@@ -271,19 +282,43 @@ public class DelinquencyBucketsIntegrationTest {
loanTransactionHelper.disburseLoanWithNetDisbursalAmount(operationDate, loanId, principalAmount); loanTransactionHelper.disburseLoanWithNetDisbursalAmount(operationDate, loanId, principalAmount);
// When // When
// Run first time the Job
final String jobName = "Loan Delinquency Classification"; final String jobName = "Loan Delinquency Classification";
schedulerJobHelper.executeAndAwaitJob(jobName); schedulerJobHelper.executeAndAwaitJob(jobName);
final GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); // Get loan details expecting to have not a delinquency classification
log.info("Loan Delinquency Range {}", getLoansLoanIdResponse.getDelinquencyRange().getClassification()); 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 // Then
assertNotNull(delinquencyBucketResponse); assertNotNull(delinquencyBucketResponse);
assertNotNull(getLoanProductsProductResponse); assertNotNull(getLoanProductsProductResponse);
assertNull(firstTestCase);
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName()); assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(), delinquencyBucket.getName());
assertNotNull(getLoansLoanIdResponse); assertNotNull(secondTestCase);
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(), classificationExpected); assertEquals(secondTestCase.getClassification(), classificationExpected);
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
} }
} }