[
https://issues.apache.org/jira/browse/FINERACT-2971?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18131592#comment-18131592
]
chinmaya samantara commented on FINERACT-2971:
----------------------------------------------
[~adamsaghy]
I looked into the fix and want to check the expected behaviour before opening a
PR, because the obvious fix is not enough.
Setup: progressive loan, advanced payment allocation, no interest
recalculation, 1200 over 6 months at 2% per month, disbursed 01 March 2026.
Same loan with a cumulative schedule for comparison. Foreclosure template
amount is 1281.19 (on 01 August 2026) for both.
1) Building the ScheduleGeneratorDTO in foreCloseLoan() (the fix suggested in
the description) stops the NPE, but the loan stays Active with 4.20
outstanding. handleRepaymentOrRecoveryOrWaiverTransaction() regenerates the
progressive schedule, which brings back installment 6 that
updateInstallmentsPostDate() had removed, so 4.20 of the payment goes to
installment 6's interest.
2) Skipping the regeneration for foreclosures closes the loan, but the
progressive processor then re-amortises the whole loan as a 5-installment loan:
installments 1-4 change (principal 190.23 -> 230.59), interest becomes 72.95
instead of 81.19, and the loan ends Overpaid by 8.24.
The cumulative loan closes correctly with interest 81.19.
What is the expected behaviour for foreclosing a progressive loan? Should it be
supported (for example as a payoff on the progressive interest model, keeping
past installments), or should foreclosure be rejected for progressive loans
with a validation error that points to a payoff repayment? I'm happy to
implement either.
> 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
> Priority: Major
> Fix For: 1.17.0
>
>
> 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
(v10.3.26#10030026)