Skip to content

[18.0][FIX] hr_shift: current_shift_id must be the shift active right now - #44

Open
cvinh wants to merge 1 commit into
OCA:18.0from
invitu:18.0-fix_hr_shift_employee_current_shift
Open

[18.0][FIX] hr_shift: current_shift_id must be the shift active right now#44
cvinh wants to merge 1 commit into
OCA:18.0from
invitu:18.0-fix_hr_shift_employee_current_shift

Conversation

@cvinh

@cvinh cvinh commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

hr.employee.current_shift_id is a Many2one that used to be computed via a helper _shift_of_date(min_time, max_time), always called with the UTC 00:00 and UTC 23:59 of "today", searching lines whose start_time and end_time fell entirely inside that window. Two issues combine to break the field:

  • The name says "current" but the query returns any shift scheduled today, so the field is misleading: it is filled hours before the shift actually starts, and stays filled well after it ends.
  • The window is built from fields.Date.today(), which is UTC-based. For a user living far from UTC (e.g. GMT-10 in French Polynesia), a single local day is split across two UTC days and a shift on Monday afternoon local time is stored on the next UTC day. An employee with two shifts the same local day (morning + afternoon) can end up with both matching the same UTC-day window on the boundary, and the Many2one assignment then raises ValueError: Wrong value for hr.employee.current_shift_id: ....

Rewrite _compute_current_shift_id to match the semantic implied by the field name: the shift whose [start_time, end_time] contains the current instant. The domain becomes an overlap check on fields.Datetime.now(), which is timezone-agnostic because both sides are stored in UTC. Only the shift active right now matches, so the Many2one assignment is naturally singular for any well-formed data set (no overlapping shifts), regardless of the user's timezone or the number of shifts scheduled the same day.

_shift_of_date is dropped since it has no external callers in shift-planning or Odoo core and its name no longer fits the new semantic.

hr.employee.current_shift_id is a Many2one that used to be computed
via a helper _shift_of_date(min_time, max_time), always called with
the UTC 00:00 and UTC 23:59 of "today", searching lines whose
start_time and end_time fell entirely inside that window. Two issues
combine to break the field:

- The name says "current" but the query returns any shift scheduled
  today, so the field is misleading: it is filled hours before the
  shift actually starts, and stays filled well after it ends.
- The window is built from fields.Date.today(), which is UTC-based.
  For a user living far from UTC (e.g. GMT-10 in French Polynesia),
  a single local day is split across two UTC days and a shift on
  Monday afternoon local time is stored on the next UTC day. An
  employee with two shifts the same local day (morning + afternoon)
  can end up with both matching the same UTC-day window on the
  boundary, and the Many2one assignment then raises
  ValueError: Wrong value for hr.employee.current_shift_id: ....

Rewrite _compute_current_shift_id to match the semantic implied by
the field name: the shift whose [start_time, end_time] contains the
current instant. The domain becomes an overlap check on
fields.Datetime.now(), which is timezone-agnostic because both sides
are stored in UTC. Only the shift active right now matches, so the
Many2one assignment is naturally singular for any well-formed data
set (no overlapping shifts), regardless of the user's timezone or
the number of shifts scheduled the same day.

_shift_of_date is dropped since it has no external callers in
shift-planning or Odoo core and its name no longer fits the new
semantic.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants