This is an automated email from the ASF dual-hosted git repository.
arnold 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 33d781f5f Loan Delinquency Tags with Loan charges
33d781f5f is described below
commit 33d781f5fb8ff5a0db5df91cac44f2998a341b84
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Mon Sep 12 00:23:43 2022 -0500
Loan Delinquency Tags with Loan charges
---
.../data/LoanRescheduleRequestDataValidator.java | 8 +-
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 9 +-
.../DelinquencyBucketsIntegrationTest.java | 101 +++++++++++++++++++++
3 files changed, 106 insertions(+), 12 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
index 67d7b8ae6..cb20dde73 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
@@ -30,6 +30,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -42,10 +43,10 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import
org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
import
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
+@AllArgsConstructor
public class LoanRescheduleRequestDataValidator {
private final FromJsonHelper fromJsonHelper;
@@ -68,11 +69,6 @@ public class LoanRescheduleRequestDataValidator {
Arrays.asList(RescheduleLoansApiConstants.localeParamName,
RescheduleLoansApiConstants.dateFormatParamName,
RescheduleLoansApiConstants.approvedOnDateParam));
- @Autowired
- public LoanRescheduleRequestDataValidator(FromJsonHelper fromJsonHelper) {
- this.fromJsonHelper = fromJsonHelper;
- }
-
/**
* Validates the request to create a new loan reschedule entry
*
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 3ecadc238..4ed29ed93 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -1253,7 +1253,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
changes.put("transactionDate",
command.stringValueOfParameterNamed("transactionDate"));
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
- final LocalDate transactionDate =
command.localDateValueOfParameterNamed("transactionDate");
final Loan loan = this.loanAssembler.assembleFrom(loanId);
if (command.hasParameter("writeoffReasonId")) {
Long writeoffReasonId =
command.longValueOfParameterNamed("writeoffReasonId");
@@ -1322,7 +1321,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
changes.put("transactionDate",
command.stringValueOfParameterNamed("transactionDate"));
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
- final LocalDate transactionDate =
command.localDateValueOfParameterNamed("transactionDate");
final List<Long> existingTransactionIds = new ArrayList<>();
final List<Long> existingReversedTransactionIds = new ArrayList<>();
@@ -1557,6 +1555,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
&& loan.isFeeCompoundingEnabledForInterestRecalculation()) {
this.loanAccountDomainService.recalculateAccruals(loan);
}
+ this.loanAccountDomainService.setLoanDelinquencyTag(loan,
DateUtils.getBusinessLocalDate());
+
businessEventNotifierService.notifyPostBusinessEvent(new
LoanAddChargeBusinessEvent(loanCharge));
return new
CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(loanCharge.getId())
.withOfficeId(loan.getOfficeId()).withClientId(loan.getClientId()).withGroupId(loan.getGroupId()).withLoanId(loanId)
@@ -1588,7 +1588,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
throw new
PlatformApiDataValidationException(dataValidationErrors);
}
}
-
}
public void runScheduleRecalculation(final Loan loan, final LocalDate
recalculateFrom) {
@@ -1606,7 +1605,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(),
mapEntry.getValue());
}
}
-
}
}
@@ -1616,7 +1614,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
ScheduleGeneratorDTO scheduleGeneratorDTO =
this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
createLoanScheduleArchive(loan, scheduleGeneratorDTO);
}
-
}
private boolean addCharge(final Loan loan, final Charge chargeDefinition,
final LoanCharge loanCharge) {
@@ -1733,7 +1730,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
businessEventNotifierService.notifyPostBusinessEvent(new
LoanBalanceChangedBusinessEvent(newChargeRefundTxn.getLoan()));
businessEventNotifierService.notifyPostBusinessEvent(new
LoanChargeRefundBusinessEvent(newChargeRefundTxn));
return result;
-
}
private JsonCommand
adaptLoanChargeRefundCommandForFurtherRepaymentProcessing(JsonCommand command,
BigDecimal fullRefundAbleAmount) {
@@ -2076,6 +2072,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl
implements LoanWritePlatf
saveLoanWithDataIntegrityViolationChecks(loan);
postJournalEntries(loan, existingTransactionIds,
existingReversedTransactionIds);
+ this.loanAccountDomainService.setLoanDelinquencyTag(loan,
DateUtils.getBusinessLocalDate());
businessEventNotifierService.notifyPostBusinessEvent(new
LoanWaiveChargeBusinessEvent(loanCharge));
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 1efd1d9af..ab5c8e10d 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
@@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import com.google.gson.Gson;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
@@ -52,9 +53,11 @@ import
org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
import
org.apache.fineract.integrationtests.common.BusinessStepConfigurationHelper;
import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.CommonConstants;
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
import
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
import
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
@@ -507,6 +510,92 @@ public class DelinquencyBucketsIntegrationTest {
log.info("Delinquency Tag Item with Lifted On {}",
getDelinquencyTagsHistory.get(0).getLiftedOnDate());
}
+ @Test
+ public void testLoanClassificationRealtimeWithCharges() {
+ // Given
+ final LoanTransactionHelper loanTransactionHelper = new
LoanTransactionHelper(this.requestSpec, this.responseSpec);
+
+ ArrayList<Integer> rangeIds = new ArrayList<>();
+ // First Range
+ String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
+ PostDelinquencyRangeResponse delinquencyRangeResponse =
DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
+ jsonRange);
+ rangeIds.add(delinquencyRangeResponse.getResourceId());
+ jsonRange = DelinquencyRangesHelper.getAsJSON(4, 60);
+
+ GetDelinquencyRangesResponse range =
DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
+ delinquencyRangeResponse.getResourceId());
+
+ // Second Range
+ delinquencyRangeResponse =
DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
jsonRange);
+ rangeIds.add(delinquencyRangeResponse.getResourceId());
+
+ range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec,
responseSpec, delinquencyRangeResponse.getResourceId());
+ final String classificationExpected = range.getClassification();
+ log.info("Expected Delinquency Range classification after Disbursement
{}", classificationExpected);
+
+ String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
+ PostDelinquencyBucketResponse delinquencyBucketResponse =
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
+ responseSpec, jsonBucket);
+ assertNotNull(delinquencyBucketResponse);
+ 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());
+ assertNotNull(getLoanProductsProductResponse);
+ log.info("Loan Product Bucket Name: {}",
getLoanProductsProductResponse.getDelinquencyBucket().getName());
+
assertEquals(getLoanProductsProductResponse.getDelinquencyBucket().getName(),
delinquencyBucket.getName());
+
+ final LocalDate todaysDate = Utils.getLocalDateOfTenant();
+ // Older date to have more than one overdue installment
+ LocalDate transactionDate = todaysDate.minusDays(45);
+ String operationDate = Utils.dateFormatter.format(transactionDate);
+
+ // Create Loan Account
+ final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
+ getLoanProductsProductResponse.getId().toString(),
operationDate);
+
+ GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+ log.info("Loan Delinquency Range after Disbursement {}",
getLoansLoanIdResponse.getDelinquencyRange().getClassification());
+ assertNotNull(getLoansLoanIdResponse);
+ // First Loan Delinquency Classification after Disbursement command
+
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(),
classificationExpected);
+ printRepaymentSchedule(getLoansLoanIdResponse);
+
+ // Apply a repayment to get a full paid installment
+ operationDate = Utils.dateFormatter.format(todaysDate);
+ loanTransactionHelper.makeLoanRepayment(operationDate, 1033.33f,
loanId);
+
+ getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec,
responseSpec, loanId);
+ log.info("Loan Delinquency Range after Repayment {}",
getLoansLoanIdResponse.getDelinquencyRange());
+ assertNotNull(getLoansLoanIdResponse);
+ // The Loan Delinquency Classification after Repayment command must be
null
+ assertNull(getLoansLoanIdResponse.getDelinquencyRange());
+ printRepaymentSchedule(getLoansLoanIdResponse);
+
+ transactionDate = todaysDate.minusDays(18);
+ operationDate = Utils.dateFormatter.format(transactionDate);
+
+ // Create and apply Charge for Specific Due Date
+ final Integer chargeId = ChargesHelper.createCharges(requestSpec,
responseSpec,
+ ChargesHelper.getLoanSpecifiedDueDateJSON(1, "30", false));
+ assertNotNull(chargeId);
+ final Integer loanChargeId =
loanTransactionHelper.addChargesForLoan(loanId, getChargeApplyJSON(chargeId,
operationDate),
+ responseSpec);
+ assertNotNull(loanChargeId);
+
+ getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec,
responseSpec, loanId);
+ printRepaymentSchedule(getLoansLoanIdResponse);
+
+ log.info("Loan Delinquency Range after add Loan Charge {}",
getLoansLoanIdResponse.getDelinquencyRange());
+ assertNotNull(getLoansLoanIdResponse.getDelinquencyRange());
+ // Evaluate a Delinquency Tag set after add charge to the Loan
+
assertEquals(getLoansLoanIdResponse.getDelinquencyRange().getClassification(),
classificationExpected);
+ }
+
@Test
public void testLoanClassificationRealtimeOlderLoan() {
// Given
@@ -741,4 +830,16 @@ public class DelinquencyBucketsIntegrationTest {
}
}
+ private String getChargeApplyJSON(final Integer chargeId, final String
dueDate) {
+ final HashMap<String, Object> map = new HashMap<>();
+ map.put("chargeId", chargeId);
+ map.put("amount", 12.0f);
+ map.put("dueDate", dueDate);
+ map.put("dateFormat", Utils.DATE_FORMAT);
+ map.put("locale", CommonConstants.LOCALE);
+ final String chargeApplyJSON = new Gson().toJson(map);
+ log.info("{}", chargeApplyJSON);
+ return chargeApplyJSON;
+ }
+
}