You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@fineract.apache.org by "Aman-Mittal (via GitHub)" <gi...@apache.org> on 2026/08/15 19:12:43 UTC

[I] Date fields default to the browser's timezone while Fineract validates in the tenant's, so users outside the tenant zone are refused for dates they never chose [fineract-backoffice-ui]

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: issues-unsubscribe@fineract.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Date fields default to the browser's timezone while Fineract validates in the tenant's, so users outside the tenant zone are refused for dates they never chose [fineract-backoffice-ui]

Posted by "Aman-Mittal (via GitHub)" <gi...@apache.org>.
Aman-Mittal closed issue #358: Date fields default to the browser's timezone while Fineract validates in the tenant's, so users outside the tenant zone are refused for dates they never chose
URL: https://github.com/apache/fineract-backoffice-ui/issues/358


-- 
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: issues-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org