Repository navigation
fix(#11423): centralize locale-independent date strings - #11451
pinankshah8-Aa wants to merge 6 commits into
Conversation
|
All checks passed — thank you @pinankshah8-Aa! This PR is ready for review. |
|
Hi, the ci-integration-sentinel-k3d job failed in the existing circular client-side muting test at tests/integration/sentinel/transitions/muting.spec.js:1989. The other 173 Sentinel tests passed, and PR #11451 does not modify Sentinel or muting-related code. I don’t have permission to rerun the upstream workflow. Could a maintainer please rerun the failed job when convenient? Failed job: https://github.com/medic/cht-core/actions/runs/35777669176/job/107042181009?pr=11451 |
|
Hi, following up on the September 23 rerun request. The PR remains open and mergeable, and the Conventional Commits, CodeQL, and zizmor workflows passed. The remaining Build and test failure is still the existing Could a maintainer please rerun the failed job or let me know if any additional action is needed from me? |
binokaryg
left a comment
There was a problem hiding this comment.
Thanks @pinankshah8-Aa, this follows the agreed split closely and the parity tests between the writer in provider-wireup and the readers in the webapp and the DHIS export are exactly what I hoped for. Two things need a change before merge, and a few smaller notes added in-line.
| } catch { | ||
| return gregorianTag; |
There was a problem hiding this comment.
Before this PR only provider-wireup.getTargetDocTag had a fallback, and it logged a console.warn when toBik threw. The webapp's getTargetIntervalTag and the DHIS targetDocsInMonth had no fallback and would throw.
The new helper catches everything and returns the Gregorian tag with no log line, so all three call sites lose the signal. The worst case is the DHIS export: if toBik fails for the requested month, the export now returns a well-formed payload with every value at 0 instead of an error.
For the webapp, the writer and the reader could end up on different calendars for one month and nothing would tell us.
Could you keep the warning inside the helper so every caller gets it? I would also consider letting the DHIS export surface the error rather than fall back, since a wrong export is worse than a failed one, but the log line is the minimum.
There was a problem hiding this comment.
Fixed in bca53db. The shared helper now preserves the Gregorian fallback and emits a warning with the conversion error, so all callers retain the diagnostic signal. I also added an assertion that the warning is emitted.
| dataSet, | ||
| completeDate: moment().format('YYYY-MM-DD'), | ||
| completeDate: CalendarInterval.toLocalIsoDate(moment()), | ||
| period: moment(from).format('YYYYMM'), |
There was a problem hiding this comment.
completeDate moved to toLocalIsoDate, but the line below it is still moment(from).format('YYYYMM').
With the ne locale active that produces २०२५०३, which DHIS2 will reject.
The new regression test does not catch this because its postformat only rewrites strings that contain a -, and YYYYMM has none.
Please route period through .locale('en') as well, or add a YYYYMM variant to the helper, and drop the includes('-') guard from the test so it covers the whole payload. (api/tests/mocha/services/export/dhis.spec.js, line 113)
There was a problem hiding this comment.
Fixed in bca53db. The period now formats with the English locale, and the regression locale now postformats every numeric string, including YYYYMM, so the expected payload verifies both completeDate and period remain ASCII.
| } else { | ||
| interval = moment(timestamp).format('YYYY-MM'); | ||
| } | ||
| const interval = CalendarInterval.getIntervalTag({ end: timestamp }, useBikramSambatMonths); |
There was a problem hiding this comment.
Not blocking: getIntervalTag takes an interval but only reads interval.end, which is why dhis.js has to build a fake { end: timestamp }. Taking the end timestamp directly would make the signature honest and remove the { end: number } type in the webapp service.
Also applies to: shared-libs/calendar-interval/src/index.js, line 146
|
|
||
| /** Formats the end month of an interval as an ASCII Gregorian or Bikram Sambat tag. */ | ||
| const getIntervalTag = (interval, useBikramSambatMonths) => { | ||
| const gregorianTag = moment(interval.end).locale('en').format('YYYY-MM'); |
There was a problem hiding this comment.
Not blocking: An invalid interval.end makes the Gregorian fallback the literal string Invalid date, which then becomes part of the allDocs range key. Returning undefined or throwing would be safer than querying target~Invalid date~.
| chai.expect(service.getIntervalTag(interval, true)).to.equal('2081-11'); | ||
| }); | ||
|
|
||
| it('falls back to the Gregorian tag for an out-of-range Bikram Sambat date', () => { |
There was a problem hiding this comment.
Non-blocking: The out-of-range fallback test uses 2150-05-15 as a date the bikram-sambat table does not cover. A future upgrade of that package could extend the table and break the test with no change here. The next test already stubs toBik to throw, so this one could do the same, or use a date before the Bikram Sambat epoch.
Signed-off-by: Pinank Shah <226854365+pinankshah8-Aa@users.noreply.github.com>
Signed-off-by: Pinank Shah <226854365+pinankshah8-Aa@users.noreply.github.com>
|
Hi @binokaryg, I’ve addressed the remaining review notes in 7a33722, including the direct timestamp signature, invalid-timestamp handling, and deterministic fallback coverage. All current workflows now pass, including the full Build and test workflow. When convenient, could you please re-review the updated PR? |
|
Hi @binokaryg, following up on the requested changes addressed in |
binokaryg
left a comment
There was a problem hiding this comment.
Thanks @pinankshah8-Aa, all five points from the first round are addressed and I am happy to approve.
Two cosmetic nits are in-line, neither should hold up the merge. One more note for the display follow-up PR rather than this one:
getReportingMonth in webapp/src/ts/services/rules-engine.service.ts (lines 638-639) parses whatever tag comes back as a Bikram Sambat month. Now that the helper falls back instead of throwing, a Gregorian tag's month would be read as a Bikram Sambat month index and show the wrong month name, where before the throw landed on the subtitle at line 644. This only happens when toBik fails, which for the current table means dates before about 1943 or after 2034, so nothing today. Since it is display behaviour, I would rather handle it in the display follow-up PR, for example by having the helper also say which calendar it used, or by checking the tag's year there.
| sinon.stub(rulesStateStore, 'getUseBikramSambatMonths').returns(true); | ||
| const bikramSambat = require('bikram-sambat'); | ||
| const toBik = sinon.stub(bikramSambat, 'toBik').throws(new Error('invalid date')); | ||
| const warning = sinon.stub(console, 'warn'); |
There was a problem hiding this comment.
nit: The console.warn stub and its assertion were removed from this test, so the fallback warning and its stack now print in the middle of the rules-engine run. The same happens for the new out-of-range case at shared-libs/calendar-interval/test/index.js, lines 851-852. The test right after it already stubs console.warn and asserts on it, so these two could do the same.
| /** Formats a timestamp as an ASCII Gregorian or Bikram Sambat month tag. */ | ||
| const getIntervalTag = (endTimestamp, useBikramSambatMonths) => { | ||
| const endDate = moment(endTimestamp); | ||
| if (!Number.isFinite(endTimestamp) || !endDate.isValid()) { |
There was a problem hiding this comment.
nit: Once Number.isFinite passes, endDate.isValid() can no longer be false, and line 159 parses the timestamp a second time although endDate already holds it. toLocalIsoDate(endDate) works because the helper accepts a moment. Purely cosmetic.
Description
Implements the first PR in the agreed two-PR split for #11423.
@medic/calendar-interval.completeDatethrough locale-independent ASCII formatting.This PR intentionally excludes the display-related sites (
message-utils,format-date.service.ts, anddate-filter.component.ts) and the #11439 site. Those remain deferred to PR 2 of the maintainer-requested split.Closes #11423.
The display-related PR 2 remains planned as the separately reviewed follow-up requested by the maintainer.
Testing
npm test --prefix shared-libs/calendar-interval— 42 passingnpm test --prefix shared-libs/rules-engine— 225 passingapi/tests/mocha/services/export/dhis.spec.js— 15 passingnpm run unit --prefix webapp -- --watch=false --code-coverage=false --include=../tests/karma/ts/services/rules-engine.service.spec.ts— 60 passingnpm run lint— passedgit diff --check origin/master...HEAD— passedCode review checklist
License
The software is provided under AGPL-3.0. Contributions to this project are accepted under the same license.