weekend on call shifts

This commit is contained in:
Marc Rejohn Castillano 2026-03-09 18:24:16 +08:00
parent aee4604fed
commit b8ec5dbf69
2 changed files with 174 additions and 33 deletions

View File

@ -1529,6 +1529,18 @@ class _ScheduleGeneratorPanelState
startMinute: 0,
duration: const Duration(hours: 8),
);
// Weekend Saturday on_call: 5PM (17:00) to 8AM (08:00) next day = 15 hours
templates['on_call_saturday'] = _ShiftTemplate(
startHour: 17,
startMinute: 0,
duration: const Duration(hours: 15),
);
// Weekend Sunday on_call: 5PM (17:00) to 7AM (07:00) next day = 14 hours
templates['on_call_sunday'] = _ShiftTemplate(
startHour: 17,
startMinute: 0,
duration: const Duration(hours: 14),
);
// Default normal shift (8am-5pm = 9 hours)
templates['normal'] = _ShiftTemplate(
startHour: 8,
@ -1684,14 +1696,7 @@ class _ScheduleGeneratorPanelState
final pmUserId = itStaff.isEmpty
? null
: itStaff[pmBaseIndex % itStaff.length].id;
final nextWeekPmUserId = itStaff.isEmpty
? null
: itStaff[(pmBaseIndex + 1) % itStaff.length].id;
final pmRelievers = _buildRelievers(pmBaseIndex, itStaff);
final nextWeekRelievers = itStaff.isEmpty
? <String>[]
: _buildRelievers((pmBaseIndex + 1) % itStaff.length, itStaff);
var weekendNormalOffset = 0;
for (
var day = weekStart;
@ -1706,33 +1711,54 @@ class _ScheduleGeneratorPanelState
final dayIsRamadan = isApproximateRamadan(day);
if (isWeekend) {
// Weekend: only IT Staff get normal + on_call (rotating)
if (itStaff.isNotEmpty) {
final normalIndex =
(amBaseIndex + pmBaseIndex + weekendNormalOffset) %
itStaff.length;
final isSaturday = day.weekday == DateTime.saturday;
if (isSaturday) {
// Saturday: AM person gets normal shift, PM person gets weekend on_call
if (amUserId != null) {
_tryAddDraft(
draft,
existing,
templates,
'normal',
itStaff[normalIndex].id,
amUserId,
day,
const [],
);
weekendNormalOffset += 1;
}
if (nextWeekPmUserId != null) {
if (pmUserId != null) {
_tryAddDraft(
draft,
existing,
templates,
'on_call',
nextWeekPmUserId,
'on_call_saturday',
pmUserId,
day,
nextWeekRelievers,
pmRelievers,
);
}
} else {
// Sunday: PM person gets both normal and weekend on_call
if (pmUserId != null) {
_tryAddDraft(
draft,
existing,
templates,
'normal',
pmUserId,
day,
const [],
);
_tryAddDraft(
draft,
existing,
templates,
'on_call_sunday',
pmUserId,
day,
pmRelievers,
);
}
}
} else {
// Weekday: IT Staff rotate AM/PM/on_call
final isFriday = day.weekday == DateTime.friday;

View File

@ -0,0 +1,115 @@
-- Add weekend-specific on_call shift types for Saturday and Sunday
-- Saturday on_call: 5PM to 8AM (15 hours)
-- Sunday on_call: 5PM to 7AM (14 hours)
-- Update duty_schedules.shift_type.
-- If enum-backed, add new enum values.
-- If CHECK-backed, replace the existing CHECK constraint with expanded values.
DO $$
DECLARE
_is_enum boolean := false;
_con text;
BEGIN
SELECT (t.typtype = 'e') INTO _is_enum
FROM pg_attribute a
JOIN pg_type t ON t.oid = a.atttypid
WHERE a.attrelid = 'duty_schedules'::regclass
AND a.attname = 'shift_type'
AND NOT a.attisdropped;
IF _is_enum THEN
BEGIN
ALTER TYPE shift_type ADD VALUE IF NOT EXISTS 'on_call_saturday';
EXCEPTION WHEN undefined_object THEN
NULL;
END;
BEGIN
ALTER TYPE shift_type ADD VALUE IF NOT EXISTS 'on_call_sunday';
EXCEPTION WHEN undefined_object THEN
NULL;
END;
ELSE
FOR _con IN
SELECT con.conname
FROM pg_constraint con
JOIN pg_attribute att
ON att.attrelid = con.conrelid
AND att.attnum = ANY(con.conkey)
WHERE con.conrelid = 'duty_schedules'::regclass
AND con.contype = 'c'
AND att.attname = 'shift_type'
LOOP
EXECUTE format('ALTER TABLE duty_schedules DROP CONSTRAINT %I', _con);
END LOOP;
ALTER TABLE duty_schedules
ADD CONSTRAINT duty_schedules_shift_type_check
CHECK (
shift_type IN (
'normal',
'am',
'pm',
'on_call',
'weekend',
'overtime',
'on_call_saturday',
'on_call_sunday'
)
);
END IF;
END $$;
-- Replace attendance_logs shift_type CHECK constraint regardless of current name.
DO $$
DECLARE
_is_enum boolean := false;
_con text;
BEGIN
SELECT (t.typtype = 'e') INTO _is_enum
FROM pg_attribute a
JOIN pg_type t ON t.oid = a.atttypid
WHERE a.attrelid = 'attendance_logs'::regclass
AND a.attname = 'shift_type'
AND NOT a.attisdropped;
IF _is_enum THEN
BEGIN
ALTER TYPE shift_type ADD VALUE IF NOT EXISTS 'on_call_saturday';
EXCEPTION WHEN undefined_object THEN
NULL;
END;
BEGIN
ALTER TYPE shift_type ADD VALUE IF NOT EXISTS 'on_call_sunday';
EXCEPTION WHEN undefined_object THEN
NULL;
END;
ELSE
FOR _con IN
SELECT con.conname
FROM pg_constraint con
JOIN pg_attribute att
ON att.attrelid = con.conrelid
AND att.attnum = ANY(con.conkey)
WHERE con.conrelid = 'attendance_logs'::regclass
AND con.contype = 'c'
AND att.attname = 'shift_type'
LOOP
EXECUTE format('ALTER TABLE attendance_logs DROP CONSTRAINT %I', _con);
END LOOP;
ALTER TABLE attendance_logs
ADD CONSTRAINT attendance_logs_shift_type_check
CHECK (
shift_type IN (
'normal',
'am',
'pm',
'on_call',
'weekend',
'overtime',
'on_call_saturday',
'on_call_sunday'
)
);
END IF;
END $$;