chinmaya samantara created FINERACT-2971:
--------------------------------------------
Summary: Foreclosure of a progressive loan always fails with HTTP
500 (NullPointerException on ScheduleGeneratorDTO)
Key: FINERACT-2971
URL: https://issues.apache.org/jira/browse/FINERACT-2971
Project: Apache Fineract
Issue Type: Bug
Reporter: chinmaya samantara
Assignee: chinmaya samantara
Foreclosing a loan that uses the progressive schedule (advanced payment
allocation) always fails. The API answers with a bare HTTP 500, nothing is
logged, and the loan stays Active. The same request on a cumulative loan closes
it as expected. The foreclosure template still works, so the UI shows the
payoff amount and then fails on submit.
*Steps to reproduce* (develop 0df2ef786f, PostgreSQL)
1. Loan product with loanScheduleType PROGRESSIVE and
transactionProcessingStrategyCode advanced-payment-allocation-strategy (no
interest recalculation), 6 monthly installments, 2% per month.
2. Loan of 1200 disbursed on 01 March 2026.
3. Foreclose it:
{code}
POST /fineract-provider/api/v1/loans/{loanId}/transactions?command=foreclosure
{ "transactionDate": "01 August 2026", "dateFormat": "dd MMMM yyyy", "locale":
"en" }
{code}
Actual result: HTTP 500 with Spring's default body (timestamp, status, error,
path) and no log entry. The loan stays Active.
Expected result: a repayment for the foreclosure amount is created and the loan
is Closed (obligations met), like for a cumulative loan.
{{GET /loans/{loanId}/transactions/template?command=foreclosure}} works for the
same loan (amount 1281.19). The same POST on a cumulative product closes the
loan.
Sending the request through the batch API shows the exception:
{code}
POST /fineract-provider/api/v1/batches?enclosingTransaction=false
-> statusCode 500, body: {"Exception":"Cannot invoke
\"org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO.getCalendar()\"
because \"scheduleGeneratorDTO\" is null"}
{code}
*Cause*
LoanAccountDomainServiceJpa.foreCloseLoan() passes a hard-coded null:
{code:java}
final ScheduleGeneratorDTO scheduleGeneratorDTO = null;
...
handleForeClosureTransactions(loan, payment, scheduleGeneratorDTO);
{code}
handleForeClosureTransactions() hands it to
loanDownPaymentHandlerService.handleRepaymentOrRecoveryOrWaiverTransaction().
For progressive loans the schedule is rebuilt through LoanMapper ->
LoanTermVariationsMapper.constructLoanApplicationTerms(scheduleGeneratorDTO,
loan), whose first lines call scheduleGeneratorDTO.getCalendar()
(LoanTermVariationsMapper.java:74), so it throws a NullPointerException.
*Suggested fix*
Build the DTO in foreCloseLoan() (for example with
loanUtilService.buildScheduleGeneratorDTO(loan, null)) instead of passing null,
and add a test that forecloses a progressive loan.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)