diff --git a/backend/main.py b/backend/main.py index dc5997c..3033e8d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1085,6 +1085,25 @@ async def dashboard_summary( if r.employee_name: staff_set.add(r.employee_name) + # Component counts: union of status_code match AND minutes field + # (handles abnormal override where status_code='abnormal' hides + # the underlying late/early/ot component from by_status) + late_count = ( + sum(v for k, v in by_status.items() if "late" in k) + + sum(1 for r in rows if r.late_minutes and r.late_minutes > 0 + and (r.status_code or "").lower() == "abnormal") + ) + early_count = ( + sum(v for k, v in by_status.items() if "early" in k) + + sum(1 for r in rows if r.early_minutes and r.early_minutes > 0 + and (r.status_code or "").lower() == "abnormal") + ) + ot_count = ( + sum(v for k, v in by_status.items() if "ot" in k) + + sum(1 for r in rows if r.ot_minutes and r.ot_minutes > 0 + and (r.status_code or "").lower() == "abnormal") + ) + return { # Backend / dashboard canonical fields "total": len(rows), @@ -1094,11 +1113,14 @@ async def dashboard_summary( "by_department": by_department, "trend": [], # Frontend-expected fields (alias for legacy UI) + # Component counts: late + early + ot may exceed total because + # a single record can carry multiple status components + # (e.g. status_code='late_ot' contributes to both late and ot). "total_records": len(rows), "normal_count": by_status.get("normal", 0), - "late_count": sum(v for k, v in by_status.items() if "late" in k), - "early_count": sum(v for k, v in by_status.items() if "early" in k), - "ot_count": sum(v for k, v in by_status.items() if "ot" in k), + "late_count": late_count, + "early_count": early_count, + "ot_count": ot_count, "missing_count": by_status.get("missing", 0), "abnormal_count": by_status.get("abnormal", 0), "staff_count": len(staff_set),