mariiaKraievska commented on code in PR #6770: URL: https://github.com/apache/fineract/pull/6770#discussion_r4410471910
########## fineract-doc/src/docs/en/chapters/features/monthly-repayment-due-date-strategy.adoc: ########## @@ -0,0 +1,163 @@ + += Monthly Repayment Due Date Strategy +:toc: +:toclevels: 2 + +https://issues.apache.org/jira/browse/FINERACT-2816[FINERACT-2816] + +== Goal + +Apache Fineract currently adjusts monthly repayment due dates to the last day of the month when the original repayment day does not exist. + +For example, a loan disbursed on *30 January* with monthly repayments has its first repayment due on *28 February*. + +The goal is to introduce a configurable loan product strategy that allows the repayment due date to roll forward to the *first day of the following month* (1 March in this example), while preserving the original repayment day for subsequent installments. + +The functionality must support both *cumulative* and *progressive* loan schedules and respect the configured interest calculation convention: + +* *360/30:* Interest per regular monthly period remains unchanged under the specified monthly convention. +* *Actual/Actual:* Interest reflects the actual number of calendar days between repayment dates. + +== Requirements + +=== Functional Requirements + +==== Repayment Due Date Configuration + +Introduce a new loan product attribute: `monthEndDueDateStrategy`. + +Supported values: + +* `LAST_DAY_OF_MONTH` (default): Use the last day of the target month when the original repayment day does not exist. +* `FIRST_DAY_OF_NEXT_MONTH`: Roll the repayment due date to the first day of the following month. + +The functionality must: + +* Apply to monthly repayment frequencies only. +* Support cumulative and progressive loan schedules. +* Preserve the original repayment day for subsequent installments. +* Apply to all repayment periods, including the final installment. +* Respect existing meeting calendar, holiday, and working-day adjustment rules. + +==== Repayment Date Example + +Loan disbursed on 30 January 2025 with monthly repayments: + +[cols="1,2,2",options="header"] +|=== +|Period |LAST_DAY_OF_MONTH |FIRST_DAY_OF_NEXT_MONTH + +|1 |28 February |1 March +|2 |30 March |30 March +|3 |30 April |30 April +|=== + +==== Interest Calculation — 360/30 + +Given a loan product configured with 360 days per year and 30 days per month, rolling a repayment date must not change the interest calculated for each regular monthly period under the specified 360/30 convention. + +[cols="1,2,2,1",options="header"] +|=== +|Period |LAST_DAY_OF_MONTH |FIRST_DAY_OF_NEXT_MONTH |Interest fraction + +|1 |30 Jan - 28 Feb |30 Jan - 1 Mar |30/360 +|2 |28 Feb - 30 Mar |1 Mar - 30 Mar |30/360 +|=== + +*Expected result:* Interest per period remains unchanged, assuming equivalent outstanding principal balances. + +==== Interest Calculation — Actual/Actual + +Given a loan product configured with Actual/Actual, interest must be calculated using the actual number of calendar days between repayment dates. + +[cols="1,2,2",options="header"] +|=== +|Period |LAST_DAY_OF_MONTH |FIRST_DAY_OF_NEXT_MONTH + +|1 |29/365 (30 Jan - 28 Feb) |30/365 (30 Jan - 1 Mar) +|2 |30/365 (28 Feb - 30 Mar) |29/365 (1 Mar - 30 Mar) +|=== + +*Expected result:* + +* The first period accrues one additional day of interest on the higher outstanding principal balance. +* The second period accrues one fewer day of interest on the reduced outstanding principal balance. +* Total interest may increase because interest is calculated on different outstanding principal balances. + +==== API and Persistence + +* Expose `monthEndDueDateStrategy` in loan product create, update, read, and template APIs. +* Store the configured strategy on both the loan product and loan account. +* Loan accounts must inherit the strategy from the loan product at submission. +* Changing the loan product configuration must not affect existing loans. +* Schedule regeneration and interest recalculation must reuse the strategy stored on the loan account. + +=== Non-Functional Requirements + +* *Backward compatibility:* Existing loan products and loans must retain their current repayment schedules and interest calculations. +* *Financial accuracy:* The new strategy must respect existing day-count conventions, rounding rules, and principal-interest allocation. +* *Consistency:* Initial schedule generation, rescheduling, fixed-length maturity calculations, and holiday processing must apply the strategy consistently. +* *Test coverage:* Automated tests must cover both schedule types, leap years, month-end dates, 360/30, Actual/Actual, and schedule regeneration. +* *Performance:* The new configuration must not introduce significant overhead during repayment schedule generation. + +== Configuration + +=== Loan Product Attribute + +The repayment due date strategy is configured at the loan product level using the `monthEndDueDateStrategy` attribute. + +=== Available Values + +[cols="1,2",options="header"] +|=== +|Value |Description + +|`LAST_DAY_OF_MONTH` +|Moves the repayment due date to the last day of the target month when the original repayment day does not exist. This is the default behavior. + +|`FIRST_DAY_OF_NEXT_MONTH` +|Moves the repayment due date to the first day of the following month when the original repayment day does not exist. +|=== + +=== Example Loan Product Configuration + +[source,json] +---- +{ + "repaymentEvery": 1, + "repaymentFrequencyType": 2, + "monthEndDueDateStrategy": "FIRST_DAY_OF_NEXT_MONTH" +} +---- + +The example contains only the relevant configuration attributes, not a complete loan product creation request. + +=== Configuration Rules + +* The default strategy is `LAST_DAY_OF_MONTH`. +* The configuration applies only to monthly repayment frequencies. +* Both cumulative and progressive loan products are supported. +* The strategy applies to all repayment due dates, including the final installment. +* The original repayment anchor day is preserved. +* Loan accounts inherit the strategy from the loan product at submission. +* Changing the loan product configuration does not affect existing loans. +* Schedule regeneration uses the strategy stored on the loan account. +* Meeting calendars take precedence over the configured strategy. +* Existing working-day and holiday adjustments continue to apply. + +=== Interaction with Interest Calculation + +The `monthEndDueDateStrategy` attribute controls repayment due dates and does not modify the loan product's interest calculation configuration. + +[cols="1,2",options="header"] +|=== +|Day-count convention |Expected behavior + +|360/30 +|Interest per regular monthly period remains unchanged under the specified 30/360 monthly convention. + +|Actual/Actual +|Interest is calculated using the actual calendar days between consecutive repayment dates. Rolling a due date can change the interest amount. +|=== + +NOTE: The expected 360/30 behavior must be verified against Fineract's day-count implementation, especially for periods such as 1 March to 30 March. Review Comment: Could you take another look at this NOTE? The 30/360 behaviour above already looks asserted, and MonthEndDueDateStrategyTest.testRolledDueDateKeepsInterestPerPeriodUnder30360 covers this case (30 Jan disbursement with FIRST_DAY_OF_NEXT_MONTH, including the 1 Mar → 30 Mar period, under days-in-month/year 30/360). If that’s right, it might be clearer to drop the “must be verified” hedge — but please correct me if I’m missing something. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
