[FINERACT-1992] Delinquency calculation with pause
This commit is contained in:
+38
-1
@@ -20,13 +20,22 @@ package org.apache.fineract.cob.loan;
|
|||||||
|
|
||||||
import static org.apache.fineract.infrastructure.core.diagnostics.performance.MeasuringUtil.measure;
|
import static org.apache.fineract.infrastructure.core.diagnostics.performance.MeasuringUtil.measure;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||||
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
||||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanDelinquencyRangeChangeBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -37,6 +46,9 @@ import org.springframework.stereotype.Component;
|
|||||||
public class SetLoanDelinquencyTagsBusinessStep implements LoanCOBBusinessStep {
|
public class SetLoanDelinquencyTagsBusinessStep implements LoanCOBBusinessStep {
|
||||||
|
|
||||||
private final LoanAccountDomainService loanAccountDomainService;
|
private final LoanAccountDomainService loanAccountDomainService;
|
||||||
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loan execute(Loan loan) {
|
public Loan execute(Loan loan) {
|
||||||
@@ -55,7 +67,17 @@ public class SetLoanDelinquencyTagsBusinessStep implements LoanCOBBusinessStep {
|
|||||||
// the
|
// the
|
||||||
// current date and not the previous (COB) date.
|
// current date and not the previous (COB) date.
|
||||||
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
||||||
loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate());
|
|
||||||
|
final List<LoanDelinquencyAction> savedDelinquencyList = delinquencyReadPlatformService
|
||||||
|
.retrieveLoanDelinquencyActions(loan.getId());
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList = delinquencyEffectivePauseHelper
|
||||||
|
.calculateEffectiveDelinquencyList(savedDelinquencyList);
|
||||||
|
|
||||||
|
if (!isDelinquencyOnPause(loan, effectiveDelinquencyList)) {
|
||||||
|
loanAccountDomainService.setLoanDelinquencyTag(loan, DateUtils.getBusinessLocalDate(), effectiveDelinquencyList);
|
||||||
|
} else {
|
||||||
|
log.debug("Delinquency is on pause for loan with ID [{}]", loan.getId());
|
||||||
|
}
|
||||||
} catch (RuntimeException re) {
|
} catch (RuntimeException re) {
|
||||||
log.error(
|
log.error(
|
||||||
"Received [{}] exception while processing delinquency tag for loan with Id [{}], account number [{}], external Id [{}]",
|
"Received [{}] exception while processing delinquency tag for loan with Id [{}], account number [{}], external Id [{}]",
|
||||||
@@ -74,6 +96,21 @@ public class SetLoanDelinquencyTagsBusinessStep implements LoanCOBBusinessStep {
|
|||||||
return loan;
|
return loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isDelinquencyOnPause(Loan loan, List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
|
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
|
||||||
|
boolean isPaused = isPausedOnDate(cobBusinessDate, effectiveDelinquencyList);
|
||||||
|
boolean wasPausedOneDayBefore = isPausedOnDate(cobBusinessDate.minusDays(1), effectiveDelinquencyList);
|
||||||
|
if ((isPaused && !wasPausedOneDayBefore) || (!isPaused && wasPausedOneDayBefore)) {
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanDelinquencyRangeChangeBusinessEvent(loan));
|
||||||
|
}
|
||||||
|
return isPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPausedOnDate(LocalDate date, List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
|
return effectiveDelinquencyList.stream()
|
||||||
|
.anyMatch(pausePeriod -> !pausePeriod.getStartDate().isAfter(date) && !pausePeriod.getEndDate().isBefore(date));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEnumStyledName() {
|
public String getEnumStyledName() {
|
||||||
return "LOAN_DELINQUENCY_CLASSIFICATION";
|
return "LOAN_DELINQUENCY_CLASSIFICATION";
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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.portfolio.delinquency.helper;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
|
|
||||||
|
public interface DelinquencyEffectivePauseHelper {
|
||||||
|
|
||||||
|
List<LoanDelinquencyActionData> calculateEffectiveDelinquencyList(List<LoanDelinquencyAction> savedDelinquencyActions);
|
||||||
|
|
||||||
|
Long getPausedDaysBeforeDate(List<LoanDelinquencyActionData> effectiveDelinquencyList, LocalDate date);
|
||||||
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* 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.portfolio.delinquency.helper;
|
||||||
|
|
||||||
|
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DelinquencyEffectivePauseHelperImpl implements DelinquencyEffectivePauseHelper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<LoanDelinquencyActionData> calculateEffectiveDelinquencyList(List<LoanDelinquencyAction> savedDelinquencyActions) {
|
||||||
|
// partition them based on type
|
||||||
|
Map<DelinquencyAction, List<LoanDelinquencyAction>> partitioned = savedDelinquencyActions.stream()
|
||||||
|
.collect(Collectors.groupingBy(LoanDelinquencyAction::getAction));
|
||||||
|
List<LoanDelinquencyActionData> effective = new ArrayList<>();
|
||||||
|
List<LoanDelinquencyAction> pauses = partitioned.get(DelinquencyAction.PAUSE);
|
||||||
|
if (pauses != null && pauses.size() > 0) {
|
||||||
|
for (LoanDelinquencyAction loanDelinquencyAction : pauses) {
|
||||||
|
Optional<LoanDelinquencyAction> resume = findMatchingResume(loanDelinquencyAction, partitioned.get(RESUME));
|
||||||
|
LoanDelinquencyActionData loanDelinquencyActionData = new LoanDelinquencyActionData(loanDelinquencyAction);
|
||||||
|
resume.ifPresent(r -> loanDelinquencyActionData.setEndDate(r.getStartDate()));
|
||||||
|
effective.add(loanDelinquencyActionData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getPausedDaysBeforeDate(List<LoanDelinquencyActionData> effectiveDelinquencyList, LocalDate date) {
|
||||||
|
Long pausedDaysClosedPausePeriods = effectiveDelinquencyList.stream() //
|
||||||
|
.filter(pausePeriod -> pausePeriod.getStartDate().isBefore(date) && pausePeriod.getEndDate().isBefore(date))
|
||||||
|
.map(pausePeriod -> DateUtils.getDifferenceInDays(pausePeriod.getStartDate(), pausePeriod.getEndDate())) //
|
||||||
|
.reduce(0L, Long::sum);
|
||||||
|
Long pausedDaysRunningPausePeriods = effectiveDelinquencyList.stream() //
|
||||||
|
.filter(pausePeriod -> pausePeriod.getStartDate().isBefore(date) && !pausePeriod.getEndDate().isBefore(date))
|
||||||
|
.map(pausePeriod -> DateUtils.getDifferenceInDays(pausePeriod.getStartDate(), date)) //
|
||||||
|
.reduce(0L, Long::sum);
|
||||||
|
return Long.sum(pausedDaysClosedPausePeriods, pausedDaysRunningPausePeriods);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<LoanDelinquencyAction> findMatchingResume(LoanDelinquencyAction pause, List<LoanDelinquencyAction> resumes) {
|
||||||
|
if (resumes != null && resumes.size() > 0) {
|
||||||
|
for (LoanDelinquencyAction resume : resumes) {
|
||||||
|
if (!pause.getStartDate().isAfter(resume.getStartDate()) && !resume.getStartDate().isAfter(pause.getEndDate())) {
|
||||||
|
return Optional.of(resume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -19,6 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.delinquency.service;
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData;
|
import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData;
|
||||||
@@ -44,6 +45,6 @@ public interface DelinquencyReadPlatformService {
|
|||||||
|
|
||||||
Collection<LoanInstallmentDelinquencyTagData> retrieveLoanInstallmentsCurrentDelinquencyTag(Long loanId);
|
Collection<LoanInstallmentDelinquencyTagData> retrieveLoanInstallmentsCurrentDelinquencyTag(Long loanId);
|
||||||
|
|
||||||
Collection<LoanDelinquencyAction> retrieveLoanDelinquencyActions(Long loanId);
|
List<LoanDelinquencyAction> retrieveLoanDelinquencyActions(Long loanId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-42
@@ -18,14 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.delinquency.service;
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collector;
|
import java.util.stream.Collector;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -36,7 +32,6 @@ import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
|||||||
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData;
|
import org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData;
|
||||||
import org.apache.fineract.portfolio.delinquency.data.LoanInstallmentDelinquencyTagData;
|
import org.apache.fineract.portfolio.delinquency.data.LoanInstallmentDelinquencyTagData;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
|
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository;
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange;
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange;
|
||||||
@@ -46,6 +41,7 @@ import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyActionRep
|
|||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyBucketMapper;
|
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;
|
||||||
@@ -73,6 +69,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
|
|||||||
private final LoanDelinquencyDomainService loanDelinquencyDomainService;
|
private final LoanDelinquencyDomainService loanDelinquencyDomainService;
|
||||||
private final LoanInstallmentDelinquencyTagRepository repositoryLoanInstallmentDelinquencyTag;
|
private final LoanInstallmentDelinquencyTagRepository repositoryLoanInstallmentDelinquencyTag;
|
||||||
private final LoanDelinquencyActionRepository loanDelinquencyActionRepository;
|
private final LoanDelinquencyActionRepository loanDelinquencyActionRepository;
|
||||||
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
|
public Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
|
||||||
@@ -127,7 +124,11 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
|
|||||||
if (optLoan.isPresent()) {
|
if (optLoan.isPresent()) {
|
||||||
final Loan loan = optLoan.get();
|
final Loan loan = optLoan.get();
|
||||||
|
|
||||||
collectionData = loanDelinquencyDomainService.getOverdueCollectionData(loan);
|
final List<LoanDelinquencyAction> savedDelinquencyList = retrieveLoanDelinquencyActions(loanId);
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList = delinquencyEffectivePauseHelper
|
||||||
|
.calculateEffectiveDelinquencyList(savedDelinquencyList);
|
||||||
|
|
||||||
|
collectionData = loanDelinquencyDomainService.getOverdueCollectionData(loan, effectiveDelinquencyList);
|
||||||
collectionData.setAvailableDisbursementAmount(loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()));
|
collectionData.setAvailableDisbursementAmount(loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()));
|
||||||
collectionData.setNextPaymentDueDate(loan.possibleNextRepaymentDate());
|
collectionData.setNextPaymentDueDate(loan.possibleNextRepaymentDate());
|
||||||
|
|
||||||
@@ -143,8 +144,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
|
|||||||
collectionData.setLastRepaymentAmount(lastRepaymentTransaction.getAmount());
|
collectionData.setLastRepaymentAmount(lastRepaymentTransaction.getAmount());
|
||||||
}
|
}
|
||||||
|
|
||||||
enrichWithDelinquencyPausePeriodInfo(collectionData, retrieveLoanDelinquencyActions(loanId),
|
enrichWithDelinquencyPausePeriodInfo(collectionData, effectiveDelinquencyList, ThreadLocalContextUtil.getBusinessDate());
|
||||||
ThreadLocalContextUtil.getBusinessDate());
|
|
||||||
|
|
||||||
if (optLoan.get().isEnableInstallmentLevelDelinquency()) {
|
if (optLoan.get().isEnableInstallmentLevelDelinquency()) {
|
||||||
addInstallmentLevelDelinquencyData(collectionData, loanId);
|
addInstallmentLevelDelinquencyData(collectionData, loanId);
|
||||||
@@ -188,29 +188,12 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void enrichWithDelinquencyPausePeriodInfo(CollectionData collectionData, Collection<LoanDelinquencyAction> delinquencyActions,
|
void enrichWithDelinquencyPausePeriodInfo(CollectionData collectionData, Collection<LoanDelinquencyActionData> effectiveDelinquencyList,
|
||||||
LocalDate businessDate) {
|
LocalDate businessDate) {
|
||||||
// partition them based on type
|
List<DelinquencyPausePeriod> result = effectiveDelinquencyList.stream() //
|
||||||
Map<DelinquencyAction, List<LoanDelinquencyAction>> partitioned = delinquencyActions.stream()
|
.sorted(Comparator.comparing(LoanDelinquencyActionData::getStartDate)) //
|
||||||
.collect(Collectors.groupingBy(LoanDelinquencyAction::getAction));
|
.map(lda -> toDelinquencyPausePeriod(businessDate, lda)).toList(); //
|
||||||
|
collectionData.setDelinquencyPausePeriods(result);
|
||||||
// add the possible resumes to it to create the effective pause periods
|
|
||||||
if (partitioned.containsKey(DelinquencyAction.PAUSE)) {
|
|
||||||
List<LoanDelinquencyActionData> effective = new ArrayList<>();
|
|
||||||
List<LoanDelinquencyAction> pauses = partitioned.get(DelinquencyAction.PAUSE);
|
|
||||||
for (LoanDelinquencyAction loanDelinquencyAction : pauses) {
|
|
||||||
Optional<LoanDelinquencyAction> resume = findMatchingResume(loanDelinquencyAction, partitioned.get(RESUME));
|
|
||||||
LoanDelinquencyActionData loanDelinquencyActionData = new LoanDelinquencyActionData(loanDelinquencyAction);
|
|
||||||
resume.ifPresent(r -> loanDelinquencyActionData.setEndDate(r.getStartDate()));
|
|
||||||
effective.add(loanDelinquencyActionData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// order them by start date, and convert to DelinquencyPausePeriod objects
|
|
||||||
List<DelinquencyPausePeriod> result = effective.stream() //
|
|
||||||
.sorted(Comparator.comparing(LoanDelinquencyActionData::getStartDate)) //
|
|
||||||
.map(lda -> toDelinquencyPausePeriod(businessDate, lda)).toList(); //
|
|
||||||
collectionData.setDelinquencyPausePeriods(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -219,24 +202,13 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo
|
|||||||
lda.getStartDate(), lda.getEndDate());
|
lda.getStartDate(), lda.getEndDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<LoanDelinquencyAction> findMatchingResume(LoanDelinquencyAction pause, List<LoanDelinquencyAction> resumes) {
|
|
||||||
if (resumes != null && resumes.size() > 0) {
|
|
||||||
for (LoanDelinquencyAction resume : resumes) {
|
|
||||||
if (!pause.getStartDate().isAfter(resume.getStartDate()) && !resume.getStartDate().isAfter(pause.getEndDate())) {
|
|
||||||
return Optional.of(resume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<LoanInstallmentDelinquencyTagData> retrieveLoanInstallmentsCurrentDelinquencyTag(Long loanId) {
|
public Collection<LoanInstallmentDelinquencyTagData> retrieveLoanInstallmentsCurrentDelinquencyTag(Long loanId) {
|
||||||
return repositoryLoanInstallmentDelinquencyTag.findInstallmentDelinquencyTags(loanId);
|
return repositoryLoanInstallmentDelinquencyTag.findInstallmentDelinquencyTags(loanId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<LoanDelinquencyAction> retrieveLoanDelinquencyActions(Long loanId) {
|
public List<LoanDelinquencyAction> retrieveLoanDelinquencyActions(Long loanId) {
|
||||||
final Optional<Loan> optLoan = this.loanRepository.findById(loanId);
|
final Optional<Loan> optLoan = this.loanRepository.findById(loanId);
|
||||||
if (optLoan.isPresent()) {
|
if (optLoan.isPresent()) {
|
||||||
return loanDelinquencyActionRepository.findByLoanOrderById(optLoan.get());
|
return loanDelinquencyActionRepository.findByLoanOrderById(optLoan.get());
|
||||||
|
|||||||
+6
-2
@@ -18,8 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.delinquency.service;
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
|
||||||
@@ -43,9 +45,11 @@ public interface DelinquencyWritePlatformService {
|
|||||||
|
|
||||||
void cleanLoanDelinquencyTags(Loan loan);
|
void cleanLoanDelinquencyTags(Loan loan);
|
||||||
|
|
||||||
LoanScheduleDelinquencyData calculateDelinquencyData(LoanScheduleDelinquencyData loanScheduleDelinquencyData);
|
LoanScheduleDelinquencyData calculateDelinquencyData(LoanScheduleDelinquencyData loanScheduleDelinquencyData,
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList);
|
||||||
|
|
||||||
void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData loanDelinquencyData);
|
void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData loanDelinquencyData,
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList);
|
||||||
|
|
||||||
CommandProcessingResult createDelinquencyAction(Long loanId, JsonCommand command);
|
CommandProcessingResult createDelinquencyAction(Long loanId, JsonCommand command);
|
||||||
|
|
||||||
|
|||||||
+18
-6
@@ -53,9 +53,11 @@ import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquen
|
|||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
|
||||||
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyBucketAgesOverlapedException;
|
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyBucketAgesOverlapedException;
|
||||||
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyRangeInvalidAgesException;
|
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyRangeInvalidAgesException;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParseAndValidator;
|
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParseAndValidator;
|
||||||
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
|
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
|
||||||
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
|
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||||
@@ -81,8 +83,10 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
|||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
private final LoanDelinquencyDomainService loanDelinquencyDomainService;
|
private final LoanDelinquencyDomainService loanDelinquencyDomainService;
|
||||||
private final LoanInstallmentDelinquencyTagRepository loanInstallmentDelinquencyTagRepository;
|
private final LoanInstallmentDelinquencyTagRepository loanInstallmentDelinquencyTagRepository;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
private final LoanDelinquencyActionRepository loanDelinquencyActionRepository;
|
private final LoanDelinquencyActionRepository loanDelinquencyActionRepository;
|
||||||
private final DelinquencyActionParseAndValidator delinquencyActionParseAndValidator;
|
private final DelinquencyActionParseAndValidator delinquencyActionParseAndValidator;
|
||||||
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult createDelinquencyRange(JsonCommand command) {
|
public CommandProcessingResult createDelinquencyRange(JsonCommand command) {
|
||||||
@@ -153,12 +157,13 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoanScheduleDelinquencyData calculateDelinquencyData(LoanScheduleDelinquencyData loanScheduleDelinquencyData) {
|
public LoanScheduleDelinquencyData calculateDelinquencyData(LoanScheduleDelinquencyData loanScheduleDelinquencyData,
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
Loan loan = loanScheduleDelinquencyData.getLoan();
|
Loan loan = loanScheduleDelinquencyData.getLoan();
|
||||||
if (loan == null) {
|
if (loan == null) {
|
||||||
loan = this.loanRepository.findOneWithNotFoundDetection(loanScheduleDelinquencyData.getLoanId());
|
loan = this.loanRepository.findOneWithNotFoundDetection(loanScheduleDelinquencyData.getLoanId());
|
||||||
}
|
}
|
||||||
final CollectionData collectionData = loanDelinquencyDomainService.getOverdueCollectionData(loan);
|
final CollectionData collectionData = loanDelinquencyDomainService.getOverdueCollectionData(loan, effectiveDelinquencyList);
|
||||||
log.debug("Delinquency {}", collectionData);
|
log.debug("Delinquency {}", collectionData);
|
||||||
return new LoanScheduleDelinquencyData(loan.getId(), collectionData.getDelinquentDate(), collectionData.getDelinquentDays(), loan);
|
return new LoanScheduleDelinquencyData(loan.getId(), collectionData.getDelinquentDate(), collectionData.getDelinquentDays(), loan);
|
||||||
}
|
}
|
||||||
@@ -168,9 +173,14 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
|||||||
Map<String, Object> changes = new HashMap<>();
|
Map<String, Object> changes = new HashMap<>();
|
||||||
|
|
||||||
final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId);
|
final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId);
|
||||||
|
final List<LoanDelinquencyAction> savedDelinquencyList = delinquencyReadPlatformService
|
||||||
|
.retrieveLoanDelinquencyActions(loan.getId());
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList = delinquencyEffectivePauseHelper
|
||||||
|
.calculateEffectiveDelinquencyList(savedDelinquencyList);
|
||||||
final DelinquencyBucket delinquencyBucket = loan.getLoanProduct().getDelinquencyBucket();
|
final DelinquencyBucket delinquencyBucket = loan.getLoanProduct().getDelinquencyBucket();
|
||||||
if (delinquencyBucket != null) {
|
if (delinquencyBucket != null) {
|
||||||
final LoanDelinquencyData loanDelinquencyData = loanDelinquencyDomainService.getLoanDelinquencyData(loan);
|
final LoanDelinquencyData loanDelinquencyData = loanDelinquencyDomainService.getLoanDelinquencyData(loan,
|
||||||
|
effectiveDelinquencyList);
|
||||||
// loan delinquent data
|
// loan delinquent data
|
||||||
final CollectionData collectionData = loanDelinquencyData.getLoanCollectionData();
|
final CollectionData collectionData = loanDelinquencyData.getLoanCollectionData();
|
||||||
// loan installments delinquent data
|
// loan installments delinquent data
|
||||||
@@ -188,11 +198,13 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData loanDelinquencyData) {
|
public void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData loanDelinquencyData,
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
final Loan loan = loanDelinquencyData.getLoan();
|
final Loan loan = loanDelinquencyData.getLoan();
|
||||||
if (loan.hasDelinquencyBucket()) {
|
if (loan.hasDelinquencyBucket()) {
|
||||||
final DelinquencyBucket delinquencyBucket = loan.getLoanProduct().getDelinquencyBucket();
|
final DelinquencyBucket delinquencyBucket = loan.getLoanProduct().getDelinquencyBucket();
|
||||||
final LoanDelinquencyData loanDelinquentData = loanDelinquencyDomainService.getLoanDelinquencyData(loan);
|
final LoanDelinquencyData loanDelinquentData = loanDelinquencyDomainService.getLoanDelinquencyData(loan,
|
||||||
|
effectiveDelinquencyList);
|
||||||
// loan delinquent data
|
// loan delinquent data
|
||||||
final CollectionData collectionData = loanDelinquentData.getLoanCollectionData();
|
final CollectionData collectionData = loanDelinquentData.getLoanCollectionData();
|
||||||
// loan installments delinquent data
|
// loan installments delinquent data
|
||||||
@@ -212,7 +224,7 @@ public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlat
|
|||||||
public CommandProcessingResult createDelinquencyAction(Long loanId, JsonCommand command) {
|
public CommandProcessingResult createDelinquencyAction(Long loanId, JsonCommand command) {
|
||||||
final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId);
|
final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId);
|
||||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||||
final List<LoanDelinquencyAction> savedDelinquencyList = loanDelinquencyActionRepository.findByLoanOrderById(loan);
|
final List<LoanDelinquencyAction> savedDelinquencyList = delinquencyReadPlatformService.retrieveLoanDelinquencyActions(loanId);
|
||||||
|
|
||||||
LoanDelinquencyAction parsedDelinquencyAction = delinquencyActionParseAndValidator.validateAndParseUpdate(command, loan,
|
LoanDelinquencyAction parsedDelinquencyAction = delinquencyActionParseAndValidator.validateAndParseUpdate(command, loan,
|
||||||
savedDelinquencyList, businessDate);
|
savedDelinquencyList, businessDate);
|
||||||
|
|||||||
+5
-2
@@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.delinquency.service;
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -29,9 +31,10 @@ public interface LoanDelinquencyDomainService {
|
|||||||
* Charge back transaction
|
* Charge back transaction
|
||||||
*
|
*
|
||||||
* @param loan
|
* @param loan
|
||||||
|
* @param effectiveDelinquencyList
|
||||||
*/
|
*/
|
||||||
CollectionData getOverdueCollectionData(Loan loan);
|
CollectionData getOverdueCollectionData(Loan loan, List<LoanDelinquencyActionData> effectiveDelinquencyList);
|
||||||
|
|
||||||
LoanDelinquencyData getLoanDelinquencyData(Loan loan);
|
LoanDelinquencyData getLoanDelinquencyData(Loan loan, List<LoanDelinquencyActionData> effectiveDelinquencyList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-8
@@ -24,9 +24,12 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -35,11 +38,14 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainService {
|
public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainService {
|
||||||
|
|
||||||
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public CollectionData getOverdueCollectionData(final Loan loan) {
|
public CollectionData getOverdueCollectionData(final Loan loan, List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||||
|
|
||||||
final MonetaryCurrency loanCurrency = loan.getCurrency();
|
final MonetaryCurrency loanCurrency = loan.getCurrency();
|
||||||
@@ -99,7 +105,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
|
|||||||
collectionData.setDelinquentDays(0L);
|
collectionData.setDelinquentDays(0L);
|
||||||
Long delinquentDays = overdueDays - graceDays;
|
Long delinquentDays = overdueDays - graceDays;
|
||||||
if (delinquentDays > 0) {
|
if (delinquentDays > 0) {
|
||||||
collectionData.setDelinquentDays(delinquentDays);
|
calculateDelinquentDays(effectiveDelinquencyList, businessDate, collectionData, delinquentDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Result: {}", collectionData.toString());
|
log.debug("Result: {}", collectionData.toString());
|
||||||
@@ -107,7 +113,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoanDelinquencyData getLoanDelinquencyData(final Loan loan) {
|
public LoanDelinquencyData getLoanDelinquencyData(final Loan loan, List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
|
|
||||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||||
LocalDate overdueSinceDate = null;
|
LocalDate overdueSinceDate = null;
|
||||||
@@ -121,7 +127,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
|
|||||||
for (LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
|
for (LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
|
||||||
CollectionData installmentCollectionData = CollectionData.template();
|
CollectionData installmentCollectionData = CollectionData.template();
|
||||||
if (!installment.isObligationsMet()) {
|
if (!installment.isObligationsMet()) {
|
||||||
installmentCollectionData = getInstallmentOverdueCollectionData(loan, installment);
|
installmentCollectionData = getInstallmentOverdueCollectionData(loan, installment, effectiveDelinquencyList);
|
||||||
outstandingAmount = outstandingAmount.add(installmentCollectionData.getDelinquentAmount());
|
outstandingAmount = outstandingAmount.add(installmentCollectionData.getDelinquentAmount());
|
||||||
// Get the oldest overdue installment if exists
|
// Get the oldest overdue installment if exists
|
||||||
if (DateUtils.isBefore(installment.getDueDate(), businessDate)) {
|
if (DateUtils.isBefore(installment.getDueDate(), businessDate)) {
|
||||||
@@ -165,12 +171,20 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
|
|||||||
collectionData.setDelinquentDays(0L);
|
collectionData.setDelinquentDays(0L);
|
||||||
Long delinquentDays = overdueDays - graceDays;
|
Long delinquentDays = overdueDays - graceDays;
|
||||||
if (delinquentDays > 0) {
|
if (delinquentDays > 0) {
|
||||||
collectionData.setDelinquentDays(delinquentDays);
|
calculateDelinquentDays(effectiveDelinquencyList, businessDate, collectionData, delinquentDays);
|
||||||
}
|
}
|
||||||
return new LoanDelinquencyData(collectionData, loanInstallmentsCollectionData);
|
return new LoanDelinquencyData(collectionData, loanInstallmentsCollectionData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CollectionData getInstallmentOverdueCollectionData(final Loan loan, final LoanRepaymentScheduleInstallment installment) {
|
private void calculateDelinquentDays(List<LoanDelinquencyActionData> effectiveDelinquencyList, LocalDate businessDate,
|
||||||
|
CollectionData collectionData, Long delinquentDays) {
|
||||||
|
Long pausedDays = delinquencyEffectivePauseHelper.getPausedDaysBeforeDate(effectiveDelinquencyList, businessDate);
|
||||||
|
Long calculatedDelinquentDays = delinquentDays - pausedDays;
|
||||||
|
collectionData.setDelinquentDays(calculatedDelinquentDays > 0 ? calculatedDelinquentDays : 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CollectionData getInstallmentOverdueCollectionData(final Loan loan, final LoanRepaymentScheduleInstallment installment,
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
|
||||||
LocalDate overdueSinceDate = null;
|
LocalDate overdueSinceDate = null;
|
||||||
CollectionData collectionData = CollectionData.template();
|
CollectionData collectionData = CollectionData.template();
|
||||||
@@ -193,7 +207,6 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
|
|||||||
|
|
||||||
Long overdueDays = 0L;
|
Long overdueDays = 0L;
|
||||||
if (overdueSinceDate != null) {
|
if (overdueSinceDate != null) {
|
||||||
// TODO : Changes for considering paused delinquency days for overdue days calculation
|
|
||||||
overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate, businessDate);
|
overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate, businessDate);
|
||||||
if (overdueDays < 0) {
|
if (overdueDays < 0) {
|
||||||
overdueDays = 0L;
|
overdueDays = 0L;
|
||||||
@@ -205,7 +218,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
|
|||||||
collectionData.setDelinquentDays(0L);
|
collectionData.setDelinquentDays(0L);
|
||||||
Long delinquentDays = overdueDays;
|
Long delinquentDays = overdueDays;
|
||||||
if (delinquentDays > 0) {
|
if (delinquentDays > 0) {
|
||||||
collectionData.setDelinquentDays(delinquentDays);
|
calculateDelinquentDays(effectiveDelinquencyList, businessDate, collectionData, delinquentDays);
|
||||||
}
|
}
|
||||||
return collectionData;
|
return collectionData;
|
||||||
|
|
||||||
|
|||||||
+11
-8
@@ -25,6 +25,7 @@ import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRangeReposito
|
|||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyActionRepository;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyActionRepository;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquencyTagRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyBucketMapper;
|
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;
|
||||||
@@ -55,10 +56,11 @@ public class DelinquencyConfiguration {
|
|||||||
LoanDelinquencyTagMapper mapperLoanDelinquencyTagHistory, LoanRepository loanRepository,
|
LoanDelinquencyTagMapper mapperLoanDelinquencyTagHistory, LoanRepository loanRepository,
|
||||||
LoanDelinquencyDomainService loanDelinquencyDomainService,
|
LoanDelinquencyDomainService loanDelinquencyDomainService,
|
||||||
LoanInstallmentDelinquencyTagRepository repositoryLoanInstallmentDelinquencyTag,
|
LoanInstallmentDelinquencyTagRepository repositoryLoanInstallmentDelinquencyTag,
|
||||||
LoanDelinquencyActionRepository loanDelinquencyActionRepository) {
|
LoanDelinquencyActionRepository loanDelinquencyActionRepository,
|
||||||
|
DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper) {
|
||||||
return new DelinquencyReadPlatformServiceImpl(repositoryRange, repositoryBucket, repositoryLoanDelinquencyTagHistory, mapperRange,
|
return new DelinquencyReadPlatformServiceImpl(repositoryRange, repositoryBucket, repositoryLoanDelinquencyTagHistory, mapperRange,
|
||||||
mapperBucket, mapperLoanDelinquencyTagHistory, loanRepository, loanDelinquencyDomainService,
|
mapperBucket, mapperLoanDelinquencyTagHistory, loanRepository, loanDelinquencyDomainService,
|
||||||
repositoryLoanInstallmentDelinquencyTag, loanDelinquencyActionRepository);
|
repositoryLoanInstallmentDelinquencyTag, loanDelinquencyActionRepository, delinquencyEffectivePauseHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -70,17 +72,18 @@ public class DelinquencyConfiguration {
|
|||||||
LoanProductRepository loanProductRepository, BusinessEventNotifierService businessEventNotifierService,
|
LoanProductRepository loanProductRepository, BusinessEventNotifierService businessEventNotifierService,
|
||||||
LoanDelinquencyDomainService loanDelinquencyDomainService,
|
LoanDelinquencyDomainService loanDelinquencyDomainService,
|
||||||
LoanInstallmentDelinquencyTagRepository loanInstallmentDelinquencyTagRepository,
|
LoanInstallmentDelinquencyTagRepository loanInstallmentDelinquencyTagRepository,
|
||||||
LoanDelinquencyActionRepository loanDelinquencyActionRepository,
|
DelinquencyReadPlatformService delinquencyReadPlatformService, LoanDelinquencyActionRepository loanDelinquencyActionRepository,
|
||||||
DelinquencyActionParseAndValidator delinquencyActionParseAndValidator) {
|
DelinquencyActionParseAndValidator delinquencyActionParseAndValidator,
|
||||||
|
DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper) {
|
||||||
return new DelinquencyWritePlatformServiceImpl(dataValidatorBucket, dataValidatorRange, repositoryRange, repositoryBucket,
|
return new DelinquencyWritePlatformServiceImpl(dataValidatorBucket, dataValidatorRange, repositoryRange, repositoryBucket,
|
||||||
repositoryBucketMappings, loanDelinquencyTagRepository, loanRepository, loanProductRepository, businessEventNotifierService,
|
repositoryBucketMappings, loanDelinquencyTagRepository, loanRepository, loanProductRepository, businessEventNotifierService,
|
||||||
loanDelinquencyDomainService, loanInstallmentDelinquencyTagRepository, loanDelinquencyActionRepository,
|
loanDelinquencyDomainService, loanInstallmentDelinquencyTagRepository, delinquencyReadPlatformService,
|
||||||
delinquencyActionParseAndValidator);
|
loanDelinquencyActionRepository, delinquencyActionParseAndValidator, delinquencyEffectivePauseHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(LoanDelinquencyDomainService.class)
|
@ConditionalOnMissingBean(LoanDelinquencyDomainService.class)
|
||||||
public LoanDelinquencyDomainService loanDelinquencyDomainService() {
|
public LoanDelinquencyDomainService loanDelinquencyDomainService(DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper) {
|
||||||
return new LoanDelinquencyDomainServiceImpl();
|
return new LoanDelinquencyDomainServiceImpl(delinquencyEffectivePauseHelper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-34
@@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.delinquency.validator;
|
package org.apache.fineract.portfolio.delinquency.validator;
|
||||||
|
|
||||||
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME;
|
|
||||||
import static org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParameters.ACTION;
|
import static org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParameters.ACTION;
|
||||||
import static org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParameters.END_DATE;
|
import static org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParameters.END_DATE;
|
||||||
import static org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParameters.START_DATE;
|
import static org.apache.fineract.portfolio.delinquency.validator.DelinquencyActionParameters.START_DATE;
|
||||||
@@ -26,11 +25,7 @@ import static org.apache.fineract.portfolio.delinquency.validator.DelinquencyAct
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
@@ -42,6 +37,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
|
|||||||
import org.apache.fineract.infrastructure.core.validator.ParseAndValidator;
|
import org.apache.fineract.infrastructure.core.validator.ParseAndValidator;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -50,10 +46,12 @@ import org.springframework.stereotype.Component;
|
|||||||
public class DelinquencyActionParseAndValidator extends ParseAndValidator {
|
public class DelinquencyActionParseAndValidator extends ParseAndValidator {
|
||||||
|
|
||||||
private final FromJsonHelper jsonHelper;
|
private final FromJsonHelper jsonHelper;
|
||||||
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
|
||||||
public LoanDelinquencyAction validateAndParseUpdate(@NotNull final JsonCommand command, Loan loan,
|
public LoanDelinquencyAction validateAndParseUpdate(@NotNull final JsonCommand command, Loan loan,
|
||||||
List<LoanDelinquencyAction> savedDelinquencyActions, LocalDate businessDate) {
|
List<LoanDelinquencyAction> savedDelinquencyActions, LocalDate businessDate) {
|
||||||
List<LoanDelinquencyActionData> effectiveDelinquencyList = calculateEffectiveDelinquencyList(savedDelinquencyActions);
|
List<LoanDelinquencyActionData> effectiveDelinquencyList = delinquencyEffectivePauseHelper
|
||||||
|
.calculateEffectiveDelinquencyList(savedDelinquencyActions);
|
||||||
LoanDelinquencyAction parsedDelinquencyAction = parseCommand(command);
|
LoanDelinquencyAction parsedDelinquencyAction = parseCommand(command);
|
||||||
validateLoanIsActive(loan);
|
validateLoanIsActive(loan);
|
||||||
if (DelinquencyAction.PAUSE.equals(parsedDelinquencyAction.getAction())) {
|
if (DelinquencyAction.PAUSE.equals(parsedDelinquencyAction.getAction())) {
|
||||||
@@ -78,34 +76,6 @@ public class DelinquencyActionParseAndValidator extends ParseAndValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LoanDelinquencyActionData> calculateEffectiveDelinquencyList(List<LoanDelinquencyAction> savedDelinquencyActions) {
|
|
||||||
// partition them based on type
|
|
||||||
Map<DelinquencyAction, List<LoanDelinquencyAction>> partitioned = savedDelinquencyActions.stream()
|
|
||||||
.collect(Collectors.groupingBy(LoanDelinquencyAction::getAction));
|
|
||||||
List<LoanDelinquencyActionData> effective = new ArrayList<>();
|
|
||||||
List<LoanDelinquencyAction> pauses = partitioned.get(DelinquencyAction.PAUSE);
|
|
||||||
if (pauses != null && pauses.size() > 0) {
|
|
||||||
for (LoanDelinquencyAction loanDelinquencyAction : pauses) {
|
|
||||||
Optional<LoanDelinquencyAction> resume = findMatchingResume(loanDelinquencyAction, partitioned.get(RESUME));
|
|
||||||
LoanDelinquencyActionData loanDelinquencyActionData = new LoanDelinquencyActionData(loanDelinquencyAction);
|
|
||||||
resume.ifPresent(r -> loanDelinquencyActionData.setEndDate(r.getStartDate()));
|
|
||||||
effective.add(loanDelinquencyActionData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return effective;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<LoanDelinquencyAction> findMatchingResume(LoanDelinquencyAction pause, List<LoanDelinquencyAction> resumes) {
|
|
||||||
if (resumes != null && resumes.size() > 0) {
|
|
||||||
for (LoanDelinquencyAction resume : resumes) {
|
|
||||||
if (!pause.getStartDate().isAfter(resume.getStartDate()) && !resume.getStartDate().isAfter(pause.getEndDate())) {
|
|
||||||
return Optional.of(resume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateResumeShouldBeOnActivePause(LoanDelinquencyAction parsedDelinquencyAction,
|
private void validateResumeShouldBeOnActivePause(LoanDelinquencyAction parsedDelinquencyAction,
|
||||||
List<LoanDelinquencyActionData> savedDelinquencyActions) {
|
List<LoanDelinquencyActionData> savedDelinquencyActions) {
|
||||||
boolean match = savedDelinquencyActions.stream()
|
boolean match = savedDelinquencyActions.stream()
|
||||||
|
|||||||
+4
@@ -20,10 +20,12 @@ package org.apache.fineract.portfolio.loanaccount.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||||
|
|
||||||
@@ -72,6 +74,8 @@ public interface LoanAccountDomainService {
|
|||||||
*/
|
*/
|
||||||
void setLoanDelinquencyTag(Loan loan, LocalDate transactionDate);
|
void setLoanDelinquencyTag(Loan loan, LocalDate transactionDate);
|
||||||
|
|
||||||
|
void setLoanDelinquencyTag(Loan loan, LocalDate transactionDate, List<LoanDelinquencyActionData> effectiveDelinquencyList);
|
||||||
|
|
||||||
LoanTransaction makeRepayment(LoanTransactionType repaymentTransactionType, Loan loan, LocalDate transactionDate,
|
LoanTransaction makeRepayment(LoanTransactionType repaymentTransactionType, Loan loan, LocalDate transactionDate,
|
||||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, ExternalId txnExternalId,
|
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, ExternalId txnExternalId,
|
||||||
boolean isRecoveryRepayment, String chargeRefundChargeType, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
|
boolean isRecoveryRepayment, String chargeRefundChargeType, boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
|
||||||
|
|||||||
+26
-2
@@ -85,7 +85,11 @@ import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
|||||||
import org.apache.fineract.portfolio.client.domain.Client;
|
import org.apache.fineract.portfolio.client.domain.Client;
|
||||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.group.domain.Group;
|
import org.apache.fineract.portfolio.group.domain.Group;
|
||||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||||
@@ -135,6 +139,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
private final ExternalIdFactory externalIdFactory;
|
private final ExternalIdFactory externalIdFactory;
|
||||||
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
|
private final ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
|
||||||
private final LoanAccrualTransactionBusinessEventService loanAccrualTransactionBusinessEventService;
|
private final LoanAccrualTransactionBusinessEventService loanAccrualTransactionBusinessEventService;
|
||||||
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
@@ -575,12 +581,30 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
@Override
|
@Override
|
||||||
public void setLoanDelinquencyTag(final Loan loan, final LocalDate transactionDate) {
|
public void setLoanDelinquencyTag(final Loan loan, final LocalDate transactionDate) {
|
||||||
LoanScheduleDelinquencyData loanDelinquencyData = new LoanScheduleDelinquencyData(loan.getId(), transactionDate, null, loan);
|
LoanScheduleDelinquencyData loanDelinquencyData = new LoanScheduleDelinquencyData(loan.getId(), transactionDate, null, loan);
|
||||||
loanDelinquencyData = this.delinquencyWritePlatformService.calculateDelinquencyData(loanDelinquencyData);
|
final List<LoanDelinquencyAction> savedDelinquencyList = delinquencyReadPlatformService
|
||||||
|
.retrieveLoanDelinquencyActions(loan.getId());
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList = delinquencyEffectivePauseHelper
|
||||||
|
.calculateEffectiveDelinquencyList(savedDelinquencyList);
|
||||||
|
loanDelinquencyData = this.delinquencyWritePlatformService.calculateDelinquencyData(loanDelinquencyData, effectiveDelinquencyList);
|
||||||
log.debug("Processing Loan {} with {} overdue days since date {}", loanDelinquencyData.getLoanId(),
|
log.debug("Processing Loan {} with {} overdue days since date {}", loanDelinquencyData.getLoanId(),
|
||||||
loanDelinquencyData.getOverdueDays(), loanDelinquencyData.getOverdueSinceDate());
|
loanDelinquencyData.getOverdueDays(), loanDelinquencyData.getOverdueSinceDate());
|
||||||
// Set or Unset the Delinquency Classification Tag
|
// Set or Unset the Delinquency Classification Tag
|
||||||
if (loanDelinquencyData.getOverdueDays() > 0) {
|
if (loanDelinquencyData.getOverdueDays() > 0) {
|
||||||
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData);
|
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData, effectiveDelinquencyList);
|
||||||
|
} else {
|
||||||
|
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLoanDelinquencyTag(Loan loan, LocalDate transactionDate, List<LoanDelinquencyActionData> effectiveDelinquencyList) {
|
||||||
|
LoanScheduleDelinquencyData loanDelinquencyData = new LoanScheduleDelinquencyData(loan.getId(), transactionDate, null, loan);
|
||||||
|
loanDelinquencyData = this.delinquencyWritePlatformService.calculateDelinquencyData(loanDelinquencyData, effectiveDelinquencyList);
|
||||||
|
log.debug("Processing Loan {} with {} overdue days since date {}", loanDelinquencyData.getLoanId(),
|
||||||
|
loanDelinquencyData.getOverdueDays(), loanDelinquencyData.getOverdueSinceDate());
|
||||||
|
// Set or Unset the Delinquency Classification Tag
|
||||||
|
if (loanDelinquencyData.getOverdueDays() > 0) {
|
||||||
|
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData, effectiveDelinquencyList);
|
||||||
} else {
|
} else {
|
||||||
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
|
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -20,6 +20,8 @@ package org.apache.fineract.portfolio.loanaccount.jobs.setloandelinquencytags;
|
|||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
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.helper.DelinquencyEffectivePauseHelper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
@@ -42,6 +44,10 @@ public class SetLoanDelinquencyTagsConfig {
|
|||||||
private JobRepository jobRepository;
|
private JobRepository jobRepository;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlatformTransactionManager transactionManager;
|
private PlatformTransactionManager transactionManager;
|
||||||
|
@Autowired
|
||||||
|
private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
@Autowired
|
||||||
|
private DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
|
||||||
private DelinquencyWritePlatformService delinquencyWritePlatformService;
|
private DelinquencyWritePlatformService delinquencyWritePlatformService;
|
||||||
private LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
private LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||||
@@ -62,7 +68,7 @@ public class SetLoanDelinquencyTagsConfig {
|
|||||||
@Bean
|
@Bean
|
||||||
public SetLoanDelinquencyTagsTasklet setLoanDelinquencyTagsTasklet() {
|
public SetLoanDelinquencyTagsTasklet setLoanDelinquencyTagsTasklet() {
|
||||||
return new SetLoanDelinquencyTagsTasklet(delinquencyWritePlatformService, loanRepaymentScheduleInstallmentRepository,
|
return new SetLoanDelinquencyTagsTasklet(delinquencyWritePlatformService, loanRepaymentScheduleInstallmentRepository,
|
||||||
loanTransactionRepository);
|
loanTransactionRepository, delinquencyEffectivePauseHelper, delinquencyReadPlatformService);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-2
@@ -27,7 +27,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
@@ -45,6 +49,8 @@ public class SetLoanDelinquencyTagsTasklet implements Tasklet {
|
|||||||
private final DelinquencyWritePlatformService delinquencyWritePlatformService;
|
private final DelinquencyWritePlatformService delinquencyWritePlatformService;
|
||||||
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||||
private final LoanTransactionRepository loanTransactionRepository;
|
private final LoanTransactionRepository loanTransactionRepository;
|
||||||
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||||
@@ -80,12 +86,18 @@ public class SetLoanDelinquencyTagsTasklet implements Tasklet {
|
|||||||
log.debug("Were found {} items", loanScheduleDelinquencyData.size());
|
log.debug("Were found {} items", loanScheduleDelinquencyData.size());
|
||||||
for (LoanScheduleDelinquencyData loanDelinquencyData : loanScheduleDelinquencyData) {
|
for (LoanScheduleDelinquencyData loanDelinquencyData : loanScheduleDelinquencyData) {
|
||||||
// Set the data used by Delinquency Classification method
|
// Set the data used by Delinquency Classification method
|
||||||
loanDelinquencyData = this.delinquencyWritePlatformService.calculateDelinquencyData(loanDelinquencyData);
|
List<LoanDelinquencyAction> savedDelinquencyList = delinquencyReadPlatformService
|
||||||
|
.retrieveLoanDelinquencyActions(loanDelinquencyData.getLoanId());
|
||||||
|
List<LoanDelinquencyActionData> effectiveDelinquencyList = delinquencyEffectivePauseHelper
|
||||||
|
.calculateEffectiveDelinquencyList(savedDelinquencyList);
|
||||||
|
|
||||||
|
loanDelinquencyData = this.delinquencyWritePlatformService.calculateDelinquencyData(loanDelinquencyData,
|
||||||
|
effectiveDelinquencyList);
|
||||||
log.debug("Processing Loan {} with {} overdue days since date {}", loanDelinquencyData.getLoanId(),
|
log.debug("Processing Loan {} with {} overdue days since date {}", loanDelinquencyData.getLoanId(),
|
||||||
loanDelinquencyData.getOverdueDays(), loanDelinquencyData.getOverdueSinceDate());
|
loanDelinquencyData.getOverdueDays(), loanDelinquencyData.getOverdueSinceDate());
|
||||||
// Set or Unset the Delinquency Classification Tag
|
// Set or Unset the Delinquency Classification Tag
|
||||||
if (loanDelinquencyData.getOverdueDays() > 0) {
|
if (loanDelinquencyData.getOverdueDays() > 0) {
|
||||||
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData);
|
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData, effectiveDelinquencyList);
|
||||||
} else {
|
} else {
|
||||||
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
|
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-7
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyList;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@@ -41,6 +42,9 @@ import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
|||||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@@ -61,6 +65,12 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
|
|||||||
*/
|
*/
|
||||||
@Mock
|
@Mock
|
||||||
private LoanAccountDomainService loanAccountDomainService;
|
private LoanAccountDomainService loanAccountDomainService;
|
||||||
|
@Mock
|
||||||
|
private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
|
@Mock
|
||||||
|
private DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
@Mock
|
||||||
|
private BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class under test.
|
* The class under test.
|
||||||
@@ -84,9 +94,10 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||||
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
||||||
ThreadLocalContextUtil
|
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()),
|
||||||
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
|
BusinessDateType.COB_DATE, LocalDate.now(ZoneId.systemDefault()))));
|
||||||
underTest = new SetLoanDelinquencyTagsBusinessStep(loanAccountDomainService);
|
underTest = new SetLoanDelinquencyTagsBusinessStep(loanAccountDomainService, delinquencyEffectivePauseHelper,
|
||||||
|
delinquencyReadPlatformService, businessEventNotifierService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,14 +109,14 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testExecuteSuccessScenario() throws Exception {
|
public void testExecuteSuccessScenario() throws Exception {
|
||||||
// given
|
// given
|
||||||
doNothing().when(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class));
|
doNothing().when(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class), anyList());
|
||||||
Loan loanForProcessing = createLoan();
|
Loan loanForProcessing = createLoan();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Loan processedLoan = underTest.execute(loanForProcessing);
|
Loan processedLoan = underTest.execute(loanForProcessing);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class));
|
verify(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class), anyList());
|
||||||
assertEquals(processedLoan, loanForProcessing);
|
assertEquals(processedLoan, loanForProcessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,14 +148,15 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testExecuteWhenSetLoanDelinquencyTagFails() throws Exception {
|
public void testExecuteWhenSetLoanDelinquencyTagFails() throws Exception {
|
||||||
// given
|
// given
|
||||||
doThrow(new RuntimeException()).when(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class));
|
doThrow(new RuntimeException()).when(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class),
|
||||||
|
anyList());
|
||||||
Loan loanForProcessing = createLoan();
|
Loan loanForProcessing = createLoan();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final Throwable thrownException = assertThrows(RuntimeException.class, () -> underTest.execute(loanForProcessing));
|
final Throwable thrownException = assertThrows(RuntimeException.class, () -> underTest.execute(loanForProcessing));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class));
|
verify(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class), any(LocalDate.class), anyList());
|
||||||
assertTrue(thrownException.getClass().isAssignableFrom(RuntimeException.class));
|
assertTrue(thrownException.getClass().isAssignableFrom(RuntimeException.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* 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.portfolio.delinquency.helper;
|
||||||
|
|
||||||
|
import static java.time.Month.JANUARY;
|
||||||
|
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.PAUSE;
|
||||||
|
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class DelinquencyEffectivePauseHelperTest {
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private DelinquencyEffectivePauseHelperImpl underTest;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiplePausesWithoutResumeActionCurrentlyInPauseFirstDay() {
|
||||||
|
// given
|
||||||
|
List<LoanDelinquencyAction> delinquencyActions = List.of(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11)),
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 12), LocalDate.of(2023, JANUARY, 13)),
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<LoanDelinquencyActionData> effectivePeriods = underTest.calculateEffectiveDelinquencyList(delinquencyActions);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(effectivePeriods.get(0).getStartDate(), LocalDate.of(2023, 1, 10));
|
||||||
|
assertEquals(effectivePeriods.get(0).getEndDate(), LocalDate.of(2023, 1, 11));
|
||||||
|
assertEquals(effectivePeriods.get(1).getStartDate(), LocalDate.of(2023, 1, 12));
|
||||||
|
assertEquals(effectivePeriods.get(1).getEndDate(), LocalDate.of(2023, 1, 13));
|
||||||
|
assertEquals(effectivePeriods.get(2).getStartDate(), LocalDate.of(2023, 1, 15));
|
||||||
|
assertEquals(effectivePeriods.get(2).getEndDate(), LocalDate.of(2023, 1, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResumeIsAppliedToOneOfThePauseNotActive() {
|
||||||
|
// given
|
||||||
|
List<LoanDelinquencyAction> delinquencyActions = List.of(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 20)),
|
||||||
|
new LoanDelinquencyAction(null, RESUME, LocalDate.of(2023, JANUARY, 11), null),
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 13), LocalDate.of(2023, JANUARY, 14)),
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<LoanDelinquencyActionData> effectivePeriods = underTest.calculateEffectiveDelinquencyList(delinquencyActions);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(effectivePeriods.get(0).getStartDate(), LocalDate.of(2023, 1, 10));
|
||||||
|
assertEquals(effectivePeriods.get(0).getEndDate(), LocalDate.of(2023, 1, 11));
|
||||||
|
assertEquals(effectivePeriods.get(1).getStartDate(), LocalDate.of(2023, 1, 13));
|
||||||
|
assertEquals(effectivePeriods.get(1).getEndDate(), LocalDate.of(2023, 1, 14));
|
||||||
|
assertEquals(effectivePeriods.get(2).getStartDate(), LocalDate.of(2023, 1, 15));
|
||||||
|
assertEquals(effectivePeriods.get(2).getEndDate(), LocalDate.of(2023, 1, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+31
-61
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.delinquency.service;
|
|||||||
|
|
||||||
import static java.time.Month.JANUARY;
|
import static java.time.Month.JANUARY;
|
||||||
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.PAUSE;
|
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.PAUSE;
|
||||||
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -35,6 +34,7 @@ import org.apache.fineract.portfolio.delinquency.domain.LoanInstallmentDelinquen
|
|||||||
import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyBucketMapper;
|
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.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.DelinquencyPausePeriod;
|
import org.apache.fineract.portfolio.loanaccount.data.DelinquencyPausePeriod;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||||
@@ -82,22 +82,25 @@ class DelinquencyReadPlatformServiceImplTest {
|
|||||||
public void testNoEnrichmentWhenThereIsNoDelinquencyAction() {
|
public void testNoEnrichmentWhenThereIsNoDelinquencyAction() {
|
||||||
// given
|
// given
|
||||||
CollectionData collectionData = CollectionData.template();
|
CollectionData collectionData = CollectionData.template();
|
||||||
Collection<LoanDelinquencyAction> delinquencyActions = List.of();
|
Collection<LoanDelinquencyActionData> delinquencyActions = List.of();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 12));
|
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 12));
|
||||||
|
|
||||||
Assertions.assertNull(collectionData.getDelinquencyPausePeriods());
|
Assertions.assertTrue(collectionData.getDelinquencyPausePeriods().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiplePausesWithoutResumeActionCurrentlyInPauseFirstDay() {
|
public void testMultiplePausesWithoutResumeActionCurrentlyInPauseFirstDay() {
|
||||||
// given
|
// given
|
||||||
CollectionData collectionData = CollectionData.template();
|
CollectionData collectionData = CollectionData.template();
|
||||||
Collection<LoanDelinquencyAction> delinquencyActions = List.of(
|
Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11)),
|
new LoanDelinquencyActionData(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 12), LocalDate.of(2023, JANUARY, 13)),
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11))),
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 12), LocalDate.of(2023, JANUARY, 13))),
|
||||||
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 12));
|
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 12));
|
||||||
@@ -114,10 +117,13 @@ class DelinquencyReadPlatformServiceImplTest {
|
|||||||
public void testMultiplePausesWithoutResumeActionCurrentlyInPauseLastDay() {
|
public void testMultiplePausesWithoutResumeActionCurrentlyInPauseLastDay() {
|
||||||
// given
|
// given
|
||||||
CollectionData collectionData = CollectionData.template();
|
CollectionData collectionData = CollectionData.template();
|
||||||
Collection<LoanDelinquencyAction> delinquencyActions = List.of(
|
Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11)),
|
new LoanDelinquencyActionData(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 12), LocalDate.of(2023, JANUARY, 13)),
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11))),
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 12), LocalDate.of(2023, JANUARY, 13))),
|
||||||
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 13));
|
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 13));
|
||||||
@@ -133,10 +139,13 @@ class DelinquencyReadPlatformServiceImplTest {
|
|||||||
public void testMultiplePausesWithoutResumeActionCurrentBusinessDateBetweenStartAndEndDate() {
|
public void testMultiplePausesWithoutResumeActionCurrentBusinessDateBetweenStartAndEndDate() {
|
||||||
// given
|
// given
|
||||||
CollectionData collectionData = CollectionData.template();
|
CollectionData collectionData = CollectionData.template();
|
||||||
Collection<LoanDelinquencyAction> delinquencyActions = List.of(
|
Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11)),
|
new LoanDelinquencyActionData(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 12), LocalDate.of(2023, JANUARY, 14)),
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11))),
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 12), LocalDate.of(2023, JANUARY, 14))),
|
||||||
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 13));
|
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 13));
|
||||||
@@ -152,10 +161,13 @@ class DelinquencyReadPlatformServiceImplTest {
|
|||||||
public void testMultiplePausesWithoutResumeCurrentBusinessDateIsNotOverlappingWithAnyOfThePauses() {
|
public void testMultiplePausesWithoutResumeCurrentBusinessDateIsNotOverlappingWithAnyOfThePauses() {
|
||||||
// given
|
// given
|
||||||
CollectionData collectionData = CollectionData.template();
|
CollectionData collectionData = CollectionData.template();
|
||||||
Collection<LoanDelinquencyAction> delinquencyActions = List.of(
|
Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11)),
|
new LoanDelinquencyActionData(
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 13), LocalDate.of(2023, JANUARY, 14)),
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 11))),
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 13), LocalDate.of(2023, JANUARY, 14))),
|
||||||
|
new LoanDelinquencyActionData(
|
||||||
|
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 12));
|
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 12));
|
||||||
@@ -168,48 +180,6 @@ class DelinquencyReadPlatformServiceImplTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testResumeIsAppliedToOneOfThePauseNotActive() {
|
|
||||||
// given
|
|
||||||
CollectionData collectionData = CollectionData.template();
|
|
||||||
Collection<LoanDelinquencyAction> delinquencyActions = List.of(
|
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 20)),
|
|
||||||
new LoanDelinquencyAction(null, RESUME, LocalDate.of(2023, JANUARY, 11), null),
|
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 13), LocalDate.of(2023, JANUARY, 14)),
|
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
|
||||||
|
|
||||||
// when
|
|
||||||
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 12));
|
|
||||||
|
|
||||||
// then
|
|
||||||
verifyPausePeriods(collectionData, //
|
|
||||||
pausePeriod(false, "2023-01-10", "2023-01-11"), //
|
|
||||||
pausePeriod(false, "2023-01-13", "2023-01-14"), //
|
|
||||||
pausePeriod(false, "2023-01-15", "2023-01-20") //
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testResumeIsAppliedToOneOfThePauseActive() {
|
|
||||||
// given
|
|
||||||
CollectionData collectionData = CollectionData.template();
|
|
||||||
Collection<LoanDelinquencyAction> delinquencyActions = List.of(
|
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 10), LocalDate.of(2023, JANUARY, 20)),
|
|
||||||
new LoanDelinquencyAction(null, RESUME, LocalDate.of(2023, JANUARY, 11), null),
|
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 13), LocalDate.of(2023, JANUARY, 14)),
|
|
||||||
new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
|
|
||||||
|
|
||||||
// when
|
|
||||||
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData, delinquencyActions, LocalDate.of(2023, JANUARY, 11));
|
|
||||||
|
|
||||||
// then
|
|
||||||
verifyPausePeriods(collectionData, //
|
|
||||||
pausePeriod(true, "2023-01-10", "2023-01-11"), //
|
|
||||||
pausePeriod(false, "2023-01-13", "2023-01-14"), //
|
|
||||||
pausePeriod(false, "2023-01-15", "2023-01-20") //
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyPausePeriods(CollectionData collectionData, DelinquencyPausePeriod... pausePeriods) {
|
private void verifyPausePeriods(CollectionData collectionData, DelinquencyPausePeriod... pausePeriods) {
|
||||||
if (pausePeriods.length > 0) {
|
if (pausePeriods.length > 0) {
|
||||||
Assertions.assertEquals(Arrays.asList(pausePeriods), collectionData.getDelinquencyPausePeriods());
|
Assertions.assertEquals(Arrays.asList(pausePeriods), collectionData.getDelinquencyPausePeriods());
|
||||||
|
|||||||
+19
-3
@@ -42,6 +42,7 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
|
|||||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
|
||||||
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -54,7 +55,9 @@ import org.mockito.Mockito;
|
|||||||
class DelinquencyActionParseAndValidatorTest {
|
class DelinquencyActionParseAndValidatorTest {
|
||||||
|
|
||||||
private final FromJsonHelper fromJsonHelper = new FromJsonHelper();
|
private final FromJsonHelper fromJsonHelper = new FromJsonHelper();
|
||||||
private final DelinquencyActionParseAndValidator underTest = new DelinquencyActionParseAndValidator(fromJsonHelper);
|
private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper = Mockito.mock(DelinquencyEffectivePauseHelper.class);
|
||||||
|
private final DelinquencyActionParseAndValidator underTest = new DelinquencyActionParseAndValidator(fromJsonHelper,
|
||||||
|
delinquencyEffectivePauseHelper);
|
||||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.US);
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.US);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -77,9 +80,12 @@ class DelinquencyActionParseAndValidatorTest {
|
|||||||
Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
|
Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
|
||||||
|
|
||||||
JsonCommand command = delinquencyAction("resume", "09 September 2022", null);
|
JsonCommand command = delinquencyAction("resume", "09 September 2022", null);
|
||||||
|
List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "05 September 2022", "15 September 2022"));
|
||||||
|
List<LoanDelinquencyActionData> effectiveList = List.of(loanDelinquencyActionData(existing.get(0)));
|
||||||
|
Mockito.when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(existing)).thenReturn(effectiveList);
|
||||||
|
|
||||||
LoanDelinquencyAction parsedDelinquencyAction = underTest.validateAndParseUpdate(command, loan,
|
LoanDelinquencyAction parsedDelinquencyAction = underTest.validateAndParseUpdate(command, loan, existing,
|
||||||
List.of(loanDelinquencyAction(PAUSE, "05 September 2022", "15 September 2022")), localDate("09 September 2022"));
|
localDate("09 September 2022"));
|
||||||
Assertions.assertEquals(RESUME, parsedDelinquencyAction.getAction());
|
Assertions.assertEquals(RESUME, parsedDelinquencyAction.getAction());
|
||||||
Assertions.assertEquals(localDate("09 September 2022"), parsedDelinquencyAction.getStartDate());
|
Assertions.assertEquals(localDate("09 September 2022"), parsedDelinquencyAction.getStartDate());
|
||||||
Assertions.assertNull(parsedDelinquencyAction.getEndDate());
|
Assertions.assertNull(parsedDelinquencyAction.getEndDate());
|
||||||
@@ -92,6 +98,8 @@ class DelinquencyActionParseAndValidatorTest {
|
|||||||
|
|
||||||
List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "14 September 2022", "22 September 2022"));
|
List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "14 September 2022", "22 September 2022"));
|
||||||
JsonCommand command = delinquencyAction("pause", "09 September 2022", "15 September 2022");
|
JsonCommand command = delinquencyAction("pause", "09 September 2022", "15 September 2022");
|
||||||
|
List<LoanDelinquencyActionData> effectiveList = List.of(loanDelinquencyActionData(existing.get(0)));
|
||||||
|
Mockito.when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(existing)).thenReturn(effectiveList);
|
||||||
|
|
||||||
assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
|
assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
|
||||||
"loan-delinquency-action-overlapping",
|
"loan-delinquency-action-overlapping",
|
||||||
@@ -105,6 +113,8 @@ class DelinquencyActionParseAndValidatorTest {
|
|||||||
|
|
||||||
List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "14 September 2022", "22 September 2022"));
|
List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "14 September 2022", "22 September 2022"));
|
||||||
JsonCommand command = delinquencyAction("pause", "15 September 2022", "23 September 2022");
|
JsonCommand command = delinquencyAction("pause", "15 September 2022", "23 September 2022");
|
||||||
|
List<LoanDelinquencyActionData> effectiveList = List.of(loanDelinquencyActionData(existing.get(0)));
|
||||||
|
Mockito.when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(existing)).thenReturn(effectiveList);
|
||||||
|
|
||||||
assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
|
assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
|
||||||
"loan-delinquency-action-overlapping",
|
"loan-delinquency-action-overlapping",
|
||||||
@@ -118,6 +128,8 @@ class DelinquencyActionParseAndValidatorTest {
|
|||||||
|
|
||||||
List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "15 September 2022", "22 September 2022"));
|
List<LoanDelinquencyAction> existing = List.of(loanDelinquencyAction(PAUSE, "15 September 2022", "22 September 2022"));
|
||||||
JsonCommand command = delinquencyAction("pause", "13 September 2022", "20 September 2022");
|
JsonCommand command = delinquencyAction("pause", "13 September 2022", "20 September 2022");
|
||||||
|
List<LoanDelinquencyActionData> effectiveList = List.of(loanDelinquencyActionData(existing.get(0)));
|
||||||
|
Mockito.when(delinquencyEffectivePauseHelper.calculateEffectiveDelinquencyList(existing)).thenReturn(effectiveList);
|
||||||
|
|
||||||
assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
|
assertPlatformValidationException("Delinquency pause period cannot overlap with another pause period",
|
||||||
"loan-delinquency-action-overlapping",
|
"loan-delinquency-action-overlapping",
|
||||||
@@ -339,6 +351,10 @@ class DelinquencyActionParseAndValidatorTest {
|
|||||||
return new LoanDelinquencyAction(null, action, localDate(startTime), localDate(endTime));
|
return new LoanDelinquencyAction(null, action, localDate(startTime), localDate(endTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LoanDelinquencyActionData loanDelinquencyActionData(LoanDelinquencyAction loanDelinquencyAction) {
|
||||||
|
return new LoanDelinquencyActionData(loanDelinquencyAction);
|
||||||
|
}
|
||||||
|
|
||||||
private LoanDelinquencyAction loanDelinquencyAction(DelinquencyAction action, String startTime) {
|
private LoanDelinquencyAction loanDelinquencyAction(DelinquencyAction action, String startTime) {
|
||||||
return new LoanDelinquencyAction(null, action, localDate(startTime), null);
|
return new LoanDelinquencyAction(null, action, localDate(startTime), null);
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-11
@@ -31,6 +31,7 @@ import java.math.BigDecimal;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -56,6 +57,7 @@ import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatfor
|
|||||||
import org.apache.fineract.portfolio.delinquency.service.LoanDelinquencyDomainService;
|
import org.apache.fineract.portfolio.delinquency.service.LoanDelinquencyDomainService;
|
||||||
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
|
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
|
||||||
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
|
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
|
||||||
@@ -115,6 +117,7 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDeliquencyRangeChangeEvent = ArgumentCaptor
|
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDeliquencyRangeChangeEvent = ArgumentCaptor
|
||||||
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
|
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
|
||||||
@@ -140,10 +143,11 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(true);
|
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(true);
|
||||||
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(false);
|
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(false);
|
||||||
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
||||||
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing)).thenReturn(loanDelinquencyData);
|
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing, effectiveDelinquencyList))
|
||||||
|
.thenReturn(loanDelinquencyData);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
|
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
||||||
@@ -155,6 +159,7 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenLoanAccountWithDelinquencyBucketWhenNoRangeChangeThenNoEventIsRaised() {
|
public void givenLoanAccountWithDelinquencyBucketWhenNoRangeChangeThenNoEventIsRaised() {
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
|
|
||||||
@@ -181,10 +186,11 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
when(loanProduct.getDelinquencyBucket()).thenReturn(delinquencyBucket);
|
when(loanProduct.getDelinquencyBucket()).thenReturn(delinquencyBucket);
|
||||||
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(true);
|
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(true);
|
||||||
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
||||||
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing)).thenReturn(loanDelinquencyData);
|
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing, effectiveDelinquencyList))
|
||||||
|
.thenReturn(loanDelinquencyData);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
|
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanDelinquencyTagRepository, times(0)).saveAllAndFlush(anyIterable());
|
verify(loanDelinquencyTagRepository, times(0)).saveAllAndFlush(anyIterable());
|
||||||
@@ -194,6 +200,7 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenLoanAccountWithNoDelinquencyBucketThenNoEventIsRaised() {
|
public void givenLoanAccountWithNoDelinquencyBucketThenNoEventIsRaised() {
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
|
|
||||||
LocalDate overDueSinceDate = DateUtils.getBusinessLocalDate();
|
LocalDate overDueSinceDate = DateUtils.getBusinessLocalDate();
|
||||||
@@ -203,7 +210,7 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(false);
|
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(false);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
|
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanDelinquencyTagRepository, times(0)).saveAllAndFlush(anyIterable());
|
verify(loanDelinquencyTagRepository, times(0)).saveAllAndFlush(anyIterable());
|
||||||
@@ -218,6 +225,7 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
|
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
|
||||||
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
|
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
|
||||||
@@ -260,12 +268,13 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
||||||
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
||||||
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
||||||
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing)).thenReturn(loanDelinquencyData);
|
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing, effectiveDelinquencyList))
|
||||||
|
.thenReturn(loanDelinquencyData);
|
||||||
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(0)))
|
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(0)))
|
||||||
.thenReturn(Optional.empty());
|
.thenReturn(Optional.empty());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
|
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
||||||
@@ -293,6 +302,7 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
|
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
|
||||||
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
|
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
|
||||||
@@ -338,12 +348,13 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
||||||
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
||||||
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
||||||
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing)).thenReturn(loanDelinquencyData);
|
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing, effectiveDelinquencyList))
|
||||||
|
.thenReturn(loanDelinquencyData);
|
||||||
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(0)))
|
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(0)))
|
||||||
.thenReturn(Optional.of(previousInstallmentTag));
|
.thenReturn(Optional.of(previousInstallmentTag));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
|
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
||||||
@@ -374,6 +385,7 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
|
|
||||||
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
|
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent> loanDelinquencyRangeChangeEvent = ArgumentCaptor
|
||||||
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
// given
|
// given
|
||||||
Loan loanForProcessing = Mockito.mock(Loan.class);
|
Loan loanForProcessing = Mockito.mock(Loan.class);
|
||||||
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
|
||||||
@@ -431,14 +443,15 @@ public class DelinquencyWritePlatformServiceRangeChangeEventTest {
|
|||||||
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
||||||
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
||||||
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(), any())).thenReturn(Optional.empty());
|
||||||
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing)).thenReturn(loanDelinquencyData);
|
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing, effectiveDelinquencyList))
|
||||||
|
.thenReturn(loanDelinquencyData);
|
||||||
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(0)))
|
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(0)))
|
||||||
.thenReturn(Optional.of(previousInstallmentTag_1));
|
.thenReturn(Optional.of(previousInstallmentTag_1));
|
||||||
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(1)))
|
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing, repaymentScheduleInstallments.get(1)))
|
||||||
.thenReturn(Optional.of(previousInstallmentTag));
|
.thenReturn(Optional.of(previousInstallmentTag));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
|
underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
verify(loanDelinquencyTagRepository, times(1)).saveAllAndFlush(anyIterable());
|
||||||
|
|||||||
+17
-5
@@ -42,7 +42,9 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
|||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.helper.DelinquencyEffectivePauseHelper;
|
||||||
import org.apache.fineract.portfolio.delinquency.service.LoanDelinquencyDomainServiceImpl;
|
import org.apache.fineract.portfolio.delinquency.service.LoanDelinquencyDomainServiceImpl;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -75,6 +77,8 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
private Loan loan;
|
private Loan loan;
|
||||||
@Mock
|
@Mock
|
||||||
private LoanProduct loanProduct;
|
private LoanProduct loanProduct;
|
||||||
|
@Mock
|
||||||
|
private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private LoanDelinquencyDomainServiceImpl underTest;
|
private LoanDelinquencyDomainServiceImpl underTest;
|
||||||
|
|
||||||
@@ -107,6 +111,7 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenLoanAccountWithoutOverdueThenCalculateDelinquentData() {
|
public void givenLoanAccountWithoutOverdueThenCalculateDelinquentData() {
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
final LocalDate fromDate = businessDate.minusMonths(1);
|
final LocalDate fromDate = businessDate.minusMonths(1);
|
||||||
final LocalDate dueDate = businessDate;
|
final LocalDate dueDate = businessDate;
|
||||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = Arrays.asList(new LoanRepaymentScheduleInstallment(loan, 1,
|
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = Arrays.asList(new LoanRepaymentScheduleInstallment(loan, 1,
|
||||||
@@ -118,7 +123,7 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
||||||
when(loan.getCurrency()).thenReturn(currency);
|
when(loan.getCurrency()).thenReturn(currency);
|
||||||
|
|
||||||
CollectionData collectionData = underTest.getOverdueCollectionData(loan);
|
CollectionData collectionData = underTest.getOverdueCollectionData(loan, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(0L, collectionData.getDelinquentDays());
|
assertEquals(0L, collectionData.getDelinquentDays());
|
||||||
@@ -130,6 +135,7 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenLoanAccountWithOverdueThenCalculateDelinquentData() {
|
public void givenLoanAccountWithOverdueThenCalculateDelinquentData() {
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
final Long daysDiff = 2L;
|
final Long daysDiff = 2L;
|
||||||
final LocalDate fromDate = businessDate.minusMonths(1).minusDays(daysDiff);
|
final LocalDate fromDate = businessDate.minusMonths(1).minusDays(daysDiff);
|
||||||
final LocalDate dueDate = businessDate.minusDays(daysDiff);
|
final LocalDate dueDate = businessDate.minusDays(daysDiff);
|
||||||
@@ -143,8 +149,9 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
when(loan.getLoanTransactions(Mockito.any(Predicate.class))).thenReturn(Collections.emptyList());
|
when(loan.getLoanTransactions(Mockito.any(Predicate.class))).thenReturn(Collections.emptyList());
|
||||||
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
|
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
|
||||||
when(loan.getCurrency()).thenReturn(currency);
|
when(loan.getCurrency()).thenReturn(currency);
|
||||||
|
when(delinquencyEffectivePauseHelper.getPausedDaysBeforeDate(effectiveDelinquencyList, businessDate)).thenReturn(0L);
|
||||||
|
|
||||||
CollectionData collectionData = underTest.getOverdueCollectionData(loan);
|
CollectionData collectionData = underTest.getOverdueCollectionData(loan, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(daysDiff, collectionData.getDelinquentDays());
|
assertEquals(daysDiff, collectionData.getDelinquentDays());
|
||||||
@@ -156,6 +163,7 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenLoanAccountWithoutOverdueWithChargebackThenCalculateDelinquentData() {
|
public void givenLoanAccountWithoutOverdueWithChargebackThenCalculateDelinquentData() {
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
PaymentDetail paymentDetail = Mockito.mock(PaymentDetail.class);
|
PaymentDetail paymentDetail = Mockito.mock(PaymentDetail.class);
|
||||||
Long daysDiff = 2L;
|
Long daysDiff = 2L;
|
||||||
final LocalDate fromDate = businessDate.minusMonths(1).plusDays(daysDiff);
|
final LocalDate fromDate = businessDate.minusMonths(1).plusDays(daysDiff);
|
||||||
@@ -178,7 +186,7 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
|
||||||
when(loan.getCurrency()).thenReturn(currency);
|
when(loan.getCurrency()).thenReturn(currency);
|
||||||
|
|
||||||
CollectionData collectionData = underTest.getOverdueCollectionData(loan);
|
CollectionData collectionData = underTest.getOverdueCollectionData(loan, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(0L, collectionData.getDelinquentDays());
|
assertEquals(0L, collectionData.getDelinquentDays());
|
||||||
@@ -190,6 +198,7 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenLoanInstallmentWithOverdueEnableInstallmentDelinquencyThenCalculateDelinquentData() {
|
public void givenLoanInstallmentWithOverdueEnableInstallmentDelinquencyThenCalculateDelinquentData() {
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
final Long daysDiff = 2L;
|
final Long daysDiff = 2L;
|
||||||
final LocalDate fromDate = businessDate.minusMonths(1).minusDays(daysDiff);
|
final LocalDate fromDate = businessDate.minusMonths(1).minusDays(daysDiff);
|
||||||
final LocalDate dueDate = businessDate.minusDays(daysDiff);
|
final LocalDate dueDate = businessDate.minusDays(daysDiff);
|
||||||
@@ -207,8 +216,9 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
|
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
|
||||||
when(loan.getCurrency()).thenReturn(currency);
|
when(loan.getCurrency()).thenReturn(currency);
|
||||||
when(loan.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
when(loan.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
||||||
|
when(delinquencyEffectivePauseHelper.getPausedDaysBeforeDate(effectiveDelinquencyList, businessDate)).thenReturn(0L);
|
||||||
|
|
||||||
LoanDelinquencyData collectionData = underTest.getLoanDelinquencyData(loan);
|
LoanDelinquencyData collectionData = underTest.getLoanDelinquencyData(loan, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertNotNull(collectionData);
|
assertNotNull(collectionData);
|
||||||
@@ -232,6 +242,7 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
public void givenLoanInstallmentWithoutOverdueWithChargebackAndEnableInstallmentDelinquencyThenCalculateDelinquentData() {
|
public void givenLoanInstallmentWithoutOverdueWithChargebackAndEnableInstallmentDelinquencyThenCalculateDelinquentData() {
|
||||||
|
|
||||||
// given
|
// given
|
||||||
|
final List<LoanDelinquencyActionData> effectiveDelinquencyList = Collections.emptyList();
|
||||||
PaymentDetail paymentDetail = Mockito.mock(PaymentDetail.class);
|
PaymentDetail paymentDetail = Mockito.mock(PaymentDetail.class);
|
||||||
Long daysDiff = 2L;
|
Long daysDiff = 2L;
|
||||||
final LocalDate fromDate = businessDate.minusMonths(1).plusDays(daysDiff);
|
final LocalDate fromDate = businessDate.minusMonths(1).plusDays(daysDiff);
|
||||||
@@ -255,8 +266,9 @@ public class LoanDelinquencyDomainServiceTest {
|
|||||||
when(loan.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
when(loan.isEnableInstallmentLevelDelinquency()).thenReturn(true);
|
||||||
when(loan.getCurrency()).thenReturn(currency);
|
when(loan.getCurrency()).thenReturn(currency);
|
||||||
when(loan.getLoanTransactions(Mockito.any(Predicate.class))).thenReturn(Arrays.asList(loanTransaction));
|
when(loan.getLoanTransactions(Mockito.any(Predicate.class))).thenReturn(Arrays.asList(loanTransaction));
|
||||||
|
when(delinquencyEffectivePauseHelper.getPausedDaysBeforeDate(effectiveDelinquencyList, businessDate)).thenReturn(0L);
|
||||||
|
|
||||||
LoanDelinquencyData collectionData = underTest.getLoanDelinquencyData(loan);
|
LoanDelinquencyData collectionData = underTest.getLoanDelinquencyData(loan, effectiveDelinquencyList);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertNotNull(collectionData);
|
assertNotNull(collectionData);
|
||||||
|
|||||||
+533
@@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.integrationtests;
|
package org.apache.fineract.integrationtests;
|
||||||
|
|
||||||
|
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.PAUSE;
|
||||||
|
import static org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME;
|
||||||
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;
|
||||||
@@ -30,6 +32,7 @@ import io.restassured.builder.ResponseSpecBuilder;
|
|||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import io.restassured.specification.RequestSpecification;
|
import io.restassured.specification.RequestSpecification;
|
||||||
import io.restassured.specification.ResponseSpecification;
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -42,11 +45,13 @@ import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
|
|||||||
import org.apache.fineract.client.models.GetDelinquencyTagHistoryResponse;
|
import org.apache.fineract.client.models.GetDelinquencyTagHistoryResponse;
|
||||||
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdDelinquencySummary;
|
import org.apache.fineract.client.models.GetLoansLoanIdDelinquencySummary;
|
||||||
|
import org.apache.fineract.client.models.GetLoansLoanIdLoanInstallmentLevelDelinquency;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule;
|
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.PostLoansDelinquencyActionResponse;
|
||||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||||
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;
|
||||||
@@ -1002,6 +1007,525 @@ public class DelinquencyBucketsIntegrationTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyWithPauseLettingPauseExpire() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
|
||||||
|
LocalDate bussinesLocalDate = Utils.getDateAsLocalDate("01 January 2012");
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
|
||||||
|
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());
|
||||||
|
final GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
delinquencyRangeResponse.getResourceId());
|
||||||
|
final String classificationExpected = range.getClassification();
|
||||||
|
log.info("Expected Delinquency Range classification {}", classificationExpected);
|
||||||
|
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 60);
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, jsonBucket);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketResponse.getResourceId());
|
||||||
|
|
||||||
|
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||||
|
Math.toIntExact(delinquencyBucket.getId()), "3");
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
log.info("Loan Product Arrears: {}", getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final LocalDate transactionDate = bussinesLocalDate;
|
||||||
|
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||||
|
|
||||||
|
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||||
|
getLoanProductsProductResponse.getId().toString(), operationDate, "3");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
final GetDelinquencyRangesResponse firstTestCase = getLoansLoanIdResponse.getDelinquencyRange();
|
||||||
|
log.info("Loan Delinquency Range is null {}", (firstTestCase == null));
|
||||||
|
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||||
|
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final String jobName = "Loan COB";
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("06 February 2012");
|
||||||
|
LocalDate lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
GetLoansLoanIdDelinquencySummary delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||||
|
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("09 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("12 March 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(2049.99, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(36, delinquent.getDelinquentDays());
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyWithPauseResumeBeforePauseExpires() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
|
||||||
|
LocalDate bussinesLocalDate = Utils.getDateAsLocalDate("01 January 2012");
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
|
||||||
|
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());
|
||||||
|
final GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
delinquencyRangeResponse.getResourceId());
|
||||||
|
final String classificationExpected = range.getClassification();
|
||||||
|
log.info("Expected Delinquency Range classification {}", classificationExpected);
|
||||||
|
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 60);
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, jsonBucket);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketResponse.getResourceId());
|
||||||
|
|
||||||
|
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||||
|
Math.toIntExact(delinquencyBucket.getId()), "3");
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
log.info("Loan Product Arrears: {}", getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final LocalDate transactionDate = bussinesLocalDate;
|
||||||
|
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||||
|
|
||||||
|
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||||
|
getLoanProductsProductResponse.getId().toString(), operationDate, "3");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
final GetDelinquencyRangesResponse firstTestCase = getLoansLoanIdResponse.getDelinquencyRange();
|
||||||
|
log.info("Loan Delinquency Range is null {}", (firstTestCase == null));
|
||||||
|
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||||
|
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final String jobName = "Loan COB";
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("06 February 2012");
|
||||||
|
LocalDate lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
GetLoansLoanIdDelinquencySummary delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||||
|
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 March 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("09 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("10 February 2012");
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "10 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("12 March 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(2049.99, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(36, delinquent.getDelinquentDays());
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyWithMultiplePausePeriods() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
|
||||||
|
LocalDate bussinesLocalDate = Utils.getDateAsLocalDate("01 January 2012");
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
|
||||||
|
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());
|
||||||
|
final GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
delinquencyRangeResponse.getResourceId());
|
||||||
|
final String classificationExpected = range.getClassification();
|
||||||
|
log.info("Expected Delinquency Range classification {}", classificationExpected);
|
||||||
|
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 60);
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, jsonBucket);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketResponse.getResourceId());
|
||||||
|
|
||||||
|
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
|
||||||
|
Math.toIntExact(delinquencyBucket.getId()), "3");
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
log.info("Loan Product Arrears: {}", getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final LocalDate transactionDate = bussinesLocalDate;
|
||||||
|
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||||
|
|
||||||
|
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||||
|
getLoanProductsProductResponse.getId().toString(), operationDate, "3");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
final GetDelinquencyRangesResponse firstTestCase = getLoansLoanIdResponse.getDelinquencyRange();
|
||||||
|
log.info("Loan Delinquency Range is null {}", (firstTestCase == null));
|
||||||
|
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||||
|
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final String jobName = "Loan COB";
|
||||||
|
|
||||||
|
// delinqut days: 5
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("06 February 2012");
|
||||||
|
LocalDate lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
GetLoansLoanIdDelinquencySummary delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||||
|
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 March 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("09 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("10 February 2012");
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "10 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("13 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(8, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
pauseDelinquencyResponse = loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "13 February 2012",
|
||||||
|
"18 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("23 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(13, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
pauseDelinquencyResponse = loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "23 February 2012",
|
||||||
|
"28 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("25 February 2012");
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "25 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("12 March 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(2049.99, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(29, delinquent.getDelinquentDays());
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyWithMultiplePausePeriodsWithInstallmentLevelDelinquency() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
|
||||||
|
LocalDate bussinesLocalDate = Utils.getDateAsLocalDate("01 January 2012");
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
|
||||||
|
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());
|
||||||
|
final GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
delinquencyRangeResponse.getResourceId());
|
||||||
|
final String classificationExpected = range.getClassification();
|
||||||
|
log.info("Expected Delinquency Range classification {}", classificationExpected);
|
||||||
|
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 60);
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, jsonBucket);
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketResponse.getResourceId());
|
||||||
|
|
||||||
|
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012");
|
||||||
|
final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithInstallmentLevelDelinquency(
|
||||||
|
loanTransactionHelper, Math.toIntExact(delinquencyBucket.getId()), "3");
|
||||||
|
assertNotNull(getLoanProductsProductResponse);
|
||||||
|
log.info("Loan Product Arrears: {}", getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoanProductsProductResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final LocalDate transactionDate = bussinesLocalDate;
|
||||||
|
String operationDate = Utils.dateFormatter.format(transactionDate);
|
||||||
|
|
||||||
|
final Integer loanId = createLoanAccount(loanTransactionHelper, clientId.toString(),
|
||||||
|
getLoanProductsProductResponse.getId().toString(), operationDate, "3");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
final GetDelinquencyRangesResponse firstTestCase = getLoansLoanIdResponse.getDelinquencyRange();
|
||||||
|
log.info("Loan Delinquency Range is null {}", (firstTestCase == null));
|
||||||
|
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||||
|
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||||
|
|
||||||
|
final String jobName = "Loan COB";
|
||||||
|
|
||||||
|
// delinqut days: 5
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("06 February 2012");
|
||||||
|
LocalDate lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
GetLoansLoanIdDelinquencySummary delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||||
|
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 March 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("09 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(5, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("10 February 2012");
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "10 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("13 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(8, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
pauseDelinquencyResponse = loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "13 February 2012",
|
||||||
|
"18 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("23 February 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||||
|
lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(1033.33, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(13, delinquent.getDelinquentDays());
|
||||||
|
|
||||||
|
pauseDelinquencyResponse = loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "23 February 2012",
|
||||||
|
"28 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("25 February 2012");
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "25 February 2012");
|
||||||
|
|
||||||
|
bussinesLocalDate = Utils.getDateAsLocalDate("14 March 2012");
|
||||||
|
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate.minusDays(1), jobName, responseSpec);
|
||||||
|
log.info("Current date {}", bussinesLocalDate);
|
||||||
|
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||||
|
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||||
|
|
||||||
|
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||||
|
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||||
|
delinquent = getLoansLoanIdResponse.getDelinquent();
|
||||||
|
|
||||||
|
assertEquals(2049.99, delinquent.getDelinquentAmount());
|
||||||
|
assertEquals(LocalDate.of(2012, 2, 1), delinquent.getDelinquentDate());
|
||||||
|
assertEquals(31, delinquent.getDelinquentDays());
|
||||||
|
assertEquals(2, delinquent.getInstallmentLevelDelinquency().size());
|
||||||
|
GetLoansLoanIdLoanInstallmentLevelDelinquency firstInstallmentDelinquent = delinquent.getInstallmentLevelDelinquency().get(0);
|
||||||
|
assertEquals(BigDecimal.valueOf(1016.66), firstInstallmentDelinquent.getDelinquentAmount().stripTrailingZeros());
|
||||||
|
GetLoansLoanIdLoanInstallmentLevelDelinquency secondInstallmentDelinquent = delinquent.getInstallmentLevelDelinquency().get(1);
|
||||||
|
assertEquals(BigDecimal.valueOf(1033.33), secondInstallmentDelinquent.getDelinquentAmount().stripTrailingZeros());
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper,
|
private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper,
|
||||||
final Integer delinquencyBucketId, final String inArrearsTolerance) {
|
final Integer delinquencyBucketId, final String inArrearsTolerance) {
|
||||||
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().withInArrearsTolerance(inArrearsTolerance).build(null,
|
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().withInArrearsTolerance(inArrearsTolerance).build(null,
|
||||||
@@ -1010,6 +1534,15 @@ public class DelinquencyBucketsIntegrationTest {
|
|||||||
return loanTransactionHelper.getLoanProduct(loanProductId);
|
return loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GetLoanProductsProductIdResponse createLoanProductWithInstallmentLevelDelinquency(
|
||||||
|
final LoanTransactionHelper loanTransactionHelper, final Integer delinquencyBucketId, final String inArrearsTolerance) {
|
||||||
|
final HashMap<String, Object> loanProductMap = new LoanProductTestBuilder().withInArrearsTolerance(inArrearsTolerance).build(null,
|
||||||
|
delinquencyBucketId);
|
||||||
|
loanProductMap.put("enableInstallmentLevelDelinquency", true);
|
||||||
|
final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap));
|
||||||
|
return loanTransactionHelper.getLoanProduct(loanProductId);
|
||||||
|
}
|
||||||
|
|
||||||
private PutLoanProductsProductIdResponse updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id,
|
private PutLoanProductsProductIdResponse updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id,
|
||||||
final Integer inArrearsTolerance) {
|
final Integer inArrearsTolerance) {
|
||||||
final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest()
|
final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest()
|
||||||
|
|||||||
Reference in New Issue
Block a user