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

   ### Summary
   Save buttons don't guard against a second click while the first request is 
in flight. One double-click submits the form twice. On the loan **Repayment** 
form both requests succeeded, so **two repayments were posted for one 
payment**. The same happened on **Create Client** (two clients created) and on 
loan **Approve** (second request refused only because the loan was already 
approved).
   
   ### Environment
   - App: https://aman-mittal.github.io/fineract-backoffice-ui (deployed `main`)
   - Backend: `sandbox.mifos.community`, tenant `default` (demo server, test 
data prefixed `E2E-AUDIT-20261016`)
   - Role: superuser
   - Chrome (Playwright) 1440×900, 2026-10-16
   
   ### Preconditions
   An active loan. Here: loan `000000002` (product `E2E-AUDIT-20261016 Monthly 
Loan`, 10,000 disbursed) for client `E2EAudit ClientOne`.
   
   ### Steps to reproduce
   1. Open the loan → **Repayment**.
   2. Enter amount `100`, choose a payment type.
   3. **Double-click** Save.
   
   ### Expected behavior
   Exactly one `POST /loans/{id}/transactions?command=repayment`. The Save 
button is disabled (with a busy indicator) from the first click until the 
response arrives.
   
   ### Actual behavior
   Two POSTs, both **200**:
   
   ```
   POST /loans/2/transactions?command=repayment → 200  resourceId 5
   POST /loans/2/transactions?command=repayment → 200  resourceId 6
   ```
   
   `GET /loans/2?associations=transactions` afterwards: two `Repayment` 
transactions of 100.00 on 2026-10-15, `summary.totalRepayment = 200`, 
outstanding reduced by 200.
   
   The same pattern, one double-click each:
   
   | Form | Requests | Outcome |
   |---|---|---|
   | Create Client (`/clients/create`, step 3) | `POST /clients` ×2 → **200, 
200** | Two clients created (ids 3 and 4, both "E2EAudit DoubleSubmit") |
   | Loan Approve (`/products/loan/2/action/approve`) | `POST 
/loans/2?command=approve` → 200, then → **400** | Second refused by the 
platform only because the state had changed |
   | Loan Repayment | ×2 → **200, 200** | Double-posted payment |
   
   ### Evidence
   Request/response pairs above, captured from the browser's network events. 
The duplicate repayment (#6) was reversed afterwards via Adjust Transaction 
(amount 0) to restore the loan.
   
   ### Impact
   - **Financial integrity.** A cashier who double-clicks, or clicks again 
because the UI looked unresponsive, posts the payment twice. The borrower's 
balance and the GL are both wrong, and someone has to notice and reverse it. 
Deposits, withdrawals, disbursement-to-savings and transfers all go through the 
same kind of form and are presumably affected in the same way (not individually 
tested).
   - **Duplicate master data.** Duplicate clients break KYC uniqueness and 
reporting.
   - Commands guarded by a state transition (approve, disburse) are protected 
by the platform by accident. Monetary transactions aren't, because each one is 
valid on its own.
   
   ### Suggested investigation
   A shared fix at the form or button level: an `inFlight` signal that disables 
the submit control from click until the request completes or fails, plus 
ignoring re-entrant submits in the submit handler (Enter key, programmatic 
clicks). Ideally it lives in a shared submit-button primitive (see #684) so 
every form gets it. For monetary commands, consider sending a client-generated 
idempotency key where Fineract supports it (`Idempotency-Key` header on command 
endpoints in recent versions), so a retry can't double-post even across network 
retries.
   
   ### Verification status
   Reproduced on three forms. Deposit, withdrawal and transfer forms not 
individually tested.
   
   ### Related endpoints
   `POST /loans/{id}/transactions?command=repayment`, `POST /clients`, `POST 
/loans/{id}?command=approve`, and by extension every command endpoint.
   
   ### Acceptance criteria
   - A double-click (and Enter pressed twice) on any create, command or 
transaction form produces exactly one request.
   - The submit control shows a busy state and is disabled while a request is 
in flight, and re-enabled on error.
   - An e2e test double-clicks Save on the repayment form and asserts a single 
`POST`.
   
   ### Related issues
   #684 (shared UI primitives).


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