Loan Delinquency Tags with Loan charges

This commit is contained in:
Jose Alberto Hernandez
2022-09-19 13:23:02 +02:00
committed by Arnold Gálovics
parent f86841646b
commit 33d781f5fb
3 changed files with 106 additions and 12 deletions
@@ -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
*
@@ -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));
@@ -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;
}
}