Foo Developer created FINERACT-3034:
---------------------------------------

             Summary: Loan reschedule after a 'reschedule to next repayment 
date' holiday pulls every later due date back one period
                 Key: FINERACT-3034
                 URL: https://issues.apache.org/jira/browse/FINERACT-3034
             Project: Apache Fineract
          Issue Type: Bug
          Components: Loan
            Reporter: Foo Developer
            Assignee: Foo Developer


h3. Steps to reproduce
# Set the global configuration {{reschedule-repayments-on-holidays}} to 
{{true}}. Business date 30 October 2026.
# Create and activate a holiday for the office from 30 December 2026 to 05 
January 2027 with {{reschedulingType}} = 1 (reschedule to next repayment date).
# Create, approve and disburse a cumulative loan on 30 October 2026: principal 
12,000, 12 monthly repayments, 1% interest per month, declining balance, equal 
installments.
   The schedule is generated correctly: installment 2 is moved from 30 December 
2026 to 30 January 2027, installment 3 falls on 28 February 2027 and the 
maturity is 30 November 2027.
# Create a loan reschedule request with {{rescheduleFromDate}} 28 February 2027 
and {{graceOnPrincipal}} 1:
   {code:json}   POST /fineract-provider/api/v1/rescheduleloans
   {
     "loanId": <loanId>,
     "rescheduleFromDate": "28 February 2027",
     "submittedOnDate": "30 October 2026",
     "rescheduleReasonId": <codeValueId>,
     "graceOnPrincipal": 1,
     "dateFormat": "dd MMMM yyyy",
     "locale": "en"
   }
   {code}
# {{GET 
/fineract-provider/api/v1/rescheduleloans/<requestId>?command=previewLoanReschedule}}

h3. Expected

Installments 1 and 2 are unchanged. Installment 3 keeps its due date of 28 
February 2027 and carries the principal grace (principal 0). The due dates of 
the later installments are unchanged, and one installment is added at the end, 
on 30 December 2027.

h3. Actual

>From the reschedule point on, every due date is one period early:
* Installment 3 runs from 30 January 2027 to 30 January 2027, a zero-length 
period, and is charged its full amount.
* The principal grace lands on installment 4 (due 28 February 2027), one 
installment too late.
* Every later due date is one month early, so the added installment 13 falls on 
the old maturity date (30 November 2027) and the maturity does not move.

Approving the request stores this schedule.

h3. Root cause

In {{AbstractCumulativeLoanScheduleGenerator}}, the full generation 
({{generate(..)}}) advances the repayment chain from 
{{AdjustedDateDetailsDTO.getChangedActualRepaymentDate()}}. For a "reschedule 
to next repayment date" holiday, 
{{DefaultScheduledDateGenerator.checkAndUpdateWorkingDayIfRepaymentDateIsHolidayDay}}
 sets that value to the date the installment was moved to, so the next 
installment is generated from the moved date.

The retained-installment loop of {{rescheduleNextInstallments(..)}} calls the 
same {{adjustRepaymentDate(..)}} but reads only {{getChangedScheduleDate()}}, 
so {{actualRepaymentDate}} stays on the unmoved date. That value is passed to 
{{LoanScheduleParams.createLoanScheduleParamsForPartialUpdate(..)}}, so the 
regenerated periods start one period behind the existing schedule. Every 
regeneration path that goes through {{rescheduleNextInstallments}} is affected, 
including loan reschedule preview and approve.

h3. Proposed fix

In the retained-installment loop of {{rescheduleNextInstallments(..)}}, keep 
the {{AdjustedDateDetailsDTO}} and also set {{actualRepaymentDate = 
adjustedDateDetailsDTO.getChangedActualRepaymentDate()}}, as the full 
generation does. For a specific-date holiday or a non-working-day move, the 
changed actual repayment date equals the input date, so those cases are 
unchanged.

h3. Test

An integration test reproducing the scenario above: holiday with reschedule to 
next repayment date, then a reschedule request with a principal grace. It 
asserts that the previewed due dates keep the holiday move.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to