shivaansh0610-LUFFY opened a new pull request, #650:
URL: https://github.com/apache/fineract-backoffice-ui/pull/650

   <!--
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
   distributed with this work for additional information
   regarding copyright ownership.  The ASF licenses this file
   to you under the Apache License, Version 2.0 (the
   "License"); you may not use this file except in compliance
   with the License.  You may obtain a copy of the License at
   
     http://www.apache.org/licenses/LICENSE-2.0
   
   Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an
   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   KIND, either express or implied.  See the License for the
   specific language governing permissions and limitations
   under the License.
   -->
   
   <!-- Commits must be signed to merge — see CONTRIBUTING.md#commit-signing if 
you haven't set this up. -->
   
   ## What and why
   
   <!-- One or two sentences explaining what changed and why. -->
   
   A regular loan's Delinquency tab could only be read, while a Working Capital 
loan has a form for delinquency actions, so an institution could pause 
delinquency on one kind of loan and not on the other. Pausing is how arrears 
stop ageing during an agreed payment holiday or moratorium; without it those 
accounts keep moving through arrears buckets they should not be in. This adds 
**Pause Delinquency** and **Resume Delinquency** to the tab.
   
   Closes #505
   
   ### Only pause and resume, not the Working Capital set
   
   The issue points at the Working Capital form as the specification. That form 
submits seven actions (pause, resume, reschedule, reset, undo_reset, disable, 
enable), but `POST /loans/{id}/delinquency-actions` accepts exactly two, 
`pause` and `resume` (`DelinquencyActionParseAndValidator` in Fineract). 
Anything else is answered with 
`validation.msg.loanDelinquencyAction.action.invalid.action`, so offering the 
longer set would be a list of ways to get a 400. For the same reason the two 
screens do not share a component: the Working Capital one is a routed page with 
fields a regular loan has no use for, and the rules differ (a regular loan's 
resume must be dated the business date and carry no end date).
   
   ### The permission is `CREATE_DELINQUENCY_ACTION`
   
   The issue names `UPDATEDELINQUENCY_LOAN`, which is the permission for 
assigning a loan to a delinquency bucket (`assignDelinquency`). The 
delinquency-actions endpoint calls 
`validateHasCreatePermission("DELINQUENCY_ACTION")`, so the buttons are gated 
by `CREATE_DELINQUENCY_ACTION` (seeded by Fineract changelog 0130). Gating on 
the other one would show the actions to people the platform then refuses, and 
hide them from people it would accept.
   
   ### Changes
   
   - **Pause Delinquency** opens a dialog for the period. The start defaults to 
the platform's business date, not the browser's clock, which differs on a 
tenant whose business date has moved. The only local rule is that the pause 
ends after it starts, which is also the platform's rule ("must last at least a 
day"). Everything else the platform enforces (active loan, start not before 
disbursement, no overlap with another pause) depends on state the dialog does 
not hold, so the platform's own message is shown.
   - **Resume Delinquency** asks for confirmation, naming the date, and sends 
`action: resume` dated the business date with no end date. The platform 
requires exactly that and answers an `endDate` with a 400.
   - Both appear only on an active loan, and only to someone holding 
`CREATE_DELINQUENCY_ACTION`.
   - Resume is offered only when a pause is in effect **and still has days left 
after today**. A period's `active` flag includes its last day, and a resume 
moves the pause's end to the resume date, so straight after resuming the period 
still reads as active until the business date moves on. Offering Resume then 
would be an offer the platform refuses ("There is an existing Resume 
Delinquency Action on this date"). Without a business date the tab does not 
offer Resume at all, rather than dating it by guesswork.
   - After a successful action the tab tells the loan view, which re-reads the 
loan the summary comes from.
   - The business date is read in the background with the error toast skipped: 
it only dates a pause and decides whether Resume can be offered, so its failure 
must not put the tables into their error state, and the header already reports 
its own.
   - `en.json` gets the new `LOANS.*` keys, and `api-surface.json` records the 
new call.
   
   ### Also on this tab
   
   The tab read each pause period's dates from `startDate` / `endDate`, but 
Fineract sends `pausePeriodStart` / `pausePeriodEnd`, so against a real 
platform the pause table had blank dates and showed `true` / `false` as the 
status. Seeing the result of a pause depends on that table, so it is fixed 
here. Fineract also sends `LocalDate` as `[year, month, day]` (the generated 
model says string), so every other date on the tab printed as `2026,10,15`; the 
summary and tag dates now go through the same reader. It is the same screen and 
the same cause, but it is separable if you would rather have it as its own 
change.
   
   ### Not in this PR
   
   - Reschedule, reset, undo reset, disable and enable: the platform has no 
such actions for a regular loan.
   - A real-Fineract e2e spec (see Verification).
   
   ## Verification
   
   <!-- List what you ran and what you checked. Note whether the UI was 
exercised with mocks, a real Fineract backend, or both. -->
   
   Exercised against mocks. **Not run against a real Fineract**, so there is no 
`backend` project spec in this PR; the rules above come from Fineract's source 
and its Pause Delinquency documentation, not from a live platform. The mocks 
use the shapes Fineract actually sends (date arrays, `pausePeriodStart` / 
`pausePeriodEnd`) and compute a period's `active` with the platform's rule, so 
a pause starting today is in effect today and a resumed pause stays in effect 
until the date moves on.
   
   - `npm run lint`, `format:check`, `i18n:check`, `check:icons`, 
`check:a11y-names`, `check:ui-primitives`, `check:responsive`, `api:surface`, 
`typecheck:e2e`, `build`: pass
   - `npm run test:unit`: 266 files, 1753 tests pass. New coverage: the date 
reader and the resume rule, the pause dialog, and the tab (permission and 
loan-state gating, the request sent for pause and for resume, nothing sent when 
cancelled, a refused request reporting no change, no Resume without a business 
date).
   - `e2e/loan-delinquency-actions.spec.ts` (new, mocked): 11 tests pass. Dates 
read as dates under the real fields; pause from the business date with the 
request asserted; a pause that ends on or before its start is refused in the 
dialog; cancel sends nothing; a platform refusal shows its own reason and 
leaves the screen usable; resume sends the business date and no end date; 
Resume goes once the pause has been ended; no Resume when nothing is paused; no 
actions without `CREATE_DELINQUENCY_ACTION`; none on a closed loan. Run 
together with `loan-servicing-gaps.spec.ts`: 29 passed.
   - axe on the pause dialog (with its error showing) and on the action 
buttons: no violations once the dialog's open animation has finished.
   
   ## Screenshots
   
   <!-- Add screenshots or a short recording for UI changes. Write "Not 
applicable" for non-UI changes. -->
   
   Same script, same mocked data, before (`main`) and after.
   
   ### Before
   
   <img width="1440" height="1100" alt="before-01-delinquency-tab" 
src="https://github.com/user-attachments/assets/0f322554-7b7f-4ec1-b6a1-5f83f64b4932";
 />
   
   
   
https://github.com/user-attachments/assets/0d25a24d-b61a-4622-b35e-26017565bd92
   
   
   ### After
   
   <img width="1440" height="1100" alt="after-02-pause-dialog" 
src="https://github.com/user-attachments/assets/843625ab-c081-4943-9587-09c84586a9cd";
 />
   
   <img width="1440" height="1100" alt="after-03-pause-dialog-end-before-start" 
src="https://github.com/user-attachments/assets/4ecc5998-f6a4-420c-b359-74b5f1d56b84";
 />
   
   <img width="1440" height="1100" alt="after-04-pause-dialog-filled" 
src="https://github.com/user-attachments/assets/9c74af79-def7-4511-ad0c-994ab7c030bc";
 />
   
   <img width="1440" height="1100" alt="after-05-after-pause" 
src="https://github.com/user-attachments/assets/5934e25a-4ce9-4910-a690-006fd303d278";
 />
   
   <img width="1440" height="1100" alt="after-06-resume-confirmation" 
src="https://github.com/user-attachments/assets/ed17c9b5-41cd-402a-8db2-bf8789d1dded";
 />
   
   <img width="1440" height="1100" alt="after-07-after-resume" 
src="https://github.com/user-attachments/assets/30bcd0d4-3061-42b3-bb62-a28d3e276764";
 />
   
   <img width="1440" height="1100" alt="after-08-without-permission" 
src="https://github.com/user-attachments/assets/7ce5e0c7-5dfc-4c0f-be0e-7a6a2488466d";
 />
   
   <img width="1440" height="1100" alt="after-01-delinquency-tab" 
src="https://github.com/user-attachments/assets/270506f0-8335-4788-be88-4b8f42632e79";
 />
   
   
https://github.com/user-attachments/assets/3a5b9d90-5dc9-476b-a5ce-49f9d6f0d00a
   
   ### Recording
   
   
   
https://github.com/user-attachments/assets/f4f4af12-9100-4ef8-97a2-77007557a41b
   
   ## AI assistance (optional)
   
   <!-- If generative AI materially assisted this contribution, optionally 
state the tool or model and
   the harness or workflow used. The contributor remains responsible for the 
submitted change. -->
   
   - Tool / model:
   - Harness / workflow:
   
   ## Checklist
   
   <!-- Check each item, or explain why it does not apply. -->
   
   - [x] I did not hand-edit generated files under `src/app/api/`.
   - [x] New component or service code uses the adapter boundary in 
`src/app/core/adapters/` instead of direct browser globals or imperative 
third-party APIs.
   - [x] User-facing strings use translation keys.
   - [x] I added or updated tests appropriate to this change, or explained why 
tests were not needed.
   - [ ] UI workflow changes include suitable e2e coverage, including 
real-backend testing where relevant. (Mocked e2e added; no real-backend spec, 
see Verification.)
   - [ ] Commits are signed — see [Commit 
Signing](CONTRIBUTING.md#commit-signing) in CONTRIBUTING.md.
   - [ ] I followed the [AI-assisted contributions 
guidance](CONTRIBUTING.md#ai-assisted-contributions).
   


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