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

   ## Business value
   
   An officer opens a dialog, accepts the date the application already filled 
in, clicks Confirm — and the platform refuses it. The date they never touched 
is wrong, and nothing on screen says so.
   
   For roughly five and a half hours of every day, a branch working in a 
timezone ahead of the tenant's sees actions fail for no reason it can act on. 
The refusals are the confusing kind — *"Submitted on date cannot be after the 
activation date"* — naming a date the user did not enter and cannot see. The 
workaround is to open the picker and choose yesterday, which no one will 
discover, and which is indistinguishable from data entry error when it shows up 
later in an audit.
   
   It also silently damages the ledger's meaning. Where the platform *accepts* 
the browser's date, the record is stamped with a day the institution was not 
working — a client activated "tomorrow", a transaction dated a day out. That is 
worse than a refusal, because nothing fails.
   
   This is not hypothetical. It reproduces on demand, and it is currently the 
cause of an intermittent CI failure (see below).
   
   ## What is wrong
   
   Fineract stamps and validates dates using the **tenant's** timezone — 
`m_tenants.timezone_id`, which its seed data sets to `Asia/Kolkata`. The 
application fills date fields from the **browser's** clock:
   
   ```ts
   // e.g. src/app/features/centers/center-action-dialog.component.ts
   date = new Date().toISOString();
   
   // src/app/core/utils/date-formatter.ts — local components, deliberately
   const day = String(d.getDate()).padStart(2, '0');
   const month = MONTHS[d.getMonth()];
   const year = d.getFullYear();
   ```
   
   Between **18:30 and 24:00 UTC** a UTC browser and an `Asia/Kolkata` tenant 
are a day apart, so the two disagree about what "today" is.
   
   ## Reproduction
   
   With the e2e stack up and the wall clock between 18:30 and 24:00 UTC:
   
   ```bash
   TZ=UTC npx playwright test e2e/center-servicing.spec.ts --project=backend -g 
"activated"
   ```
   
   The centre is created (Fineract stamps `submittedOnDate` as the *tenant's* 
today), the UI offers the *browser's* today as the activation date, and the 
platform answers:
   
   ```json
   {
     "httpStatusCode": "400",
     "errors": [{
       "userMessageGlobalisationCode": 
"error.msg.group.submittedOnDate.after.activation.date",
       "defaultUserMessage": "Submitted on date cannot be after the activation 
date",
       "parameterName": "submittedOnDate",
       "args": [{ "value": "2026-08-16" }]
     }]
   }
   ```
   
   The same run passes from a machine already in `Asia/Kolkata`, and passes at 
any hour outside that window — which is exactly what makes it hard to see.
   
   ## Scope of the problem
   
   This is not specific to centres. Every dialog that seeds a date from `new 
Date()` is affected — activation, closure, transaction, disbursal, repayment 
and the rest. Centres are simply where it surfaced, because activation is 
validated against a date the platform stamped moments earlier.
   
   ## What to build
   
   Default date fields from the **platform's** notion of today rather than the 
browser's.
   
   The application already displays a business date in the header, so the 
platform's date is available to the client — that is the value these pickers 
should open on. `GET /v1/businessdate` returns the configured business date 
when the tenant has one; note it answers `[]` when none is configured, so a 
fallback is still needed and it should be the tenant's current date, not the 
browser's.
   
   Suggested shape:
   
   - A single service that answers "what is today, according to the platform", 
with the browser's clock as a last resort.
   - Date dialogs seed from it instead of `new Date()`.
   - `formatDateToFineract` keeps formatting local components — the fix belongs 
at the source of the value, not in the formatter, so that a date a user 
genuinely picked is still sent as picked.
   
   ### Two things to get right
   
   1. **Do not simply switch the formatter to UTC.** That trades one wrong 
answer for another: a user who explicitly picks a date would then have it 
shifted a day. The defect is in what the field is *seeded* with.
   2. **A refused date must say which date was refused.** Today the dialog 
closes and the record silently stays in its previous state; the platform's 
message names a date the user never saw. Surfacing the platform's error is part 
of this fix.
   
   ## Testing
   
   - **Unit:** a dialog seeds its date from the platform date service, not `new 
Date()`.
   - **Unit:** with the platform a day ahead of the browser, the submitted 
payload carries the platform's date.
   - **Backend e2e:** the `TZ=UTC` reproduction above should pass on its own 
merits, without the harness pinning the browser timezone.
   
   ## Relationship to the CI harness
   
   `playwright.config.ts` pins the browser timezone to the tenant's so the 
suite stops depending on the hour it runs at. **That makes the harness 
deterministic; it does not fix this.** When this issue is resolved, that pin 
should be removed — and its removal is a good confirmation that the fix is real.
   
   ## Getting started
   
   - `src/app/core/utils/date-formatter.ts` — `formatDateToFineract`, and the 
`FINERACT_DATE_FORMAT`/`FINERACT_LOCALE` constants
   - `src/app/features/centers/center-action-dialog.component.ts` — a small, 
clear example of the seeding pattern
   - The business-date indicator in the application header, for where the 
platform date is already read
   - `npm test`, `npm run lint`, `npm run build`
   


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