On this page
Settings toggles (web + mobile)Daily Summary message contentDaily Appointments Summary message contentScheduling and edge casesFor Quality
There is no automated test coverage for this feature (no tests exist anywhere under packages/server/src/cronJobs/, and none were added here). Everything below is manual-verification territory, primarily via the internal admin "Execute Cron Job" action (ignoreHour: true), which bypasses the local-time gate so a run can be forced immediately.
Settings toggles (web + mobile)
- Toggle Daily Summary off, save, reload the page — confirm it stays
off (i.e. it actually persisted, not just visually unchecked).
- Do the same for Daily Appointments Summary.
- Regression check specific to this PR: toggle Treasury
notifications off and back on, on the web app, and confirm it persists across a reload. This PR incidentally fixed a pre-existing bug where the Treasury checkbox rendered but was never included in the saved payload — worth explicit regression coverage since it wasn't the PR's stated goal (see Notification Settings Toggles).
- Confirm both new toggles show up correctly in all 9 languages — this is
translation-file text (app.summaryCron, app.summaryCronNotifications, app.appointmentsCron, app.appointmentsCronNotifications), separate from the cron's own message-body translations below.
Daily Summary message content
- A user with full access (or all three of invoice/payment analytics +
view-all-branches) and the toggle on should receive it; a user missing any one of those permissions should not, even with the toggle on.
- A user with the right permissions but the toggle off should not receive
it.
- Verify the numbers against the source screens for a day with: some
invoices, some payments, a mix of completed/canceled/no-show appointments. Specifically check:
- Balance top-up invoices are excluded from the invoice total.
- Payments of type
BALANCEand refunded payments are excluded from the
payments total.
- "Remaining" never goes negative even if a test invoice has
paid > total. - The completed/total appointment count includes canceled and no-show
appointments in the "total" but not in "completed."
- Verify currency displayed matches the company's configured currency.
Daily Appointments Summary message content
- A doctor with completed appointments today and none tomorrow → "no
appointments scheduled for tomorrow" variant.
- A doctor with nothing completed today but appointments tomorrow → "no
completed appointments" variant.
- A doctor with both → the full variant, including a correctly formatted
first-appointment time for tomorrow.
- A doctor with neither → confirm they receive no message (not an
empty one).
- Total time formatting: verify
0hcollapses to just minutes (e.g.
"45m", not "0h 45m") and that duration reads correctly for a multi-hour appointment.
- Cancel or no-show tomorrow's only appointment for a doctor and confirm
they drop out of "upcoming" — but a canceled/no-show appointment today still counts toward the company-wide "total appointments" figure in the Daily Summary.
Scheduling and edge cases
- Time zone edge case: create/find a company with
timeZoneunset
(null) and force-run the cron. Per the code, this should throw inside the per-company loop rather than falling back to UTC as the code's own comment claims — worth confirming whether this actually happens in the current environment, and if so, whether it takes down the entire run (every company not yet processed that tick) rather than just skipping the one bad company. See The Cron for the exact mechanism.
- Two clinics, two time zones: confirm each clinic's summary fires
independently at its own local 23:30, not at a shared UTC time.
- Overlap protection: while a run is in progress (
running: truein
Redis), confirm a second invocation (natural hourly tick, or a manual Execute click) is a no-op rather than double-sending.
- Disabled company: confirm a disabled company (
disabled: true) is
skipped entirely, even via manual execute.
- Disabled user: confirm a disabled user never receives either
message, even if they'd otherwise qualify.
- Stale/invalid push tokens: a user with no valid Expo push tokens
(Expo.isExpoPushToken fails, or pushNotifications is empty) should be silently skipped, not error the run.
- Notification tap behavior: confirm tapping either notification just
opens the app without navigating anywhere specific (there's no id in the payload, so the app's generic navigation-on-tap handler doesn't fire) — this is expected per the current code, not a bug to file, but worth knowing so it isn't mistaken for one during a test pass.