FINERACT-1885 - Fix Actual Maturity when Loan reopen

- [x] Fix actual maturity date
- [x] Added to actual maturity date to the timeline too
- [x] Integration test
This commit is contained in:
Janos Haber
2023-02-13 23:43:11 +01:00
committed by Adam Saghy
parent 521aec47ea
commit 0d7c93177a
7 changed files with 84 additions and 10 deletions
@@ -470,7 +470,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
.append(" l.closedon_date as closedOnDate,")
.append(" cbu.username as closedByUsername, cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname,")
.append(" la.overdue_since_date_derived as overdueSinceDate, ")
.append(" l.writtenoffon_date as writtenOffOnDate, l.expected_maturedon_date as expectedMaturityDate, ")
.append(" l.writtenoffon_date as writtenOffOnDate, l.maturedon_date as actualMaturityDate, l.expected_maturedon_date as expectedMaturityDate, ")
.append(" l.charged_off_on_date as chargedOffOnDate, cobu.username as chargedOffByUsername, ")
.append(" cobu.firstname as chargedOffByFirstname, cobu.lastname as chargedOffByLastname ").append(" from m_loan l ")
.append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id")
@@ -541,6 +541,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
final LocalDate writtenOffOnDate = JdbcSupport.getLocalDate(rs, "writtenOffOnDate");
final LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
final LocalDate actualMaturityDate = JdbcSupport.getLocalDate(rs, "actualMaturityDate");
final LocalDate overdueSinceDate = JdbcSupport.getLocalDate(rs, "overdueSinceDate");
@@ -556,8 +557,8 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
withdrawnOnDate, withdrawnByUsername, withdrawnByFirstname, withdrawnByLastname, approvedOnDate, approvedByUsername,
approvedByFirstname, approvedByLastname, expectedDisbursementDate, actualDisbursementDate, disbursedByUsername,
disbursedByFirstname, disbursedByLastname, closedOnDate, closedByUsername, closedByFirstname, closedByLastname,
expectedMaturityDate, writtenOffOnDate, closedByUsername, closedByFirstname, closedByLastname, chargedOffOnDate,
chargedOffByUsername, chargedOffByFirstname, chargedOffByLastname);
actualMaturityDate, expectedMaturityDate, writtenOffOnDate, closedByUsername, closedByFirstname, closedByLastname,
chargedOffOnDate, chargedOffByUsername, chargedOffByFirstname, chargedOffByLastname);
return new LoanAccountSummaryData(id, accountNo, parentAccountNumber, externalId, productId, loanProductName,
shortLoanProductName, loanStatus, loanType, loanCycle, timeline, inArrears, originalLoan, loanBalance, amountPaid);
@@ -584,7 +585,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
.append(" l.approvedon_date as approvedOnDate,")
.append(" l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate,")
.append(" l.closedon_date as closedOnDate,").append(" la.overdue_since_date_derived as overdueSinceDate,")
.append(" l.writtenoffon_date as writtenOffOnDate, l.expected_maturedon_date as expectedMaturityDate,")
.append(" l.writtenoffon_date as writtenOffOnDate, l.maturedon_date as actualMaturityDate, l.expected_maturedon_date as expectedMaturityDate,")
.append(" g.is_active as isActive,").append(" cv.code_value as relationship,").append(" sa.on_hold_funds_derived")
.append(" from m_loan l ").append(" join m_guarantor as g on g.loan_id = l.id ")
.append(" join m_client as c on c.id = g.entity_id ").append(" LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id")
@@ -245,6 +245,8 @@ final class LoansApiResourceSwagger {
public String disbursedByLastname;
@Schema(example = "[2012, 4, 10]")
public LocalDate expectedMaturityDate;
@Schema(example = "[2012, 4, 10]")
public LocalDate actualMaturityDate;
@Schema(example = "[2012, 4, 3]")
public LocalDate closedOnDate;
@Schema(example = "[2012, 4, 10]")
@@ -56,6 +56,8 @@ public class LoanApplicationTimelineData {
private final String closedByUsername;
private final String closedByFirstname;
private final String closedByLastname;
private final LocalDate actualMaturityDate;
private final LocalDate expectedMaturityDate;
private final LocalDate writeOffOnDate;
private final String writeOffByUsername;
@@ -102,14 +104,15 @@ public class LoanApplicationTimelineData {
final String chargedOffByUsername = null;
final String chargedOffByFirstname = null;
final String chargedOffByLastname = null;
final LocalDate actualMaturityDate = null;
return new LoanApplicationTimelineData(submittedOnDate, submittedByUsername, submittedByFirstname, submittedByLastname,
rejectedOnDate, rejectedByUsername, rejectedByFirstname, rejectedByLastname, withdrawnOnDate, withdrawnByUsername,
withdrawnByFirstname, withdrawnByLastname, approvedOnDate, approvedByUsername, approvedByFirstname, approvedByLastname,
expectedDisbursementDate, actualDisbursementDate, disbursedByUsername, disbursedByFirstname, disbursedByLastname,
closedOnDate, closedByUsername, closedByFirstname, closedByLastname, expectedMaturityDate, writeOffOnDate,
writeOffByUsername, writeOffByFirstname, writeOffByLastname, chargedOffOnDate, chargedOffByUsername, chargedOffByFirstname,
chargedOffByLastname);
closedOnDate, closedByUsername, closedByFirstname, closedByLastname, actualMaturityDate, expectedMaturityDate,
writeOffOnDate, writeOffByUsername, writeOffByFirstname, writeOffByLastname, chargedOffOnDate, chargedOffByUsername,
chargedOffByFirstname, chargedOffByLastname);
}
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData(final CurrencyData currency, final BigDecimal principal,
@@ -7027,4 +7027,10 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
return getLoanTransactions().stream().filter(predicate).toList();
}
public void handleMaturityDateActivate() {
if (this.expectedMaturityDate != null && this.actualMaturityDate == null) {
this.actualMaturityDate = this.expectedMaturityDate;
}
}
}
@@ -616,7 +616,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " l.approvedon_date as approvedOnDate, abu.username as approvedByUsername, abu.firstname as approvedByFirstname, abu.lastname as approvedByLastname,"
+ " l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate, dbu.username as disbursedByUsername, dbu.firstname as disbursedByFirstname, dbu.lastname as disbursedByLastname,"
+ " l.closedon_date as closedOnDate, cbu.username as closedByUsername, cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname, l.writtenoffon_date as writtenOffOnDate, "
+ " l.expected_firstrepaymenton_date as expectedFirstRepaymentOnDate, l.interest_calculated_from_date as interestChargedFromDate, l.expected_maturedon_date as expectedMaturityDate, "
+ " l.expected_firstrepaymenton_date as expectedFirstRepaymentOnDate, l.interest_calculated_from_date as interestChargedFromDate, l.maturedon_date as actualMaturityDate, l.expected_maturedon_date as expectedMaturityDate, "
+ " l.principal_amount_proposed as proposedPrincipal, l.principal_amount as principal, l.approved_principal as approvedPrincipal, l.net_disbursal_amount as netDisbursalAmount, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery,"
+ " l.grace_on_principal_periods as graceOnPrincipalPayment, l.recurring_moratorium_principal_periods as recurringMoratoriumOnPrincipalPeriods, l.grace_on_interest_periods as graceOnInterestPayment, l.grace_interest_free_periods as graceOnInterestCharged,l.grace_on_arrears_ageing as graceOnArrearsAgeing,"
+ " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
@@ -791,6 +791,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final LocalDate writtenOffOnDate = JdbcSupport.getLocalDate(rs, "writtenOffOnDate");
final Long writeoffReasonId = JdbcSupport.getLong(rs, "writeoffReasonId");
final String writeoffReason = rs.getString("writeoffReason");
final LocalDate actualMaturityDate = JdbcSupport.getLocalDate(rs, "actualMaturityDate");
final LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
final Boolean isvariableInstallmentsAllowed = rs.getBoolean("isvariableInstallmentsAllowed");
@@ -810,8 +811,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
withdrawnOnDate, withdrawnByUsername, withdrawnByFirstname, withdrawnByLastname, approvedOnDate, approvedByUsername,
approvedByFirstname, approvedByLastname, expectedDisbursementDate, actualDisbursementDate, disbursedByUsername,
disbursedByFirstname, disbursedByLastname, closedOnDate, closedByUsername, closedByFirstname, closedByLastname,
expectedMaturityDate, writtenOffOnDate, closedByUsername, closedByFirstname, closedByLastname, chargedOffOnDate,
chargedOffByUsername, chargedOffByFirstname, chargedOffByLastname);
actualMaturityDate, expectedMaturityDate, writtenOffOnDate, closedByUsername, closedByFirstname, closedByLastname,
chargedOffOnDate, chargedOffByUsername, chargedOffByFirstname, chargedOffByLastname);
final BigDecimal principal = rs.getBigDecimal("principal");
final BigDecimal approvedPrincipal = rs.getBigDecimal("approvedPrincipal");
@@ -50,6 +50,9 @@ public class LoanStatusChangePlatformServiceImpl implements LoanStatusChangePlat
log.debug("Loan Status {} for loan {}", loan.getStatus().getCode(), loan.getId());
loan.applyIncomeAccrualTransaction(loan.getClosedOnDate());
}
if (loan.isOpen()) {
loan.handleMaturityDateActivate();
}
}
}
}
@@ -7004,6 +7004,64 @@ public class ClientLoanIntegrationTest {
assertEquals("Administrator", loanDetails.getTimeline().getChargedOffByLastname());
}
@Test
public void testCloseOpenMaturityDate() {
GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec, this.responseSpec, true);
final Account assetAccount = this.accountHelper.createAssetAccount();
final Account incomeAccount = this.accountHelper.createIncomeAccount();
final Account expenseAccount = this.accountHelper.createExpenseAccount();
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
final Integer loanProductID = createLoanProductWithPeriodicAccrualAccountingNoInterest(assetAccount, incomeAccount, expenseAccount,
overpaymentAccount);
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2011");
final Integer loanID = applyForLoanApplication(clientID, loanProductID);
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
loanStatusHashMap = this.loanTransactionHelper.approveLoan("02 September 2022", loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 2022", loanID, "1000");
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
GetLoansLoanIdResponse loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
LocalDate expectedMaturityDate = loanDetails.getTimeline().getExpectedMaturityDate();
LocalDate actualMaturityDate = loanDetails.getTimeline().getActualMaturityDate();
assertTrue(expectedMaturityDate.isEqual(actualMaturityDate));
this.loanTransactionHelper.makeRepayment("04 September 2022", Float.parseFloat("500"), loanID);
this.loanTransactionHelper.makeRepayment("05 September 2022", Float.parseFloat("700"), loanID);
loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
expectedMaturityDate = loanDetails.getTimeline().getExpectedMaturityDate();
actualMaturityDate = loanDetails.getTimeline().getActualMaturityDate();
assertNotNull(expectedMaturityDate);
assertNull(actualMaturityDate);
this.loanTransactionHelper.reverseLoanTransaction((long) loanID, loanDetails.getTransactions().get(1).getId(),
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy").transactionDate("04 September 2022")
.transactionAmount(0.0).locale("en"));
loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID);
expectedMaturityDate = loanDetails.getTimeline().getExpectedMaturityDate();
actualMaturityDate = loanDetails.getTimeline().getActualMaturityDate();
assertNotNull(expectedMaturityDate);
assertNotNull(actualMaturityDate);
assertTrue(expectedMaturityDate.isEqual(actualMaturityDate));
}
@Test
public void testReverseReplay() {
try {