Aman-Mittal opened a new issue, #512:
URL: https://github.com/apache/fineract-backoffice-ui/issues/512

   ## What happens
   
   `/loans/{loanId}/interest-pauses/edit/:variationId` takes its id straight 
from the route:
   
   ```ts
   // 
src/app/features/loans/interest-pauses/interest-pause-form.component.ts:176
   if (variationId) {
     this.variationId = +variationId;
     this.isEditMode.set(true);
     this.loadPause();
   }
   ```
   
   The route has no constraint on the segment, so `edit/abc` gives `+'abc'` → 
`NaN`. From there two guards disagree with `isEditMode`, because `NaN` is falsy:
   
   ```ts
   private loadPause(): void {
     if (!this.loanId || !this.variationId) return;   // NaN → returns, form 
stays empty
   ```
   
   ```ts
   const save$ =
     this.isEditMode() && this.variationId              // NaN → falsy
       ? this.pauseService.putLoansLoanIdInterestPausesVariationId(...)
       : this.pauseService.postLoansLoanIdInterestPauses(this.loanId, request); 
 // ← taken
   ```
   
   So the header reads **Edit Interest Pause**, the pickers sit on today rather 
than on the stored pause, and pressing Save creates a second pause instead of 
correcting the first. Nothing on screen says so.
   
   ## Reproduced against a live platform
   
   Loan 26 on the local stack: progressive, interest-recalculating, one pause 
from 2026-08-17 to 2026-08-27.
   
   Navigating to `/loans/26/interest-pauses/edit/abc`:
   
   ![The edit screen with a NaN 
id](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/interest-pause-edit-nan-blank.png)
   
   Picking 1–5 September and saving produced exactly one request, and it is a 
create:
   
   ```
   POST /fineract-provider/api/v1/loans/26/interest-pauses
   {"startDate":"01 September 2026","endDate":"05 September 
2026","dateFormat":"dd MMMM yyyy","locale":"en"}
   ```
   
   No `PUT .../interest-pauses/{id}`, and no `GET` beforehand — `loadPause()` 
had already returned. The list afterwards:
   
   ![Two pauses where the user expected one 
edit](https://raw.githubusercontent.com/Aman-Mittal/fineract-backoffice-ui/assets/issue-screenshots/interest-pause-edit-nan-duplicated.png)
   
   [Screen 
recording](https://github.com/Aman-Mittal/fineract-backoffice-ui/raw/assets/issue-screenshots/interest-pause-edit-nan.webm).
   
   ## Why it matters
   
   An interest pause changes what a borrower owes. A user who reaches this 
screen from a stale link, a typo, or a bookmark that outlived a data reset gets 
a screen that claims to be editing and silently grants a *second* relief period 
on top of the first. The loan is then paused across two ranges the operator 
never agreed to, and on a recalculating loan that is a real schedule change, 
not a display artifact.
   
   The same shape applies to `0` and to any id the segment cannot parse.
   
   ## Suggested fix
   
   Reject an unusable id rather than falling through to create. Parse once, and 
let the rest of the component depend on that one decision:
   
   ```ts
   const parsed = Number(variationId);
   if (!Number.isInteger(parsed) || parsed <= 0) {
     // Not an id this screen can edit — send the user back to the list.
     void this.router.navigate(['/loans', this.loanId, 'interest-pauses']);
     return;
   }
   ```
   
   Whatever the handling, `isEditMode()` and the `save$` branch must not be 
able to disagree — the bug is that they are derived from the same value by two 
different truthiness rules. Deriving the mode from `variationId !== null` after 
validation removes the possibility.
   
   A route matcher constraining `:variationId` to digits would stop it earlier, 
and is worth doing as well as, not instead of, the guard.
   
   ## Regression guard
   
   A unit case asserting that a non-numeric route parameter does not call 
`postLoansLoanIdInterestPauses`. The existing spec already stubs 
`LoanInterestPauseService`, so this is one more case in the file, not new 
scaffolding.
   
   ## Environment
   
   `main` at `3c6d7479`. `apache/fineract:latest` via 
`deploy/docker-compose-e2e.yml`, driven through the UI with no API seeding of 
the request itself.
   
   Found while reviewing #283 / PR #481 after it merged.
   


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