From cca088261bf79b3a22c39d304bc3ce1caea4093e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IT=E7=8B=97?= Date: Tue, 21 Jul 2026 12:26:27 +0800 Subject: [PATCH] Fix: use roster public_holiday column to determine if employee works on holidays, instead of checking clock-in --- backend/main.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/backend/main.py b/backend/main.py index 2bd4348..07e2f3a 100644 --- a/backend/main.py +++ b/backend/main.py @@ -128,8 +128,19 @@ def enrich_attendance_with_leave(records, db): if r.date in holidays_by_date: h = holidays_by_date[r.date] - # Only mark as holiday if no clock-in record - # (employee who worked on holiday should keep attendance status) + # Check roster: if shift's public_holiday == 'Yes', employee works on holidays + # Don't override with holiday status in that case + shift_holiday = '休息' # default: assume rest on holiday + if r.shift_code: + shift_info = get_shift_schedule_full(r.shift_code, r.weekday or '') + if shift_info and len(shift_info) >= 3: + shift_holiday = shift_info[2] + if shift_holiday == 'Yes': + # Employee works on public holidays - keep attendance status, append holiday note + base = r.status_text or "正常" + r.status_text = f"{base} (🎉{h.name})" + continue + # Employee rests on public holidays - mark as holiday unless already has clock-in has_clock_in = ( (r.check_in is not None) or (r.actual_in and r.actual_in not in ("", "-")) @@ -138,9 +149,10 @@ def enrich_attendance_with_leave(records, db): r.status_code = "holiday" r.status_text = f"\U0001F3D6\uFE0F{h.name}" continue - # Has clock-in on holiday: keep computed attendance status but append holiday flag - base = r.status_text or "正常" - r.status_text = f"{base} (🎉{h.name})" + # Has clock-in but roster says rest on holiday - still show holiday + r.status_code = "holiday" + r.status_text = f"\U0001F3D6\uFE0F{h.name}" + continue emp_leaves = leave_by_emp_date.get(r.employee_name, {}).get(r.date, []) if not emp_leaves: @@ -504,7 +516,8 @@ async def _import_attendance_to_db(db: Session, headers, rows, user_id: int) -> # ============ Attendance Calculation ============ def get_shift_schedule_full(shift_code: str, weekday: str) -> Optional[tuple]: """Get the expected start and end time for a shift on a given weekday. - Returns (start_time, end_time) tuple. + Returns (start_time, end_time, public_holiday) tuple. + public_holiday is 'Yes' if the shift requires working on public holidays, '休息' otherwise. """ roster_path = get_excel_path("roster") if not os.path.exists(roster_path): @@ -518,10 +531,12 @@ def get_shift_schedule_full(shift_code: str, weekday: str) -> Optional[tuple]: # Find column indices shift_col = None + ph_col = None for i, h in enumerate(headers): if h == '班次': shift_col = i - break + elif h == 'public holiday': + ph_col = i if shift_col is None: return None @@ -549,6 +564,7 @@ def get_shift_schedule_full(shift_code: str, weekday: str) -> Optional[tuple]: # Find the shift row for row in ws.iter_rows(min_row=2, values_only=True): if row[shift_col] == shift_code: + public_holiday = str(row[ph_col]).strip() if ph_col is not None else '休息' day_col = day_col_map.get(target_day) if day_col is not None: schedule = row[day_col] @@ -561,7 +577,7 @@ def get_shift_schedule_full(shift_code: str, weekday: str) -> Optional[tuple]: end_str = parts[1].strip() start_time = datetime.strptime(start_str, '%H:%M').time() end_time = datetime.strptime(end_str, '%H:%M').time() - return (start_time, end_time) + return (start_time, end_time, public_holiday) except: pass