Aman-Mittal opened a new pull request, #811:
URL: https://github.com/apache/fineract-backoffice-ui/pull/811
Closes #756, #758, #761, #763.
Four defects that are one subject: what a form sends, and what the screen
does while it is
sending or after it fails. Two of them move money to the wrong place.
Everything below was
measured against a running `apache/fineract:latest` before it was written,
and both e2e tests
were checked to fail without the fix.
## #756 — a double-click posted two repayments
One double-click on the loan repayment form posted twice, both `200`: the
borrower's balance and
the GL each wrong by the payment, and someone had to notice and reverse one.
Create Client made
two clients the same way. Approve and disburse escaped only because the
platform refuses the
second one once the state has moved; a monetary command has no such accident
to rely on.
The forms do set an `isSaving` flag and bind it to `[disabled]`, which is
not a guard — the
second click, and a second Enter, land before the flag reaches the DOM.
Ninety-nine components
carry such a flag and one re-checks it in its handler, so this is fixed
once, in the HTTP layer:
- **identical mutating requests in flight are collapsed** — the second
caller gets the first
request's response and no second request is issued. The window is the
first request's flight,
not a timed cache, so two *deliberate* identical submissions stay two
requests;
- **every mutating request carries an idempotency key**, which this platform
honours. Measured:
two repayments with the same `Idempotency-Key` produced **one**
transaction and returned the
same `resourceId` twice, and two keyed `POST /clients` produced one client
where the keyless
pair produced two. So a duplicate that does leave the browser cannot
double-post either.
This is the application's half of what the existing `IDEMPOTENT` context
token already describes.
Nothing here opts commands into retrying — that stays a call-site decision.
## #758 — dates defaulted to the browser's today, and were refused
`PlatformDateService` already existed for this, used by exactly one dialog,
while five places
read `GET /businessdate` for themselves. It is now the one source, and right
about two things it
had wrong:
- **it asks whether the business date governs.** Those rows persist after
the feature is switched
off and stop being maintained — measured, a tenant with it disabled still
reported
`BUSINESS_DATE 2026-10-17` on the 18th, and `POST /businessdate` refused
to move it with
`business.date.is.not.enabled`. Screens reading it unasked seeded a day in
the past; the header
announced a business date that governed nothing;
- **it no longer invents a timezone.** The fallback assumed `Asia/Kolkata`
when none was
configured — a date up to a day away from the platform's for any other
tenant. Today now comes
from the platform's own clock, read off the `Date` header every response
already carries, with a
configured `tenantTimezone` applied to *that* instant rather than the
browser's.
Worth recording: `GET /loans/template` reports `expectedDisbursementDate` as
the business date,
while `GET /clients/template` reports `activationDate` as the **system**
date — which under a
business date of the 10th is the 18th, and is refused. So the client form
cannot simply trust its
own template, and the shared source is consulted either way.
Seven forms now seed from it (client, loan, savings account, both deposit
accounts, group,
centre), and four screens read the business date through it instead of
fetching it themselves.
## #761 — every savings account was opened at 0%
The Interest Rate field started at `0` and never moved when a product was
chosen, and the form
sent it on every submit. Fineract reads a rate in the request as an
account-level **override**,
so a 5% product opened an account paying nothing and nobody finds out until
interest posting.
The rate now comes from the product the user picked, out of the `GET
/savingsproducts` list the
form already loads — measured, a product configured at 3.75% reports 3.75
there, so no extra
request is needed. With no rate known the field is **omitted**, which is how
the platform is
asked to apply the product's own rate, and a rate the user types still
stands, including a
deliberate 0%.
(The deposit product lists are the opposite case: they report `0` for every
product because a
term deposit's rate lives in its chart. Same field name, opposite meaning.)
## #763 — a failed savings load rendered an empty page
The view wrapped its template in `@if (account())` and reported failure
through a toast that had
already gone, so an outage left the breadcrumb and nothing else. It now uses
the shared
load-error state with a Try again that re-reads, a separate branch for a 404
or 403 where
retrying cannot succeed, and a spinner while the read is in flight. The
deposit account view had
the same gap — it even held a `hasError` boolean no part of its template
read — and is fixed with
it.
## Verification
- **2477 unit tests / 308 files**, green in UTC and in `America/New_York`;
`test:mfe` green
- **new backend e2e**: a double-click on the repayment form issues one POST
and leaves one
transaction; a client is created once; and with the browser clock a day
ahead, Create Client
submits with untouched defaults. Each was run with its fix removed and
fails then — 2 requests,
and a form that never leaves `/clients/create`
- mocked and date-sensitive backend slices green; `lint`, `lint:prune`,
`prettier --check`,
`check-api-surface` and the translation check all exit 0
## Not covered
The remaining ~35 `new Date()` seeds are dialogs, report filters and charge
due dates rather than
the create and submit paths; they now have a shared source to move to.
`client-form.component.test.ts`
has a pre-existing 10s `beforeEach` budget that its Ionic wizard exceeds
when the machine is
busy — it fails on a loaded machine on `main` as well as here, and passes
idle; worth its own
issue.
--
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]