This is an automated email from the ASF dual-hosted git repository.
adamsaghy 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 b1af8a3f8 FINERACT-1724: Arrears configuration at loan creation is not
considered correctly
b1af8a3f8 is described below
commit b1af8a3f833503b65ebf42717b0d69de9c0e2891
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Thu Jun 1 01:50:50 2023 -0600
FINERACT-1724: Arrears configuration at loan creation is not considered
correctly
---
.../service/LoanDelinquencyDomainServiceImpl.java | 7 +-
.../loanaccount/api/LoansApiResourceSwagger.java | 2 +
.../api/LoanProductsApiResourceSwagger.java | 2 +
.../LoanDelinquencyDomainServiceTest.java | 9 +-
.../DelinquencyBucketsIntegrationTest.java | 115 +++++++++++++++++++--
5 files changed, 116 insertions(+), 19 deletions(-)
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 90e036f82..13507cf59 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
@@ -120,11 +120,8 @@ public class LoanDelinquencyDomainServiceImpl implements
LoanDelinquencyDomainSe
}
Integer graceDays = 0;
- if
(loan.getLoanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing()
!= null) {
- graceDays =
loan.getLoanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
- if (graceDays == null) {
- graceDays = 0;
- }
+ if (loan.getLoanProductRelatedDetail().getGraceOnArrearsAgeing() !=
null) {
+ graceDays =
loan.getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
}
log.debug("Loan id {} with overdue since date {} and outstanding
amount {}", loan.getId(), overdueSinceDate, outstandingAmount);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
index 96bf96f27..2c636e45f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
@@ -1072,6 +1072,8 @@ final class LoansApiResourceSwagger {
public LocalDate overpaidOnDate;
@Schema(example = "false")
public Boolean chargedOff;
+ @Schema(example = "3")
+ public Integer inArrearsTolerance;
}
@Schema(description = "GetLoansResponse")
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
index 1f2afab08..2626ac977 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java
@@ -1199,6 +1199,8 @@ final class LoanProductsApiResourceSwagger {
public Integer dueDaysForRepaymentEvent;
@Schema(example = "3")
public Integer overDueDaysForRepaymentEvent;
+ @Schema(example = "3")
+ public Integer inArrearsTolerance;
}
@Schema(description = "PutLoanProductsProductIdRequest")
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 054021e56..c75580724 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
@@ -112,8 +112,7 @@ public class LoanDelinquencyDomainServiceTest {
// when
when(loanProductRelatedDetail.getGraceOnArrearsAgeing()).thenReturn(0);
-
when(loanProduct.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
- when(loan.getLoanProduct()).thenReturn(loanProduct);
+
when(loan.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loan.getCurrency()).thenReturn(currency);
@@ -137,8 +136,7 @@ public class LoanDelinquencyDomainServiceTest {
// when
when(loanProductRelatedDetail.getGraceOnArrearsAgeing()).thenReturn(0);
-
when(loanProduct.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
- when(loan.getLoanProduct()).thenReturn(loanProduct);
+
when(loan.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loan.getLoanTransactions(Mockito.any(Predicate.class))).thenReturn(Collections.emptyList());
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
@@ -174,8 +172,7 @@ public class LoanDelinquencyDomainServiceTest {
// when
when(loanProductRelatedDetail.getGraceOnArrearsAgeing()).thenReturn(0);
-
when(loanProduct.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
- when(loan.getLoanProduct()).thenReturn(loanProduct);
+
when(loan.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loan.getCurrency()).thenReturn(currency);
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 252c7ec64..dcac50af7 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
@@ -50,6 +50,8 @@ import
org.apache.fineract.client.models.PostDelinquencyRangeResponse;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
import org.apache.fineract.client.models.PutDelinquencyBucketResponse;
import org.apache.fineract.client.models.PutDelinquencyRangeResponse;
+import org.apache.fineract.client.models.PutLoanProductsProductIdRequest;
+import org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
import org.apache.fineract.cob.data.JobBusinessStepConfigData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
@@ -294,7 +296,7 @@ public class DelinquencyBucketsIntegrationTest {
// Create Loan Account
final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
- getLoanProductsProductResponse.getId().toString(),
operationDate);
+ getLoanProductsProductResponse.getId().toString(),
operationDate, null);
GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
assertNotNull(getLoansLoanIdResponse);
@@ -390,7 +392,7 @@ public class DelinquencyBucketsIntegrationTest {
// Create Loan Account
final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
- getLoanProductsProductResponse.getId().toString(),
operationDate);
+ getLoanProductsProductResponse.getId().toString(),
operationDate, null);
GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
log.info("Loan Delinquency Range after Disbursement {}",
getLoansLoanIdResponse.getDelinquencyRange().getClassification());
@@ -488,7 +490,7 @@ public class DelinquencyBucketsIntegrationTest {
// Create Loan Account
final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
- getLoanProductsProductResponse.getId().toString(),
operationDate);
+ getLoanProductsProductResponse.getId().toString(),
operationDate, null);
GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
assertNotNull(getLoansLoanIdResponse);
@@ -583,7 +585,7 @@ public class DelinquencyBucketsIntegrationTest {
// Create Loan Account
final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
- getLoanProductsProductResponse.getId().toString(),
operationDate);
+ getLoanProductsProductResponse.getId().toString(),
operationDate, null);
GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
@@ -689,7 +691,7 @@ public class DelinquencyBucketsIntegrationTest {
// Create Loan Account
final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
- getLoanProductsProductResponse.getId().toString(),
operationDate);
+ getLoanProductsProductResponse.getId().toString(),
operationDate, null);
// Run first time the Job
final String jobName = "Loan Delinquency Classification";
@@ -777,7 +779,7 @@ public class DelinquencyBucketsIntegrationTest {
// Create Loan Account
final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
- getLoanProductsProductResponse.getId().toString(),
operationDate);
+ getLoanProductsProductResponse.getId().toString(),
operationDate, null);
// COB Step Validation
final JobBusinessStepConfigData jobBusinessStepConfigData =
BusinessStepConfigurationHelper
@@ -879,7 +881,7 @@ public class DelinquencyBucketsIntegrationTest {
// Create Loan Account
final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
- getLoanProductsProductResponse.getId().toString(),
operationDate);
+ getLoanProductsProductResponse.getId().toString(),
operationDate, null);
// Get loan details expecting to have a delinquency classification
GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
@@ -911,6 +913,95 @@ public class DelinquencyBucketsIntegrationTest {
}
}
+ @Test
+ public void testLoanClassificationUsingAgeingArrears() {
+ 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);
+
+ // Given
+ 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());
+
+ // Client and Loan account creation
+ final Integer clientId =
ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January
2012");
+ final GetLoanProductsProductIdResponse
getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper,
+ delinquencyBucket.getId(), "3");
+ assertNotNull(getLoanProductsProductResponse);
+ log.info("Loan Product Arrears: {}",
getLoanProductsProductResponse.getInArrearsTolerance());
+ assertEquals(3,
getLoanProductsProductResponse.getInArrearsTolerance());
+
+ // Older date to have more than one overdue installment
+ final LocalDate transactionDate = bussinesLocalDate;
+ String operationDate = Utils.dateFormatter.format(transactionDate);
+
+ // Create Loan Account
+ final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
+ getLoanProductsProductResponse.getId().toString(),
operationDate, "3");
+
+ // Get loan details expecting to have a delinquency classification
+ 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());
+
+ // Update the Loan Product
+ updateLoanProduct(loanTransactionHelper,
getLoanProductsProductResponse.getId(), 0);
+ GetLoanProductsProductIdResponse loanProductsProductIdResponseUpd
= loanTransactionHelper
+
.getLoanProduct(getLoanProductsProductResponse.getId().intValue());
+ assertNotNull(loanProductsProductIdResponseUpd);
+ log.info("Loan Product Arrears: {}",
loanProductsProductIdResponseUpd.getInArrearsTolerance());
+ assertEquals(0,
loanProductsProductIdResponseUpd.getInArrearsTolerance());
+
+ final String jobName = "Loan COB";
+
+ bussinesLocalDate = Utils.getDateAsLocalDate("31 January 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);
+ // Run Second time the Job
+ schedulerJobHelper.executeAndAwaitJob(jobName);
+
+ // Get loan details expecting to have a delinquency classification
+ getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+ loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
+
+ GetLoansLoanIdCollectionData getLoansLoanIdCollectionData =
getLoansLoanIdResponse.getDelinquent();
+ assertNotNull(getLoansLoanIdCollectionData);
+ assertEquals(0, getLoansLoanIdCollectionData.getDelinquentDays());
+ assertEquals(0, getLoansLoanIdCollectionData.getPastDueDays());
+
+ } 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,
@@ -919,8 +1010,15 @@ public class DelinquencyBucketsIntegrationTest {
return loanTransactionHelper.getLoanProduct(loanProductId);
}
+ private PutLoanProductsProductIdResponse
updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id,
+ final Integer inArrearsTolerance) {
+ final PutLoanProductsProductIdRequest requestModifyLoan = new
PutLoanProductsProductIdRequest()
+ .inArrearsTolerance(inArrearsTolerance);
+ return loanTransactionHelper.updateLoanProduct(id, requestModifyLoan);
+ }
+
private Integer createLoanAccount(final LoanTransactionHelper
loanTransactionHelper, final String clientId, final String loanProductId,
- final String operationDate) {
+ final String operationDate, final String inArrearsTolerance) {
final String loanApplicationJSON = new
LoanApplicationTestBuilder().withPrincipal(principalAmount).withLoanTermFrequency("12")
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("12").withRepaymentEveryAfter("1")
.withRepaymentFrequencyTypeAsMonths() //
@@ -928,6 +1026,7 @@ public class DelinquencyBucketsIntegrationTest {
.withExpectedDisbursementDate(operationDate) //
.withInterestTypeAsDecliningBalance() //
.withSubmittedOnDate(operationDate) //
+ .withInArrearsTolerance(inArrearsTolerance) //
.build(clientId, loanProductId, null);
final Integer loanId =
loanTransactionHelper.getLoanId(loanApplicationJSON);
loanTransactionHelper.approveLoan(operationDate, principalAmount,
loanId, null);