fix: business hours closing for one minute a day

Merged
SA
2mo ago
+97-1

CORE-2550

Proposed changes

Work hours are configured at minute granularity, but filterBusinessHoursThatMustBeOpened compared the finish time as exclusive. Consecutive daily windows therefore never met: a 00:00–23:59 business hour — the only way the admin UI can express "always open" — leaves the service closed for the whole 23:59 minute, every day.

During that minute:

  • agents cannot become available (error-business-hours-are-closed from livechat/agent.status)
  • saving a business hour strips openBusinessHours from every agent
  • the Livechat widget renders the offline form instead of the registration form

A work hour now stays open until the end of its finish minute:

const afterFinishMinute = localTimeFinish.clone().add(1, 'minute');
return currentTime.isSameOrAfter(localTimeStart) && currentTime.isBefore(afterFinishMinute);

The clone happens after the existing week-shift adjustments, so that logic is untouched.

How this was found

CI run 31729126298 failed on Test API Livechat (EE) and (FIPS), both on a single assertion in 19-business-hours.ts:154 (should allow agents to be available). The job timings pin it exactly:

jobfinishedresult
Livechat API (CE)18:25:11:white_check_mark:
Livechat API (EE)18:29:58:x:
Livechat API (FIPS)18:30:06:x:

That test inherits a default business hour saved as 00:00–23:59 in Asia/Kolkata, which on a UTC server runs Saturday 18:30 → Sunday 18:29. EE and FIPS ran the assertion inside the resulting 18:29:00–18:29:59 UTC hole; CE ran four minutes earlier and passed. Same commit, different wall clock.

Reviewer notes

This widens every business hour by one minute. The default 08:00–20:00 now stays open through 20:00:59. That is inherent to "finish is inclusive of its minute", and it is asserted explicitly by one of the new tests rather than left implicit. The alternative considered was special-casing finish.time === '23:59' as end-of-day — no collateral effect, but a magic constant. Happy to switch if reviewers prefer that.

This does not fully fix the 24/7 case. findHoursToScheduleJobs schedules cron jobs at exactly start.cron.time and finish.cron.time, so a 00:00–23:59 config still gets a close job at 18:29 and an open job at 18:30 — the cron will still strip openBusinessHours for that minute. This PR fixes the point-in-time check, which is what runs on business-hour save and drives agent.status. Making the cron skip a close that is immediately followed by an open is a separate, larger change and deserves its own issue.

Marginal effect on an existing test. should not allow a user to be available if BH are closed uses a 00:00–00:01 Monday window in America/Sao_Paulo; its open window grows from 03:00:00–03:00:59 to 03:00:00–03:01:59 UTC. Still a ~2-minutes-per-week exposure, same flake class as before.

Testing

Three tests added to filterBusinessHoursThatMustBeOpened.spec.ts, using the file's existing jest.useFakeTimers() style:

testbeforeafter
Kolkata 00:00–23:59 @ Sun 18:29:30 UTC (the hole):x::white_check_mark:
same window @ Sun 18:30:30 UTC (past the window):white_check_mark::white_check_mark:
UTC 08:00–20:00 @ Mon 20:00:30:x::white_check_mark:

All 6 tests in the file pass; the 3 pre-existing ones are unchanged. The two new positive tests were verified to fail against unmodified source — the middle test is the guard proving the window widens by exactly one minute and no more.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Business-hour schedules now remain open throughout their configured closing minute.
    • Fixed all-day schedules, such as 00:00–23:59, incorrectly closing at 23:59.
    • Added coverage for finish-time behavior across time zones and same-day schedules.