adamsaghy commented on PR #6546:
URL: https://github.com/apache/fineract/pull/6546#issuecomment-5908531280

   @alberto-art3ch Please review below my concerns:
   
   ### 1. The schedule is wrong end to end, and CI shows it
   All 8 schedule-generation tests in the PR's own 
`LoanSemiMonthlyRepaymentScheduleTest` fail on MariaDB, MySQL and PostgreSQL. 
In every one, the first due date is **disbursement + 1 year**. For example, a 
loan disbursed on 02 Jan 2023 is expected to fall due on 2023-01-10 but falls 
due on 2024-01-02.
   
   - **Cause:** `LoanScheduleAssembler.deriveFirstRepaymentDate` (around line 
1195) branches on daily, weekly and monthly, and everything else falls into 
`else { // yearly loan } → seedDate.plusYears(repaymentEvery)`. The PR adds no 
semi-monthly branch, so the first repayment date is wrong before the new 
`SemiMonthlyScheduleDates.next()` is ever called.
   - **Why nothing caught it:** `SemiMonthlyScheduleDatesTest` passes, but it 
only tests the helper on its own.
   - **What this breaks in the spec:** Rule 6 (disbursed 12 Jan should give 15 
Jan; 20 Jan should give 1 Feb), Example 1, Example 2, and the acceptance 
criterion "two repayment dates per calendar month".
   - **When a first repayment date is supplied:** if the caller passes 
`repaymentsStartingFromDate`, that date is used as-is and is not moved onto a 
configured day.
   
   ### 2. The configuration doesn't match the spec
   | Spec | PR |
   |---|---|
   | Two fields: first day 1–28, second day 2–28 or "Last Day" | One field, 
`firstRepaymentDayOfMonth`, allowed 1–15. The second day is derived: 1→15, 
15→last day, anything else→day+15 |
   | Rule 1 (second > first) and Rule 3 (no duplicates) are checked on user 
input | Always true by construction, because there is no second field to 
validate |
   | Rule 2: second day must be 2–28 or Last Day | 
`firstRepaymentDayOfMonth=14` gives the **29th** in every month except non-leap 
February, which the spec disallows |
   
   The only pairs you can set are 1&15, 2&17 … 13&28, 14&29, and 15&Last. Many 
pairs the spec allows can't be configured at all: 1 & Last Day, 1 & 20, 10 & 
20, 5 & 25, 20 & Last Day, or any first day above 15. The spec's own examples 
(1&15, 15&Last, 10&25) happen to be reachable. This is a design choice the 
author needs to justify or change, not a bug.
   
   ### 3. What matches the spec
   - A new frequency type, `SEMI_MONTHLY(6)`, is added after `INVALID`, so 
existing rows are unaffected.
   - Last Day resolution is correct in the helper: 28/29 Feb, 30 Apr, 31 Jul 
(Rules 4 and 5, unit-tested).
   - 24 periods per year is used for the APR and periods-per-year calculations.
   - The existing daily, weekly, monthly and yearly paths look untouched. The 
switch statements that gained a `SEMI_MONTHLY` case either do nothing or throw 
on purpose.
   
   ### 4. Smaller gaps against the spec
   - **Progressive schedules are blocked, but only at product create.** 
`effectiveLoanScheduleType(element)` defaults to `CUMULATIVE` when 
`loanScheduleType` isn't in the request. So a `PUT` that sets only 
`repaymentFrequencyType=6` on an existing progressive product passes the check. 
The loan application validator has no such check at all. I haven't traced what 
the progressive engine then does. Note that the spec's "declining balance/EIR" 
wording implies progressive should be supported, not rejected.
   - **Spec Example 3 can't be entered as written.** `LoanScheduleValidator` 
requires `loanTermFrequencyType` to equal `repaymentFrequencyType`, so "Term 6 
Months, 12 installments" must be entered as a term of 12 semi-monthly periods.
   - **A loan's missing day is silently defaulted.** A loan can switch to 
`repaymentFrequencyType=6` without a `firstRepaymentDayOfMonth` (only the 
product validator requires it), and the code then quietly uses 15, i.e. the 
15th & last day.
   
   ### Suggested asks for the author
   1. Add semi-monthly handling to `deriveFirstRepaymentDate` and get the 
integration tests green.
   2. Either implement the spec's two fields (first 1–28, second 2–28 or Last 
Day, with validation for order and duplicates), or get the spec changed to the 
derived-day model. If the derived model stays, disallow 14, since it produces 
the 29th.
   3. Make the progressive guard use the product's stored schedule type on 
update, and add the same guard to the loan application.
   
   I reviewed the PR against its head commit in a temporary worktree; your 
current branch wasn't touched. I can post this as a PR comment if you want.
   


-- 
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]

Reply via email to