Skip to content

Commit 073d50f

Browse files
author
Jose Alberto Hernandez
committed
FINERACT-2421: Loan repayment transaction template with overpaid loan
1 parent 6875645 commit 073d50f

File tree

2 files changed

+47
-38
lines changed

2 files changed

+47
-38
lines changed

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.Set;
4040
import java.util.stream.Collectors;
4141
import lombok.RequiredArgsConstructor;
42+
import lombok.extern.slf4j.Slf4j;
4243
import org.apache.commons.lang3.StringUtils;
4344
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
4445
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
@@ -159,6 +160,7 @@
159160
import org.springframework.transaction.annotation.Transactional;
160161
import org.springframework.util.CollectionUtils;
161162

163+
@Slf4j
162164
@RequiredArgsConstructor
163165
@Transactional(readOnly = true)
164166
public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, LoanReadPlatformServiceCommon {
@@ -540,14 +542,11 @@ public LoanTransactionData retrieveLoanTransactionTemplate(final Long loanId, fi
540542

541543
@Override
542544
public LoanTransactionData retrieveLoanTransactionTemplate(final Long loanId) {
543-
544545
this.context.authenticatedUser();
545546

546-
RepaymentTransactionTemplateMapper mapper = new RepaymentTransactionTemplateMapper(sqlGenerator);
547-
String sql = "select " + mapper.schema();
548-
LoanTransactionData loanTransactionData = this.jdbcTemplate.queryForObject(sql, mapper, // NOSONAR
549-
LoanTransactionType.REPAYMENT.getValue(), LoanTransactionType.DOWN_PAYMENT.getValue(),
550-
LoanTransactionType.REPAYMENT.getValue(), LoanTransactionType.DOWN_PAYMENT.getValue(), loanId, loanId);
547+
final RepaymentTransactionTemplateMapper mapper = new RepaymentTransactionTemplateMapper();
548+
LoanTransactionData loanTransactionData = this.jdbcTemplate.queryForObject("select " + mapper.schema(), mapper, // NOSONAR
549+
LoanTransactionType.REPAYMENT.getValue(), LoanTransactionType.DOWN_PAYMENT.getValue(), loanId);
551550
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
552551
return LoanTransactionData.templateOnTop(loanTransactionData, paymentOptions);
553552
}
@@ -2116,42 +2115,42 @@ public CurrencyData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum)
21162115

21172116
private static final class RepaymentTransactionTemplateMapper implements RowMapper<LoanTransactionData> {
21182117

2119-
private final DatabaseSpecificSQLGenerator sqlGenerator;
21202118
private final CurrencyMapper currencyMapper = new CurrencyMapper();
21212119

2122-
RepaymentTransactionTemplateMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
2123-
this.sqlGenerator = sqlGenerator;
2124-
}
2125-
21262120
public String schema() {
21272121
// TODO: investigate whether it can be refactored to be more efficient
2128-
StringBuilder sqlBuilder = new StringBuilder();
2129-
sqlBuilder.append("(CASE ");
2130-
sqlBuilder.append(
2131-
"WHEN (select max(tr.transaction_date) as transaction_date from m_loan_transaction tr where tr.loan_id = l.id AND tr.transaction_type_enum in (?,?) AND tr.is_reversed = false) > ls.dueDate ");
2132-
sqlBuilder.append(
2133-
"THEN (select max(tr.transaction_date) as transaction_date from m_loan_transaction tr where tr.loan_id = l.id AND tr.transaction_type_enum in (?,?) AND tr.is_reversed = false) ");
2134-
sqlBuilder.append("ELSE ls.dueDate END) as transactionDate, ");
2135-
sqlBuilder.append(
2136-
"ls.principal_amount - coalesce(ls.principal_writtenoff_derived, 0) - coalesce(ls.principal_completed_derived, 0) as principalDue, ");
2137-
sqlBuilder.append(
2138-
"ls.interest_amount - coalesce(ls.interest_completed_derived, 0) - coalesce(ls.interest_waived_derived, 0) - coalesce(ls.interest_writtenoff_derived, 0) as interestDue, ");
2139-
sqlBuilder.append(
2140-
"ls.fee_charges_amount - coalesce(ls.fee_charges_completed_derived, 0) - coalesce(ls.fee_charges_writtenoff_derived, 0) - coalesce(ls.fee_charges_waived_derived, 0) as feeDue, ");
2141-
sqlBuilder.append(
2142-
"ls.penalty_charges_amount - coalesce(ls.penalty_charges_completed_derived, 0) - coalesce(ls.penalty_charges_writtenoff_derived, 0) - coalesce(ls.penalty_charges_waived_derived, 0) as penaltyDue, ");
2143-
sqlBuilder.append(
2144-
"l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, l.net_disbursal_amount as netDisbursalAmount, ");
2145-
sqlBuilder.append("rc." + sqlGenerator.escape("name")
2146-
+ " as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode ");
2147-
sqlBuilder.append("FROM m_loan l ");
2148-
sqlBuilder.append("JOIN m_currency rc on rc." + sqlGenerator.escape("code") + " = l.currency_code ");
2149-
sqlBuilder.append("JOIN m_loan_repayment_schedule ls ON ls.loan_id = l.id AND ls.completed_derived = false ");
2150-
sqlBuilder.append(
2151-
"JOIN((SELECT ls.loan_id, ls.duedate as datedue FROM m_loan_repayment_schedule ls WHERE ls.loan_id = ? and ls.completed_derived = false ORDER BY ls.duedate LIMIT 1)) asq on asq.loan_id = ls.loan_id ");
2152-
sqlBuilder.append("AND asq.datedue = ls.duedate ");
2153-
sqlBuilder.append("WHERE l.id = ? LIMIT 1");
2154-
return sqlBuilder.toString();
2122+
return """
2123+
GREATEST(loan_transaction.transaction_date, ls.dueDate) as transactionDate,
2124+
coalesce(ls.principal_amount, 0) - coalesce(ls.principal_writtenoff_derived, 0) - coalesce(ls.principal_completed_derived, 0) as principalDue,
2125+
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,
2126+
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,
2127+
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,
2128+
l.currency_code as currencyCode,
2129+
l.currency_digits as currencyDigits,
2130+
l.currency_multiplesof as inMultiplesOf,
2131+
l.net_disbursal_amount as netDisbursalAmount,
2132+
rc."name" as currencyName,
2133+
rc.display_symbol as currencyDisplaySymbol,
2134+
rc.internationalized_name_code as currencyNameCode
2135+
FROM
2136+
m_loan l
2137+
JOIN m_currency rc on rc."code" = l.currency_code
2138+
JOIN m_loan_repayment_schedule ls ON ls.loan_id = l.id AND (l.loan_status_id >= 600 OR ls.completed_derived = false)
2139+
LEFT JOIN (
2140+
select
2141+
tr.loan_id, max(tr.transaction_date) as transaction_date
2142+
from
2143+
m_loan_transaction tr
2144+
where
2145+
tr.transaction_type_enum in (?,?)
2146+
AND tr.is_reversed = false
2147+
group by tr.loan_id
2148+
) loan_transaction ON loan_transaction.loan_id = l.id
2149+
WHERE
2150+
l.id = ?
2151+
ORDER BY ls.installment
2152+
LIMIT 1
2153+
""";
21552154
}
21562155

21572156
@Override

integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,11 @@ public void uc2() {
278278
validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 25.0, 0.0);
279279
validateLoanTransaction(loanDetails, 4, 125.0, 100.0, 25.0, 0.0);
280280
assertTrue(loanDetails.getStatus().getOverpaid());
281+
282+
// Loan Repayment (after) Overpaid
283+
GetLoansLoanIdTransactionsTemplateResponse transactionAfter = loanTransactionHelper
284+
.retrieveTransactionTemplate(loanResponse.getLoanId(), "repayment", DATETIME_PATTERN, "15 February 2023", LOCALE);
285+
assertNotNull(transactionAfter);
281286
});
282287
}
283288
// UC3: Overpayment2
@@ -345,6 +350,11 @@ public void uc3() {
345350
validateRepaymentPeriod(loanDetails, 4, 125.0, 125.0, 0.0, 25.0, 0.0);
346351
validateLoanTransaction(loanDetails, 4, 125.0, 100.0, 25.0, 0.0);
347352
assertTrue(loanDetails.getStatus().getOverpaid());
353+
354+
// Loan Repayment (after) Overpaid
355+
GetLoansLoanIdTransactionsTemplateResponse transactionAfter = loanTransactionHelper
356+
.retrieveTransactionTemplate(loanResponse.getLoanId(), "repayment", DATETIME_PATTERN, "15 February 2023", LOCALE);
357+
assertNotNull(transactionAfter);
348358
});
349359
}
350360
// UC4: Delinquent balance

0 commit comments

Comments
 (0)