Fix: use roster public_holiday column to determine if employee works on holidays, instead of checking clock-in
This commit is contained in:
+24
-8
@@ -128,8 +128,19 @@ def enrich_attendance_with_leave(records, db):
|
|||||||
|
|
||||||
if r.date in holidays_by_date:
|
if r.date in holidays_by_date:
|
||||||
h = holidays_by_date[r.date]
|
h = holidays_by_date[r.date]
|
||||||
# Only mark as holiday if no clock-in record
|
# Check roster: if shift's public_holiday == 'Yes', employee works on holidays
|
||||||
# (employee who worked on holiday should keep attendance status)
|
# 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 = (
|
has_clock_in = (
|
||||||
(r.check_in is not None) or
|
(r.check_in is not None) or
|
||||||
(r.actual_in and r.actual_in not in ("", "-"))
|
(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_code = "holiday"
|
||||||
r.status_text = f"\U0001F3D6\uFE0F{h.name}"
|
r.status_text = f"\U0001F3D6\uFE0F{h.name}"
|
||||||
continue
|
continue
|
||||||
# Has clock-in on holiday: keep computed attendance status but append holiday flag
|
# Has clock-in but roster says rest on holiday - still show holiday
|
||||||
base = r.status_text or "正常"
|
r.status_code = "holiday"
|
||||||
r.status_text = f"{base} (🎉{h.name})"
|
r.status_text = f"\U0001F3D6\uFE0F{h.name}"
|
||||||
|
continue
|
||||||
|
|
||||||
emp_leaves = leave_by_emp_date.get(r.employee_name, {}).get(r.date, [])
|
emp_leaves = leave_by_emp_date.get(r.employee_name, {}).get(r.date, [])
|
||||||
if not emp_leaves:
|
if not emp_leaves:
|
||||||
@@ -504,7 +516,8 @@ async def _import_attendance_to_db(db: Session, headers, rows, user_id: int) ->
|
|||||||
# ============ Attendance Calculation ============
|
# ============ Attendance Calculation ============
|
||||||
def get_shift_schedule_full(shift_code: str, weekday: str) -> Optional[tuple]:
|
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.
|
"""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")
|
roster_path = get_excel_path("roster")
|
||||||
if not os.path.exists(roster_path):
|
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
|
# Find column indices
|
||||||
shift_col = None
|
shift_col = None
|
||||||
|
ph_col = None
|
||||||
for i, h in enumerate(headers):
|
for i, h in enumerate(headers):
|
||||||
if h == '班次':
|
if h == '班次':
|
||||||
shift_col = i
|
shift_col = i
|
||||||
break
|
elif h == 'public holiday':
|
||||||
|
ph_col = i
|
||||||
|
|
||||||
if shift_col is None:
|
if shift_col is None:
|
||||||
return None
|
return None
|
||||||
@@ -549,6 +564,7 @@ def get_shift_schedule_full(shift_code: str, weekday: str) -> Optional[tuple]:
|
|||||||
# Find the shift row
|
# Find the shift row
|
||||||
for row in ws.iter_rows(min_row=2, values_only=True):
|
for row in ws.iter_rows(min_row=2, values_only=True):
|
||||||
if row[shift_col] == shift_code:
|
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)
|
day_col = day_col_map.get(target_day)
|
||||||
if day_col is not None:
|
if day_col is not None:
|
||||||
schedule = row[day_col]
|
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()
|
end_str = parts[1].strip()
|
||||||
start_time = datetime.strptime(start_str, '%H:%M').time()
|
start_time = datetime.strptime(start_str, '%H:%M').time()
|
||||||
end_time = datetime.strptime(end_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:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user