This is an automated email from the ASF dual-hosted git repository.
taskain pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new cb40f230b [FINERACT-1992] Delinquency calculation with pause
cb40f230b is described below
commit cb40f230b144bbf02c4ce00492cf1da339dc9f07
Author: taskain7 <[email protected]>
AuthorDate: Mon Nov 27 16:33:43 2023 +0100
[FINERACT-1992] Delinquency calculation with pause
---
.../loan/SetLoanDelinquencyTagsBusinessStep.java | 39 +-
.../DelinquencyEffectivePauseHelper.java} | 22 +-
.../DelinquencyEffectivePauseHelperImpl.java | 79 +++
.../service/DelinquencyReadPlatformService.java | 3 +-
.../DelinquencyReadPlatformServiceImpl.java | 56 +--
.../service/DelinquencyWritePlatformService.java | 8 +-
.../DelinquencyWritePlatformServiceImpl.java | 24 +-
.../service/LoanDelinquencyDomainService.java | 7 +-
.../service/LoanDelinquencyDomainServiceImpl.java | 29 +-
.../starter/DelinquencyConfiguration.java | 19 +-
.../DelinquencyActionParseAndValidator.java | 38 +-
.../domain/LoanAccountDomainService.java | 4 +
.../domain/LoanAccountDomainServiceJpa.java | 28 +-
.../SetLoanDelinquencyTagsConfig.java | 8 +-
.../SetLoanDelinquencyTagsTasklet.java | 16 +-
.../SetLoanDelinquencyTagsBusinessStepTest.java | 26 +-
.../DelinquencyEffectivePauseHelperTest.java | 82 ++++
.../DelinquencyReadPlatformServiceImplTest.java | 92 ++--
.../DelinquencyActionParseAndValidatorTest.java | 22 +-
...cyWritePlatformServiceRangeChangeEventTest.java | 35 +-
.../LoanDelinquencyDomainServiceTest.java | 22 +-
.../DelinquencyBucketsIntegrationTest.java | 533 +++++++++++++++++++++
22 files changed, 982 insertions(+), 210 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStep.java
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStep.java
index 979a6e288..c94ad88bd 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStep.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStep.java
@@ -20,13 +20,22 @@ package org.apache.fineract.cob.loan;
import static
org.apache.fineract.infrastructure.core.diagnostics.performance.MeasuringUtil.measure;
+import java.time.LocalDate;
+import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
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.ExternalId;
import org.apache.fineract.infrastructure.core.service.DateUtils;
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.LoanAccountDomainService;
import org.springframework.stereotype.Component;
@@ -37,6 +46,9 @@ import org.springframework.stereotype.Component;
public class SetLoanDelinquencyTagsBusinessStep implements LoanCOBBusinessStep
{
private final LoanAccountDomainService loanAccountDomainService;
+ private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
+ private final DelinquencyReadPlatformService
delinquencyReadPlatformService;
+ private final BusinessEventNotifierService businessEventNotifierService;
@Override
public Loan execute(Loan loan) {
@@ -55,7 +67,17 @@ public class SetLoanDelinquencyTagsBusinessStep implements
LoanCOBBusinessStep {
// the
// current date and not the previous (COB) date.
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) {
log.error(
"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;
}
+ 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
public String getEnumStyledName() {
return "LOAN_DELINQUENCY_CLASSIFICATION";
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainService.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelper.java
similarity index 56%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainService.java
copy to
fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelper.java
index 656ceb6b7..e236d8422 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelper.java
@@ -16,22 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.portfolio.delinquency.service;
+package org.apache.fineract.portfolio.delinquency.helper;
-import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
-import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
-import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+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 LoanDelinquencyDomainService {
+public interface DelinquencyEffectivePauseHelper {
- /**
- * This method is to calculate the Overdue date and other properties, If
the loan is overdue or If there is some
- * Charge back transaction
- *
- * @param loan
- */
- CollectionData getOverdueCollectionData(Loan loan);
-
- LoanDelinquencyData getLoanDelinquencyData(Loan loan);
+ List<LoanDelinquencyActionData>
calculateEffectiveDelinquencyList(List<LoanDelinquencyAction>
savedDelinquencyActions);
+ Long getPausedDaysBeforeDate(List<LoanDelinquencyActionData>
effectiveDelinquencyList, LocalDate date);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelperImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelperImpl.java
new file mode 100644
index 000000000..eeb64bff5
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelperImpl.java
@@ -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();
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformService.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformService.java
index 174cc1283..f54a45d4f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformService.java
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.delinquency.service;
import java.util.Collection;
+import java.util.List;
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
import
org.apache.fineract.portfolio.delinquency.data.LoanDelinquencyTagHistoryData;
@@ -44,6 +45,6 @@ public interface DelinquencyReadPlatformService {
Collection<LoanInstallmentDelinquencyTagData>
retrieveLoanInstallmentsCurrentDelinquencyTag(Long loanId);
- Collection<LoanDelinquencyAction> retrieveLoanDelinquencyActions(Long
loanId);
+ List<LoanDelinquencyAction> retrieveLoanDelinquencyActions(Long loanId);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
index d0192d168..b80b51e89 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java
@@ -18,14 +18,10 @@
*/
package org.apache.fineract.portfolio.delinquency.service;
-import static
org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction.RESUME;
-
import java.time.LocalDate;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.stream.Collector;
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.LoanDelinquencyTagHistoryData;
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.DelinquencyBucketRepository;
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.LoanDelinquencyTagHistoryRepository;
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.DelinquencyRangeMapper;
import
org.apache.fineract.portfolio.delinquency.mapper.LoanDelinquencyTagMapper;
@@ -73,6 +69,7 @@ public class DelinquencyReadPlatformServiceImpl implements
DelinquencyReadPlatfo
private final LoanDelinquencyDomainService loanDelinquencyDomainService;
private final LoanInstallmentDelinquencyTagRepository
repositoryLoanInstallmentDelinquencyTag;
private final LoanDelinquencyActionRepository
loanDelinquencyActionRepository;
+ private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
@Override
public Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
@@ -127,7 +124,11 @@ public class DelinquencyReadPlatformServiceImpl implements
DelinquencyReadPlatfo
if (optLoan.isPresent()) {
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.setNextPaymentDueDate(loan.possibleNextRepaymentDate());
@@ -143,8 +144,7 @@ public class DelinquencyReadPlatformServiceImpl implements
DelinquencyReadPlatfo
collectionData.setLastRepaymentAmount(lastRepaymentTransaction.getAmount());
}
- enrichWithDelinquencyPausePeriodInfo(collectionData,
retrieveLoanDelinquencyActions(loanId),
- ThreadLocalContextUtil.getBusinessDate());
+ enrichWithDelinquencyPausePeriodInfo(collectionData,
effectiveDelinquencyList, ThreadLocalContextUtil.getBusinessDate());
if (optLoan.get().isEnableInstallmentLevelDelinquency()) {
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) {
- // partition them based on type
- Map<DelinquencyAction, List<LoanDelinquencyAction>> partitioned =
delinquencyActions.stream()
-
.collect(Collectors.groupingBy(LoanDelinquencyAction::getAction));
-
- // 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);
- }
+ List<DelinquencyPausePeriod> result =
effectiveDelinquencyList.stream() //
+
.sorted(Comparator.comparing(LoanDelinquencyActionData::getStartDate)) //
+ .map(lda -> toDelinquencyPausePeriod(businessDate,
lda)).toList(); //
+ collectionData.setDelinquencyPausePeriods(result);
}
@NotNull
@@ -219,24 +202,13 @@ public class DelinquencyReadPlatformServiceImpl
implements DelinquencyReadPlatfo
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
public Collection<LoanInstallmentDelinquencyTagData>
retrieveLoanInstallmentsCurrentDelinquencyTag(Long loanId) {
return
repositoryLoanInstallmentDelinquencyTag.findInstallmentDelinquencyTags(loanId);
}
@Override
- public Collection<LoanDelinquencyAction>
retrieveLoanDelinquencyActions(Long loanId) {
+ public List<LoanDelinquencyAction> retrieveLoanDelinquencyActions(Long
loanId) {
final Optional<Loan> optLoan = this.loanRepository.findById(loanId);
if (optLoan.isPresent()) {
return
loanDelinquencyActionRepository.findByLoanOrderById(optLoan.get());
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java
index 9db4b45df..c02222c14 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformService.java
@@ -18,8 +18,10 @@
*/
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.data.CommandProcessingResult;
+import
org.apache.fineract.portfolio.delinquency.validator.LoanDelinquencyActionData;
import
org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -43,9 +45,11 @@ public interface DelinquencyWritePlatformService {
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);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java
index 1ebe04761..c92693d34 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyWritePlatformServiceImpl.java
@@ -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.exception.DelinquencyBucketAgesOverlapedException;
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.DelinquencyBucketParseAndValidator;
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.LoanDelinquencyData;
import
org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
@@ -81,8 +83,10 @@ public class DelinquencyWritePlatformServiceImpl implements
DelinquencyWritePlat
private final BusinessEventNotifierService businessEventNotifierService;
private final LoanDelinquencyDomainService loanDelinquencyDomainService;
private final LoanInstallmentDelinquencyTagRepository
loanInstallmentDelinquencyTagRepository;
+ private final DelinquencyReadPlatformService
delinquencyReadPlatformService;
private final LoanDelinquencyActionRepository
loanDelinquencyActionRepository;
private final DelinquencyActionParseAndValidator
delinquencyActionParseAndValidator;
+ private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
@Override
public CommandProcessingResult createDelinquencyRange(JsonCommand command)
{
@@ -153,12 +157,13 @@ public class DelinquencyWritePlatformServiceImpl
implements DelinquencyWritePlat
}
@Override
- public LoanScheduleDelinquencyData
calculateDelinquencyData(LoanScheduleDelinquencyData
loanScheduleDelinquencyData) {
+ public LoanScheduleDelinquencyData
calculateDelinquencyData(LoanScheduleDelinquencyData
loanScheduleDelinquencyData,
+ List<LoanDelinquencyActionData> effectiveDelinquencyList) {
Loan loan = loanScheduleDelinquencyData.getLoan();
if (loan == null) {
loan =
this.loanRepository.findOneWithNotFoundDetection(loanScheduleDelinquencyData.getLoanId());
}
- final CollectionData collectionData =
loanDelinquencyDomainService.getOverdueCollectionData(loan);
+ final CollectionData collectionData =
loanDelinquencyDomainService.getOverdueCollectionData(loan,
effectiveDelinquencyList);
log.debug("Delinquency {}", collectionData);
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<>();
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();
if (delinquencyBucket != null) {
- final LoanDelinquencyData loanDelinquencyData =
loanDelinquencyDomainService.getLoanDelinquencyData(loan);
+ final LoanDelinquencyData loanDelinquencyData =
loanDelinquencyDomainService.getLoanDelinquencyData(loan,
+ effectiveDelinquencyList);
// loan delinquent data
final CollectionData collectionData =
loanDelinquencyData.getLoanCollectionData();
// loan installments delinquent data
@@ -188,11 +198,13 @@ public class DelinquencyWritePlatformServiceImpl
implements DelinquencyWritePlat
}
@Override
- public void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData
loanDelinquencyData) {
+ public void applyDelinquencyTagToLoan(LoanScheduleDelinquencyData
loanDelinquencyData,
+ List<LoanDelinquencyActionData> effectiveDelinquencyList) {
final Loan loan = loanDelinquencyData.getLoan();
if (loan.hasDelinquencyBucket()) {
final DelinquencyBucket delinquencyBucket =
loan.getLoanProduct().getDelinquencyBucket();
- final LoanDelinquencyData loanDelinquentData =
loanDelinquencyDomainService.getLoanDelinquencyData(loan);
+ final LoanDelinquencyData loanDelinquentData =
loanDelinquencyDomainService.getLoanDelinquencyData(loan,
+ effectiveDelinquencyList);
// loan delinquent data
final CollectionData collectionData =
loanDelinquentData.getLoanCollectionData();
// loan installments delinquent data
@@ -212,7 +224,7 @@ public class DelinquencyWritePlatformServiceImpl implements
DelinquencyWritePlat
public CommandProcessingResult createDelinquencyAction(Long loanId,
JsonCommand command) {
final Loan loan =
this.loanRepository.findOneWithNotFoundDetection(loanId);
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,
savedDelinquencyList, businessDate);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainService.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainService.java
index 656ceb6b7..065eca1a8 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainService.java
@@ -18,6 +18,8 @@
*/
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.LoanDelinquencyData;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -29,9 +31,10 @@ public interface LoanDelinquencyDomainService {
* Charge back transaction
*
* @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);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java
index 67085cd65..8b048e7af 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/LoanDelinquencyDomainServiceImpl.java
@@ -24,9 +24,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.DateUtils;
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.LoanDelinquencyData;
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;
@Slf4j
+@RequiredArgsConstructor
public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainService {
+ private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
+
@Override
@Transactional(readOnly = true)
- public CollectionData getOverdueCollectionData(final Loan loan) {
+ public CollectionData getOverdueCollectionData(final Loan loan,
List<LoanDelinquencyActionData> effectiveDelinquencyList) {
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
final MonetaryCurrency loanCurrency = loan.getCurrency();
@@ -99,7 +105,7 @@ public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainSe
collectionData.setDelinquentDays(0L);
Long delinquentDays = overdueDays - graceDays;
if (delinquentDays > 0) {
- collectionData.setDelinquentDays(delinquentDays);
+ calculateDelinquentDays(effectiveDelinquencyList, businessDate,
collectionData, delinquentDays);
}
log.debug("Result: {}", collectionData.toString());
@@ -107,7 +113,7 @@ public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainSe
}
@Override
- public LoanDelinquencyData getLoanDelinquencyData(final Loan loan) {
+ public LoanDelinquencyData getLoanDelinquencyData(final Loan loan,
List<LoanDelinquencyActionData> effectiveDelinquencyList) {
final LocalDate businessDate = DateUtils.getBusinessLocalDate();
LocalDate overdueSinceDate = null;
@@ -121,7 +127,7 @@ public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainSe
for (LoanRepaymentScheduleInstallment installment :
loan.getRepaymentScheduleInstallments()) {
CollectionData installmentCollectionData =
CollectionData.template();
if (!installment.isObligationsMet()) {
- installmentCollectionData =
getInstallmentOverdueCollectionData(loan, installment);
+ installmentCollectionData =
getInstallmentOverdueCollectionData(loan, installment,
effectiveDelinquencyList);
outstandingAmount =
outstandingAmount.add(installmentCollectionData.getDelinquentAmount());
// Get the oldest overdue installment if exists
if (DateUtils.isBefore(installment.getDueDate(),
businessDate)) {
@@ -165,12 +171,20 @@ public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainSe
collectionData.setDelinquentDays(0L);
Long delinquentDays = overdueDays - graceDays;
if (delinquentDays > 0) {
- collectionData.setDelinquentDays(delinquentDays);
+ calculateDelinquentDays(effectiveDelinquencyList, businessDate,
collectionData, delinquentDays);
}
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();
LocalDate overdueSinceDate = null;
CollectionData collectionData = CollectionData.template();
@@ -193,7 +207,6 @@ public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainSe
Long overdueDays = 0L;
if (overdueSinceDate != null) {
- // TODO : Changes for considering paused delinquency days for
overdue days calculation
overdueDays = DateUtils.getDifferenceInDays(overdueSinceDate,
businessDate);
if (overdueDays < 0) {
overdueDays = 0L;
@@ -205,7 +218,7 @@ public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainSe
collectionData.setDelinquentDays(0L);
Long delinquentDays = overdueDays;
if (delinquentDays > 0) {
- collectionData.setDelinquentDays(delinquentDays);
+ calculateDelinquentDays(effectiveDelinquencyList, businessDate,
collectionData, delinquentDays);
}
return collectionData;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
index 1b78a48c2..734a249af 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java
@@ -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.LoanDelinquencyTagHistoryRepository;
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.DelinquencyRangeMapper;
import
org.apache.fineract.portfolio.delinquency.mapper.LoanDelinquencyTagMapper;
@@ -55,10 +56,11 @@ public class DelinquencyConfiguration {
LoanDelinquencyTagMapper mapperLoanDelinquencyTagHistory,
LoanRepository loanRepository,
LoanDelinquencyDomainService loanDelinquencyDomainService,
LoanInstallmentDelinquencyTagRepository
repositoryLoanInstallmentDelinquencyTag,
- LoanDelinquencyActionRepository loanDelinquencyActionRepository) {
+ LoanDelinquencyActionRepository loanDelinquencyActionRepository,
+ DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper) {
return new DelinquencyReadPlatformServiceImpl(repositoryRange,
repositoryBucket, repositoryLoanDelinquencyTagHistory, mapperRange,
mapperBucket, mapperLoanDelinquencyTagHistory, loanRepository,
loanDelinquencyDomainService,
- repositoryLoanInstallmentDelinquencyTag,
loanDelinquencyActionRepository);
+ repositoryLoanInstallmentDelinquencyTag,
loanDelinquencyActionRepository, delinquencyEffectivePauseHelper);
}
@Bean
@@ -70,17 +72,18 @@ public class DelinquencyConfiguration {
LoanProductRepository loanProductRepository,
BusinessEventNotifierService businessEventNotifierService,
LoanDelinquencyDomainService loanDelinquencyDomainService,
LoanInstallmentDelinquencyTagRepository
loanInstallmentDelinquencyTagRepository,
- LoanDelinquencyActionRepository loanDelinquencyActionRepository,
- DelinquencyActionParseAndValidator
delinquencyActionParseAndValidator) {
+ DelinquencyReadPlatformService delinquencyReadPlatformService,
LoanDelinquencyActionRepository loanDelinquencyActionRepository,
+ DelinquencyActionParseAndValidator
delinquencyActionParseAndValidator,
+ DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper) {
return new DelinquencyWritePlatformServiceImpl(dataValidatorBucket,
dataValidatorRange, repositoryRange, repositoryBucket,
repositoryBucketMappings, loanDelinquencyTagRepository,
loanRepository, loanProductRepository, businessEventNotifierService,
- loanDelinquencyDomainService,
loanInstallmentDelinquencyTagRepository, loanDelinquencyActionRepository,
- delinquencyActionParseAndValidator);
+ loanDelinquencyDomainService,
loanInstallmentDelinquencyTagRepository, delinquencyReadPlatformService,
+ loanDelinquencyActionRepository,
delinquencyActionParseAndValidator, delinquencyEffectivePauseHelper);
}
@Bean
@ConditionalOnMissingBean(LoanDelinquencyDomainService.class)
- public LoanDelinquencyDomainService loanDelinquencyDomainService() {
- return new LoanDelinquencyDomainServiceImpl();
+ public LoanDelinquencyDomainService
loanDelinquencyDomainService(DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper) {
+ return new
LoanDelinquencyDomainServiceImpl(delinquencyEffectivePauseHelper);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java
index 56274956c..41f876353 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidator.java
@@ -18,7 +18,6 @@
*/
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.END_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 jakarta.validation.constraints.NotNull;
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 lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
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.portfolio.delinquency.domain.DelinquencyAction;
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.springframework.stereotype.Component;
@@ -50,10 +46,12 @@ import org.springframework.stereotype.Component;
public class DelinquencyActionParseAndValidator extends ParseAndValidator {
private final FromJsonHelper jsonHelper;
+ private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
public LoanDelinquencyAction validateAndParseUpdate(@NotNull final
JsonCommand command, Loan loan,
List<LoanDelinquencyAction> savedDelinquencyActions, LocalDate
businessDate) {
- List<LoanDelinquencyActionData> effectiveDelinquencyList =
calculateEffectiveDelinquencyList(savedDelinquencyActions);
+ List<LoanDelinquencyActionData> effectiveDelinquencyList =
delinquencyEffectivePauseHelper
+ .calculateEffectiveDelinquencyList(savedDelinquencyActions);
LoanDelinquencyAction parsedDelinquencyAction = parseCommand(command);
validateLoanIsActive(loan);
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,
List<LoanDelinquencyActionData> savedDelinquencyActions) {
boolean match = savedDelinquencyActions.stream()
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
index 976597686..c15be59a6 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
@@ -20,10 +20,12 @@ package org.apache.fineract.portfolio.loanaccount.domain;
import java.math.BigDecimal;
import java.time.LocalDate;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
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.paymentdetail.domain.PaymentDetail;
@@ -72,6 +74,8 @@ public interface LoanAccountDomainService {
*/
void setLoanDelinquencyTag(Loan loan, LocalDate transactionDate);
+ void setLoanDelinquencyTag(Loan loan, LocalDate transactionDate,
List<LoanDelinquencyActionData> effectiveDelinquencyList);
+
LoanTransaction makeRepayment(LoanTransactionType
repaymentTransactionType, Loan loan, LocalDate transactionDate,
BigDecimal transactionAmount, PaymentDetail paymentDetail, String
noteText, ExternalId txnExternalId,
boolean isRecoveryRepayment, String chargeRefundChargeType,
boolean isAccountTransfer, HolidayDetailDTO holidayDetailDto,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
index f54f5186d..f58785762 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
@@ -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.exception.ClientNotActiveException;
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.validator.LoanDelinquencyActionData;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
@@ -135,6 +139,8 @@ public class LoanAccountDomainServiceJpa implements
LoanAccountDomainService {
private final ExternalIdFactory externalIdFactory;
private final ReplayedTransactionBusinessEventService
replayedTransactionBusinessEventService;
private final LoanAccrualTransactionBusinessEventService
loanAccrualTransactionBusinessEventService;
+ private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
+ private final DelinquencyReadPlatformService
delinquencyReadPlatformService;
@Transactional
@Override
@@ -575,12 +581,30 @@ public class LoanAccountDomainServiceJpa implements
LoanAccountDomainService {
@Override
public void setLoanDelinquencyTag(final Loan loan, final LocalDate
transactionDate) {
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(),
loanDelinquencyData.getOverdueDays(),
loanDelinquencyData.getOverdueSinceDate());
// Set or Unset the Delinquency Classification Tag
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 {
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java
index 9d94a2097..f15ead37a 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsConfig.java
@@ -20,6 +20,8 @@ package
org.apache.fineract.portfolio.loanaccount.jobs.setloandelinquencytags;
import lombok.AllArgsConstructor;
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.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
@@ -42,6 +44,10 @@ public class SetLoanDelinquencyTagsConfig {
private JobRepository jobRepository;
@Autowired
private PlatformTransactionManager transactionManager;
+ @Autowired
+ private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
+ @Autowired
+ private DelinquencyReadPlatformService delinquencyReadPlatformService;
private DelinquencyWritePlatformService delinquencyWritePlatformService;
private LoanRepaymentScheduleInstallmentRepository
loanRepaymentScheduleInstallmentRepository;
@@ -62,7 +68,7 @@ public class SetLoanDelinquencyTagsConfig {
@Bean
public SetLoanDelinquencyTagsTasklet setLoanDelinquencyTagsTasklet() {
return new
SetLoanDelinquencyTagsTasklet(delinquencyWritePlatformService,
loanRepaymentScheduleInstallmentRepository,
- loanTransactionRepository);
+ loanTransactionRepository, delinquencyEffectivePauseHelper,
delinquencyReadPlatformService);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java
index 3ce55809d..292be13c1 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/setloandelinquencytags/SetLoanDelinquencyTagsTasklet.java
@@ -27,7 +27,11 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.service.DateUtils;
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.validator.LoanDelinquencyActionData;
import
org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
@@ -45,6 +49,8 @@ public class SetLoanDelinquencyTagsTasklet implements Tasklet
{
private final DelinquencyWritePlatformService
delinquencyWritePlatformService;
private final LoanRepaymentScheduleInstallmentRepository
loanRepaymentScheduleInstallmentRepository;
private final LoanTransactionRepository loanTransactionRepository;
+ private final DelinquencyEffectivePauseHelper
delinquencyEffectivePauseHelper;
+ private final DelinquencyReadPlatformService
delinquencyReadPlatformService;
@Override
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());
for (LoanScheduleDelinquencyData loanDelinquencyData :
loanScheduleDelinquencyData) {
// 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(),
loanDelinquencyData.getOverdueDays(),
loanDelinquencyData.getOverdueSinceDate());
// Set or Unset the Delinquency Classification Tag
if (loanDelinquencyData.getOverdueDays() > 0) {
-
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData);
+
this.delinquencyWritePlatformService.applyDelinquencyTagToLoan(loanDelinquencyData,
effectiveDelinquencyList);
} else {
this.delinquencyWritePlatformService.removeDelinquencyTagToLoan(loanDelinquencyData.getLoan());
}
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java
b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java
index 555b0bc42..bdb22dd65 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/SetLoanDelinquencyTagsBusinessStepTest.java
@@ -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.assertThrows;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
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.FineractPlatformTenant;
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.LoanAccountDomainService;
import org.junit.jupiter.api.BeforeEach;
@@ -61,6 +65,12 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
*/
@Mock
private LoanAccountDomainService loanAccountDomainService;
+ @Mock
+ private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
+ @Mock
+ private DelinquencyReadPlatformService delinquencyReadPlatformService;
+ @Mock
+ private BusinessEventNotifierService businessEventNotifierService;
/**
* The class under test.
@@ -84,9 +94,10 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
public void setUp() {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L,
"default", "Default", "Asia/Kolkata", null));
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
- ThreadLocalContextUtil
- .setBusinessDates(new
HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE,
LocalDate.now(ZoneId.systemDefault()))));
- underTest = new
SetLoanDelinquencyTagsBusinessStep(loanAccountDomainService);
+ ThreadLocalContextUtil.setBusinessDates(new
HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE,
LocalDate.now(ZoneId.systemDefault()),
+ BusinessDateType.COB_DATE,
LocalDate.now(ZoneId.systemDefault()))));
+ underTest = new
SetLoanDelinquencyTagsBusinessStep(loanAccountDomainService,
delinquencyEffectivePauseHelper,
+ delinquencyReadPlatformService, businessEventNotifierService);
}
/**
@@ -98,14 +109,14 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
@Test
public void testExecuteSuccessScenario() throws Exception {
// 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();
// when
Loan processedLoan = underTest.execute(loanForProcessing);
// then
-
verify(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class),
any(LocalDate.class));
+
verify(loanAccountDomainService).setLoanDelinquencyTag(any(Loan.class),
any(LocalDate.class), anyList());
assertEquals(processedLoan, loanForProcessing);
}
@@ -137,14 +148,15 @@ public class SetLoanDelinquencyTagsBusinessStepTest {
@Test
public void testExecuteWhenSetLoanDelinquencyTagFails() throws Exception {
// 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();
// when
final Throwable thrownException = assertThrows(RuntimeException.class,
() -> underTest.execute(loanForProcessing));
// 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));
}
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelperTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelperTest.java
new file mode 100644
index 000000000..e6f7f07e8
--- /dev/null
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/helper/DelinquencyEffectivePauseHelperTest.java
@@ -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));
+ }
+
+}
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImplTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImplTest.java
index ea6a186df..dd8d3c01c 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImplTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImplTest.java
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.delinquency.service;
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 java.time.LocalDate;
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.DelinquencyRangeMapper;
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.DelinquencyPausePeriod;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
@@ -82,22 +82,25 @@ class DelinquencyReadPlatformServiceImplTest {
public void testNoEnrichmentWhenThereIsNoDelinquencyAction() {
// given
CollectionData collectionData = CollectionData.template();
- Collection<LoanDelinquencyAction> delinquencyActions = List.of();
+ Collection<LoanDelinquencyActionData> delinquencyActions = List.of();
// when
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData,
delinquencyActions, LocalDate.of(2023, JANUARY, 12));
- Assertions.assertNull(collectionData.getDelinquencyPausePeriods());
+
Assertions.assertTrue(collectionData.getDelinquencyPausePeriods().isEmpty());
}
@Test
public void
testMultiplePausesWithoutResumeActionCurrentlyInPauseFirstDay() {
// given
CollectionData collectionData = CollectionData.template();
- Collection<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)));
+ Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
+ new LoanDelinquencyActionData(
+ 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 LoanDelinquencyActionData(
+ new LoanDelinquencyAction(null, PAUSE,
LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
// when
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData,
delinquencyActions, LocalDate.of(2023, JANUARY, 12));
@@ -114,10 +117,13 @@ class DelinquencyReadPlatformServiceImplTest {
public void testMultiplePausesWithoutResumeActionCurrentlyInPauseLastDay()
{
// given
CollectionData collectionData = CollectionData.template();
- Collection<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)));
+ Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
+ new LoanDelinquencyActionData(
+ 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 LoanDelinquencyActionData(
+ new LoanDelinquencyAction(null, PAUSE,
LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
// when
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData,
delinquencyActions, LocalDate.of(2023, JANUARY, 13));
@@ -133,10 +139,13 @@ class DelinquencyReadPlatformServiceImplTest {
public void
testMultiplePausesWithoutResumeActionCurrentBusinessDateBetweenStartAndEndDate()
{
// given
CollectionData collectionData = CollectionData.template();
- Collection<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, 14)),
- new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023,
JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
+ Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
+ new LoanDelinquencyActionData(
+ 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 LoanDelinquencyActionData(
+ new LoanDelinquencyAction(null, PAUSE,
LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
// when
underTest.enrichWithDelinquencyPausePeriodInfo(collectionData,
delinquencyActions, LocalDate.of(2023, JANUARY, 13));
@@ -152,10 +161,13 @@ class DelinquencyReadPlatformServiceImplTest {
public void
testMultiplePausesWithoutResumeCurrentBusinessDateIsNotOverlappingWithAnyOfThePauses()
{
// given
CollectionData collectionData = CollectionData.template();
- Collection<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, 13), LocalDate.of(2023, JANUARY, 14)),
- new LoanDelinquencyAction(null, PAUSE, LocalDate.of(2023,
JANUARY, 15), LocalDate.of(2023, JANUARY, 20)));
+ Collection<LoanDelinquencyActionData> delinquencyActions = List.of(
+ new LoanDelinquencyActionData(
+ 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 LoanDelinquencyActionData(
+ new LoanDelinquencyAction(null, PAUSE,
LocalDate.of(2023, JANUARY, 15), LocalDate.of(2023, JANUARY, 20))));
// when
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) {
if (pausePeriods.length > 0) {
Assertions.assertEquals(Arrays.asList(pausePeriods),
collectionData.getDelinquencyPausePeriods());
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java
index 34011234a..ceb4475dd 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/delinquency/validator/DelinquencyActionParseAndValidatorTest.java
@@ -42,6 +42,7 @@ import
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
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.LoanStatus;
import org.jetbrains.annotations.NotNull;
@@ -54,7 +55,9 @@ import org.mockito.Mockito;
class DelinquencyActionParseAndValidatorTest {
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);
@Test
@@ -77,9 +80,12 @@ class DelinquencyActionParseAndValidatorTest {
Mockito.when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
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,
- List.of(loanDelinquencyAction(PAUSE, "05 September 2022", "15
September 2022")), localDate("09 September 2022"));
+ LoanDelinquencyAction parsedDelinquencyAction =
underTest.validateAndParseUpdate(command, loan, existing,
+ localDate("09 September 2022"));
Assertions.assertEquals(RESUME, parsedDelinquencyAction.getAction());
Assertions.assertEquals(localDate("09 September 2022"),
parsedDelinquencyAction.getStartDate());
Assertions.assertNull(parsedDelinquencyAction.getEndDate());
@@ -92,6 +98,8 @@ class DelinquencyActionParseAndValidatorTest {
List<LoanDelinquencyAction> existing =
List.of(loanDelinquencyAction(PAUSE, "14 September 2022", "22 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",
"loan-delinquency-action-overlapping",
@@ -105,6 +113,8 @@ class DelinquencyActionParseAndValidatorTest {
List<LoanDelinquencyAction> existing =
List.of(loanDelinquencyAction(PAUSE, "14 September 2022", "22 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",
"loan-delinquency-action-overlapping",
@@ -118,6 +128,8 @@ class DelinquencyActionParseAndValidatorTest {
List<LoanDelinquencyAction> existing =
List.of(loanDelinquencyAction(PAUSE, "15 September 2022", "22 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",
"loan-delinquency-action-overlapping",
@@ -339,6 +351,10 @@ class DelinquencyActionParseAndValidatorTest {
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) {
return new LoanDelinquencyAction(null, action, localDate(startTime),
null);
}
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
index e40c8d541..63663d77f 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
@@ -31,6 +31,7 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
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.validator.DelinquencyBucketParseAndValidator;
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.LoanDelinquencyData;
import
org.apache.fineract.portfolio.loanaccount.data.LoanScheduleDelinquencyData;
@@ -115,6 +117,7 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent>
loanDeliquencyRangeChangeEvent = ArgumentCaptor
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
Loan loanForProcessing = Mockito.mock(Loan.class);
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
@@ -140,10 +143,11 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(true);
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(false);
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(),
any())).thenReturn(Optional.empty());
-
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing)).thenReturn(loanDelinquencyData);
+
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing,
effectiveDelinquencyList))
+ .thenReturn(loanDelinquencyData);
// when
- underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
+ underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData,
effectiveDelinquencyList);
// then
verify(loanDelinquencyTagRepository,
times(1)).saveAllAndFlush(anyIterable());
@@ -155,6 +159,7 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
@Test
public void
givenLoanAccountWithDelinquencyBucketWhenNoRangeChangeThenNoEventIsRaised() {
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
Loan loanForProcessing = Mockito.mock(Loan.class);
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
@@ -181,10 +186,11 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
when(loanProduct.getDelinquencyBucket()).thenReturn(delinquencyBucket);
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(true);
when(loanDelinquencyTagRepository.findByLoanAndLiftedOnDate(any(),
any())).thenReturn(Optional.empty());
-
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing)).thenReturn(loanDelinquencyData);
+
when(loanDelinquencyDomainService.getLoanDelinquencyData(loanForProcessing,
effectiveDelinquencyList))
+ .thenReturn(loanDelinquencyData);
// when
- underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
+ underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData,
effectiveDelinquencyList);
// then
verify(loanDelinquencyTagRepository,
times(0)).saveAllAndFlush(anyIterable());
@@ -194,6 +200,7 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
@Test
public void givenLoanAccountWithNoDelinquencyBucketThenNoEventIsRaised() {
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
Loan loanForProcessing = Mockito.mock(Loan.class);
LocalDate overDueSinceDate = DateUtils.getBusinessLocalDate();
@@ -203,7 +210,7 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
when(loanForProcessing.hasDelinquencyBucket()).thenReturn(false);
// when
- underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
+ underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData,
effectiveDelinquencyList);
// then
verify(loanDelinquencyTagRepository,
times(0)).saveAllAndFlush(anyIterable());
@@ -218,6 +225,7 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent>
loanDelinquencyRangeChangeEvent = ArgumentCaptor
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
Loan loanForProcessing = Mockito.mock(Loan.class);
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
@@ -260,12 +268,13 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
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)))
.thenReturn(Optional.empty());
// when
- underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
+ underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData,
effectiveDelinquencyList);
// then
verify(loanDelinquencyTagRepository,
times(1)).saveAllAndFlush(anyIterable());
@@ -293,6 +302,7 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent>
loanDelinquencyRangeChangeEvent = ArgumentCaptor
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
Loan loanForProcessing = Mockito.mock(Loan.class);
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
DelinquencyRange range1 = DelinquencyRange.instance("Range1", 1, 2);
@@ -338,12 +348,13 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
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)))
.thenReturn(Optional.of(previousInstallmentTag));
// when
- underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
+ underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData,
effectiveDelinquencyList);
// then
verify(loanDelinquencyTagRepository,
times(1)).saveAllAndFlush(anyIterable());
@@ -374,6 +385,7 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
ArgumentCaptor<LoanDelinquencyRangeChangeBusinessEvent>
loanDelinquencyRangeChangeEvent = ArgumentCaptor
.forClass(LoanDelinquencyRangeChangeBusinessEvent.class);
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
// given
Loan loanForProcessing = Mockito.mock(Loan.class);
LoanProduct loanProduct = Mockito.mock(LoanProduct.class);
@@ -431,14 +443,15 @@ public class
DelinquencyWritePlatformServiceRangeChangeEventTest {
when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
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)))
.thenReturn(Optional.of(previousInstallmentTag_1));
when(loanInstallmentDelinquencyTagRepository.findByLoanAndInstallment(loanForProcessing,
repaymentScheduleInstallments.get(1)))
.thenReturn(Optional.of(previousInstallmentTag));
// when
- underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData);
+ underTest.applyDelinquencyTagToLoan(loanScheduleDelinquencyData,
effectiveDelinquencyList);
// then
verify(loanDelinquencyTagRepository,
times(1)).saveAllAndFlush(anyIterable());
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java
index 047f7a08d..1e2b5d27b 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/LoanDelinquencyDomainServiceTest.java
@@ -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.Money;
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.validator.LoanDelinquencyActionData;
import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
import org.apache.fineract.portfolio.loanaccount.data.LoanDelinquencyData;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
@@ -75,6 +77,8 @@ public class LoanDelinquencyDomainServiceTest {
private Loan loan;
@Mock
private LoanProduct loanProduct;
+ @Mock
+ private DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper;
@InjectMocks
private LoanDelinquencyDomainServiceImpl underTest;
@@ -107,6 +111,7 @@ public class LoanDelinquencyDomainServiceTest {
@Test
public void givenLoanAccountWithoutOverdueThenCalculateDelinquentData() {
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
final LocalDate fromDate = businessDate.minusMonths(1);
final LocalDate dueDate = businessDate;
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments =
Arrays.asList(new LoanRepaymentScheduleInstallment(loan, 1,
@@ -118,7 +123,7 @@ public class LoanDelinquencyDomainServiceTest {
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loan.getCurrency()).thenReturn(currency);
- CollectionData collectionData =
underTest.getOverdueCollectionData(loan);
+ CollectionData collectionData =
underTest.getOverdueCollectionData(loan, effectiveDelinquencyList);
// then
assertEquals(0L, collectionData.getDelinquentDays());
@@ -130,6 +135,7 @@ public class LoanDelinquencyDomainServiceTest {
@Test
public void givenLoanAccountWithOverdueThenCalculateDelinquentData() {
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
final Long daysDiff = 2L;
final LocalDate fromDate =
businessDate.minusMonths(1).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.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
when(loan.getCurrency()).thenReturn(currency);
+
when(delinquencyEffectivePauseHelper.getPausedDaysBeforeDate(effectiveDelinquencyList,
businessDate)).thenReturn(0L);
- CollectionData collectionData =
underTest.getOverdueCollectionData(loan);
+ CollectionData collectionData =
underTest.getOverdueCollectionData(loan, effectiveDelinquencyList);
// then
assertEquals(daysDiff, collectionData.getDelinquentDays());
@@ -156,6 +163,7 @@ public class LoanDelinquencyDomainServiceTest {
@Test
public void
givenLoanAccountWithoutOverdueWithChargebackThenCalculateDelinquentData() {
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
PaymentDetail paymentDetail = Mockito.mock(PaymentDetail.class);
Long daysDiff = 2L;
final LocalDate fromDate =
businessDate.minusMonths(1).plusDays(daysDiff);
@@ -178,7 +186,7 @@ public class LoanDelinquencyDomainServiceTest {
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loan.getCurrency()).thenReturn(currency);
- CollectionData collectionData =
underTest.getOverdueCollectionData(loan);
+ CollectionData collectionData =
underTest.getOverdueCollectionData(loan, effectiveDelinquencyList);
// then
assertEquals(0L, collectionData.getDelinquentDays());
@@ -190,6 +198,7 @@ public class LoanDelinquencyDomainServiceTest {
@Test
public void
givenLoanInstallmentWithOverdueEnableInstallmentDelinquencyThenCalculateDelinquentData()
{
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
final Long daysDiff = 2L;
final LocalDate fromDate =
businessDate.minusMonths(1).minusDays(daysDiff);
final LocalDate dueDate = businessDate.minusDays(daysDiff);
@@ -207,8 +216,9 @@ public class LoanDelinquencyDomainServiceTest {
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
when(loan.getCurrency()).thenReturn(currency);
when(loan.isEnableInstallmentLevelDelinquency()).thenReturn(true);
+
when(delinquencyEffectivePauseHelper.getPausedDaysBeforeDate(effectiveDelinquencyList,
businessDate)).thenReturn(0L);
- LoanDelinquencyData collectionData =
underTest.getLoanDelinquencyData(loan);
+ LoanDelinquencyData collectionData =
underTest.getLoanDelinquencyData(loan, effectiveDelinquencyList);
// then
assertNotNull(collectionData);
@@ -232,6 +242,7 @@ public class LoanDelinquencyDomainServiceTest {
public void
givenLoanInstallmentWithoutOverdueWithChargebackAndEnableInstallmentDelinquencyThenCalculateDelinquentData()
{
// given
+ final List<LoanDelinquencyActionData> effectiveDelinquencyList =
Collections.emptyList();
PaymentDetail paymentDetail = Mockito.mock(PaymentDetail.class);
Long daysDiff = 2L;
final LocalDate fromDate =
businessDate.minusMonths(1).plusDays(daysDiff);
@@ -255,8 +266,9 @@ public class LoanDelinquencyDomainServiceTest {
when(loan.isEnableInstallmentLevelDelinquency()).thenReturn(true);
when(loan.getCurrency()).thenReturn(currency);
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
assertNotNull(collectionData);
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java
index eb5395d2f..d7ccbf91f 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java
@@ -18,6 +18,8 @@
*/
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.assertNotEquals;
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.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
+import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
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.GetLoanProductsProductIdResponse;
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.GetLoansLoanIdRepaymentSchedule;
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
import org.apache.fineract.client.models.PostDelinquencyBucketResponse;
import org.apache.fineract.client.models.PostDelinquencyRangeResponse;
+import org.apache.fineract.client.models.PostLoansDelinquencyActionResponse;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
import org.apache.fineract.client.models.PutDelinquencyBucketResponse;
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,
final Integer delinquencyBucketId, final String
inArrearsTolerance) {
final HashMap<String, Object> loanProductMap = new
LoanProductTestBuilder().withInArrearsTolerance(inArrearsTolerance).build(null,
@@ -1010,6 +1534,15 @@ public class DelinquencyBucketsIntegrationTest {
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,
final Integer inArrearsTolerance) {
final PutLoanProductsProductIdRequest requestModifyLoan = new
PutLoanProductsProductIdRequest()