Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2125,20 +2125,30 @@ private static final class RepaymentTransactionTemplateMapper implements RowMapp

public String schema() {
// TODO: investigate whether it can be refactored to be more efficient
return " GREATEST(loan_transaction.transaction_date, ls.dueDate) as transactionDate,"
+ " coalesce(ls.principal_amount, 0) - coalesce(ls.principal_writtenoff_derived, 0) - coalesce(ls.principal_completed_derived, 0) as principalDue,"
+ " coalesce(ls.interest_amount, 0) - coalesce(ls.interest_completed_derived, 0) - coalesce(ls.interest_waived_derived, 0) - coalesce(ls.interest_writtenoff_derived, 0) as interestDue,"
+ " coalesce(ls.fee_charges_amount, 0) - coalesce(ls.fee_charges_completed_derived, 0) - coalesce(ls.fee_charges_writtenoff_derived, 0) - coalesce(ls.fee_charges_waived_derived, 0) as feeDue,"
+ " coalesce(ls.penalty_charges_amount, 0) - coalesce(ls.penalty_charges_completed_derived, 0) - coalesce(ls.penalty_charges_writtenoff_derived, 0) - coalesce(ls.penalty_charges_waived_derived, 0) as penaltyDue,"
final String principalDueExpression = "coalesce(ls.principal_amount, 0) - coalesce(ls.principal_writtenoff_derived, 0) "
+ "- coalesce(ls.principal_completed_derived, 0)";
final String interestDueExpression = "coalesce(ls.interest_amount, 0) - coalesce(ls.interest_completed_derived, 0) "
+ "- coalesce(ls.interest_waived_derived, 0) - coalesce(ls.interest_writtenoff_derived, 0)";
final String feeDueExpression = "coalesce(ls.fee_charges_amount, 0) - coalesce(ls.fee_charges_completed_derived, 0) "
+ "- coalesce(ls.fee_charges_writtenoff_derived, 0) - coalesce(ls.fee_charges_waived_derived, 0)";
final String penaltyDueExpression = "coalesce(ls.penalty_charges_amount, 0) "
+ "- coalesce(ls.penalty_charges_completed_derived, 0) - coalesce(ls.penalty_charges_writtenoff_derived, 0) "
+ "- coalesce(ls.penalty_charges_waived_derived, 0)";
final String totalDueExpression = principalDueExpression + " + " + interestDueExpression + " + " + feeDueExpression + " + "
+ penaltyDueExpression;

return " GREATEST(loan_transaction.transaction_date, ls.dueDate) as transactionDate," + " " + principalDueExpression
+ " as principalDue," + " " + interestDueExpression + " as interestDue," + " " + feeDueExpression + " as feeDue,"
+ " " + penaltyDueExpression + " as penaltyDue,"
+ " l.currency_code as currencyCode," + " l.currency_digits as currencyDigits,"
+ " l.currency_multiplesof as inMultiplesOf," + " l.net_disbursal_amount as netDisbursalAmount," + " rc."
+ sqlGenerator.escape("name") + " as currencyName," + " rc.display_symbol as currencyDisplaySymbol,"
+ " rc.internationalized_name_code as currencyNameCode" + " FROM" + " m_loan l" + " JOIN m_currency rc on rc."
+ sqlGenerator.escape("code") + " = l.currency_code" + " JOIN m_loan_repayment_schedule ls ON ls.loan_id = l.id"
+ " LEFT JOIN (" + " select tr.loan_id, max(tr.transaction_date) as transaction_date" + " from m_loan_transaction tr"
+ " where tr.transaction_type_enum in (?,?)" + " AND tr.is_reversed = false" + " group by tr.loan_id"
+ " ) loan_transaction ON loan_transaction.loan_id = l.id" + " WHERE l.id = ?" + " ORDER BY ls.installment"
+ " LIMIT 1";
+ " ) loan_transaction ON loan_transaction.loan_id = l.id" + " WHERE l.id = ?" + " ORDER BY CASE WHEN ("
+ totalDueExpression + ") > 0 THEN 0 ELSE 1 END, ls.installment" + " LIMIT 1";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,35 @@ public void uc4() {
});
}

@Test
public void repaymentTemplateReturnsNextUnpaidInstallmentAmount() {
runAt("15 February 2023", () -> {
final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), commonLoanProductId,
BigDecimal.valueOf(500.0), 45, 15, 3, BigDecimal.ZERO, "01 January 2023", "01 January 2023");

loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(500)).dateFormat(DATETIME_PATTERN)
.approvedOnDate("01 January 2023").locale("en"));

loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
new PostLoansLoanIdRequest().actualDisbursementDate("01 January 2023").dateFormat(DATETIME_PATTERN)
.transactionAmount(BigDecimal.valueOf(500.00)).locale("en"));

loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
.dateFormat(DATETIME_PATTERN).transactionDate("16 January 2023").locale("en").transactionAmount(125.0));

final GetLoansLoanIdTransactionsTemplateResponse transactionTemplate = loanTransactionHelper
.retrieveTransactionTemplate(loanResponse.getLoanId(), "repayment", DATETIME_PATTERN, "16 January 2023", LOCALE);

assertNotNull(transactionTemplate);
assertEquals(125.0, transactionTemplate.getAmount());
assertEquals(125.0, transactionTemplate.getPrincipalPortion());
assertEquals(0.0, transactionTemplate.getInterestPortion());
assertEquals(0.0, transactionTemplate.getFeeChargesPortion());
assertEquals(0.0, transactionTemplate.getPenaltyChargesPortion());
});
}

// UC5: Refund past due
// ADVANCED_PAYMENT_ALLOCATION_STRATEGY
// 1. Disburse the loan
Expand Down
Loading