Loan Delinquency Classification job
This commit is contained in:
committed by
Arnold Gálovics
parent
24a199458f
commit
0980aa8abf
+1
-1
@@ -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;
|
||||
|
||||
|
||||
+2
-3
@@ -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;
|
||||
|
||||
|
||||
+6
-6
@@ -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);
|
||||
|
||||
+4
-6
@@ -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);
|
||||
|
||||
+3
-3
@@ -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);
|
||||
|
||||
+1
-2
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
+1
-3
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -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());
|
||||
}
|
||||
|
||||
+8
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user