Skip to content

FINERACT-2455: Working Capital - Delinquency Effective Date - #6476

Open
alberto-art3ch wants to merge 2 commits into
apache:developfrom
openMF:FINERACT-2455/working-capital-delinquency-effective-date
Open

alberto-art3ch wants to merge 2 commits into
apache:developfrom
openMF:FINERACT-2455/working-capital-delinquency-effective-date

Conversation

@alberto-art3ch

Copy link
Copy Markdown
Contributor

Description

Expose delinquencyEffectiveStartDate on the Working Capital loan retrieve response and in the WC loan business event payload. When delinquency grace days are configured (> 0) and the earliest delinquent period is the first one, the field returns delinquencyStartDate + delinquencyGraceDays — the date the borrower's cool off period ends and the delinquency window effectively begins. It is null for any later period, since only the first period is shifted by the grace days.

FINERACT-2455

Checklist

Please make sure these boxes are checked before submitting your pull request - thanks!

  • Write the commit message as per our guidelines
  • Acknowledge that we will not review PRs that are not passing the build ("green") - it is your responsibility to get a proposed PR to pass the build, not primarily the project's maintainers.
  • Create/update unit or integration tests for verifying the changes made.
  • Follow our coding conventions.
  • Add required Swagger annotation and update API documentation at fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm with details of any API changes
  • This PR must not be a "code dump". Large changes can be made in a branch, with assistance. Ask for help on the developer mailing list.
  • If merging this PR resolves a JIRA issue, I will mark that issue as resolved and set "Fix Version/s" appropriately.
  • I followed the AI Policy.

Your assigned reviewer(s) will follow our guidelines for code reviews.

@alberto-art3ch
alberto-art3ch marked this pull request as ready for review September 18, 2026 03:01

@galovics galovics left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change is additive and safe - no migration (the value is computed at read time), the Avro field is ["null","string"] with default: null, and delinquencyStartDate itself doesn't change behaviour (the code already returned the raw fromDate; the PR fixes the Swagger/adoc text that wrongly said grace was added). The date math checks out in the normal case: generateInitialPeriod adds the loan-level grace days to period 1's toDate and later periods chain from toDate + 1, so fromDate + grace is right, and the three integration test cases match.

The concern is that the field assumes period 1 always still carries the grace days, and that isn't true after a supported action:

  • A frequency reschedule while period 1 is still open re-dates the period through calculateRescheduledToDate (fromDate + frequency, extended by pauses), which never adds the grace days back. The schedule then has no grace, but resolveDelinquencyEffectiveStartDate still reports fromDate + graceDays - and if the new frequency is shorter than the grace, that lands after the new toDate. recalculatePeriodsForPauses and the breach side's naturalToDate both put the grace back, so the paths already disagree. Either re-apply grace for period 1 in the reschedule path or derive the value from the persisted bounds; either way please add an integration test for reschedule-in-period-1.
  • A pause overlapping the grace window stretches period 1's toDate but not the reported start. Is the grace supposed to be "paused" too? Needs a decision and a test (the same question applies to #6482).
  • The grace days are read from the loan at read time rather than from what the schedule used - fine as long as they can't change after disbursement, but a short comment would state that assumption.

Docs and tests: the Javadoc on resolveScheduleAnchorDate in the range schedule service still says grace is "added when the derived delinquencyStartDate is computed at read time", and the comment in WorkingCapitalBreachSchedule.feature ~L471 still says delinquencyStartDate = fromDate + delinquencyGraceDays, contradicting the scenario's own expected value. WorkingCapitalLoanStartDatesTest doesn't assert the effective date under the LOAN_CREATION anchor, and the mapper test/EventCheckHelper don't check the new Avro field.

Conflict with #6482: 3 files conflict (the adoc, the read service, WorkingCapitalLoanStartDatesTest), and resolveDelinquencyEffectiveStartDate is a copy of resolveBreachEffectiveStartDate with the types swapped. I'd merge the two together or agree an order and share one helper.

Recommendation: COMMENT

@alberto-art3ch
alberto-art3ch force-pushed the FINERACT-2455/working-capital-delinquency-effective-date branch from 9f28ec2 to d6c21f1 Compare September 24, 2026 03:46
@alberto-art3ch

Copy link
Copy Markdown
Contributor Author

The change is additive and safe - no migration (the value is computed at read time), the Avro field is ["null","string"] with default: null, and delinquencyStartDate itself doesn't change behaviour (the code already returned the raw fromDate; the PR fixes the Swagger/adoc text that wrongly said grace was added). The date math checks out in the normal case: generateInitialPeriod adds the loan-level grace days to period 1's toDate and later periods chain from toDate + 1, so fromDate + grace is right, and the three integration test cases match.

The concern is that the field assumes period 1 always still carries the grace days, and that isn't true after a supported action:

  • A frequency reschedule while period 1 is still open re-dates the period through calculateRescheduledToDate (fromDate + frequency, extended by pauses), which never adds the grace days back. The schedule then has no grace, but resolveDelinquencyEffectiveStartDate still reports fromDate + graceDays - and if the new frequency is shorter than the grace, that lands after the new toDate. recalculatePeriodsForPauses and the breach side's naturalToDate both put the grace back, so the paths already disagree. Either re-apply grace for period 1 in the reschedule path or derive the value from the persisted bounds; either way please add an integration test for reschedule-in-period-1.
  • A pause overlapping the grace window stretches period 1's toDate but not the reported start. Is the grace supposed to be "paused" too? Needs a decision and a test (the same question applies to FINERACT-2455: Working Capital - Breach Effective Date #6482).
  • The grace days are read from the loan at read time rather than from what the schedule used - fine as long as they can't change after disbursement, but a short comment would state that assumption.

Docs and tests: the Javadoc on resolveScheduleAnchorDate in the range schedule service still says grace is "added when the derived delinquencyStartDate is computed at read time", and the comment in WorkingCapitalBreachSchedule.feature ~L471 still says delinquencyStartDate = fromDate + delinquencyGraceDays, contradicting the scenario's own expected value. WorkingCapitalLoanStartDatesTest doesn't assert the effective date under the LOAN_CREATION anchor, and the mapper test/EventCheckHelper don't check the new Avro field.

Conflict with #6482: 3 files conflict (the adoc, the read service, WorkingCapitalLoanStartDatesTest), and resolveDelinquencyEffectiveStartDate is a copy of resolveBreachEffectiveStartDate with the types swapped. I'd merge the two together or agree an order and share one helper.

Recommendation: COMMENT

Good catch on the reschedule — period 1 was silently losing its grace days there (pre-existing, the new field only exposed it): generation, reschedule and the validator that guards it now share a calculateNaturalToDate that applies the grace to period 1 only, covered by a unit test and an integration test for reschedule-in-period-1.

Also fixed the stale javadoc and the feature-file comment, added the missing LOAN_CREATION and Avro assertions, and documented why the read-time grace lookup can't diverge: validateForUpdate rejects any change once the loan leaves submitted-and-pending-approval, and the schedule is only generated at disbursement.

On pauses, the current behaviour treats the cool off as calendar days from the anchor and does not pause it — happy to flip that if you think it should be paused; and once #6482 lands I'll extract the shared helper for both effective-start resolvers.

@alberto-art3ch
alberto-art3ch force-pushed the FINERACT-2455/working-capital-delinquency-effective-date branch from d6c21f1 to fb61c7a Compare September 24, 2026 03:55
@peter-kovacs-dpc
peter-kovacs-dpc force-pushed the FINERACT-2455/working-capital-delinquency-effective-date branch from e4c7c0c to d26d08e Compare September 28, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants