Fix: exclude accident source + filter email-format names from employees list

Root cause: Accident.employee_name contains submitter EMAIL addresses
(e.g. info@scmedical.hk), not the injured staff name. UNION of all three
sources polluted the attendance staff dropdown with emails.

Fix:
- Removed Accident from /api/employees/list UNION (source=all now means
  attendance + leave only)
- Added EMAIL_RE filter to skip any name containing @ (defensive)
- Updated docstring + response includes excluded field explaining why

Verified: 12 clean staff names returned (down from 16 with 4 emails mixed in)
This commit is contained in:
IT Dog
2026-07-19 23:45:34 +08:00
parent 6c70b81df5
commit c0076a125c
+17 -14
View File
@@ -1294,32 +1294,35 @@ async def update_attendance_record(
# ============ Employees List (combined source) ============
@app.get("/api/employees/list")
async def list_employees(
source: Optional[str] = "all", # "all" / "attendance" / "leave" / "accident"
source: Optional[str] = "all", # "all" / "attendance" / "leave"
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""List distinct employee names from attendance + leave + accident records.
"""List distinct employee names (real staff only).
Sources: attendance_records + leave_records (NOT accident - that table stores
submitter emails, not staff names).
Filter: names containing "@" (email format) are excluded automatically.
Used by frontend dropdowns to show ALL staff, even those who haven't taken leave yet.
source:
- all (default): UNION of attendance + leave + accident
- attendance: only attendance_records.employee_name
- leave: only leave_records.employee_name
- accident: only Accident.employee_name
"""
import re
EMAIL_RE = re.compile(r"@")
names = set()
if source in ("all", "attendance"):
for n in db.query(AttendanceRecord.employee_name).distinct().all():
if n[0]: names.add(n[0])
if n[0] and not EMAIL_RE.search(n[0]):
names.add(n[0])
if source in ("all", "leave"):
for n in db.query(LeaveRecord.employee_name).distinct().all():
if n[0]: names.add(n[0])
if source in ("all", "accident"):
for n in db.query(Accident.employee_name).distinct().all():
if n[0]: names.add(n[0])
if n[0] and not EMAIL_RE.search(n[0]):
names.add(n[0])
# NOTE: Accident.employee_name contains submitter EMAIL (e.g. info@scmedical.hk),
# NOT the injured staff name. We exclude accident from employee list to avoid
# polluting staff dropdown with email addresses.
sorted_names = sorted(names, key=lambda x: x.lower())
return {"employees": sorted_names, "count": len(sorted_names), "source": source}
return {"employees": sorted_names, "count": len(sorted_names), "source": source, "excluded": "accident (email column)"}
# ============ Holidays CRUD ============# ============ Holidays CRUD ============