import uuid from datetime import date, time from pydantic import BaseModel # ── Employee Dashboard ───────────────────────────────────────────────────────── class EmployeeDashboard(BaseModel): today_open: bool today_start: time | None today_hours_so_far: float | None week_hours_worked: float week_hours_expected: float week_overtime: float vacation_remaining_days: int | None vacation_used_days: int vacation_entitled_days: int pending_absences: int overtime_balance_hours: float | None # verfügbares Überstundenguthaben schedule_name: str | None # zugewiesener Arbeitsplan # ── Team Dashboard ───────────────────────────────────────────────────────────── class TeamMemberStatus(BaseModel): user_id: uuid.UUID user_name: str department: str | None status: str # "present" | "on_leave" | "absent" absence_type: str | None time_in: time | None hours_today: float | None class TeamDashboard(BaseModel): present_count: int on_leave_count: int absent_count: int pending_time_approvals: int pending_absence_approvals: int members: list[TeamMemberStatus] # ── Company Dashboard ────────────────────────────────────────────────────────── class UpcomingAbsence(BaseModel): user_id: uuid.UUID user_name: str absence_type: str start_date: date end_date: date working_days: float class CompanyDashboard(BaseModel): total_employees: int active_today: int attendance_rate: float month_hours_worked: float month_hours_expected: float month_overtime: float pending_time_approvals: int pending_absence_approvals: int upcoming_absences: list[UpcomingAbsence] # ── Time Report ──────────────────────────────────────────────────────────────── class HoursBreakdown(BaseModel): """Stunden-Aufteilung nach §3b EStG für den Steuerberater.""" normal_hours: float # Mo–Fr, 06–20 Uhr, kein Feiertag night_25_hours: float # 20–24 + 04–06 Uhr (25% Zuschlag) night_40_hours: float # 00–04 Uhr (40% Zuschlag) sunday_hours: float # Sonntag 00–24 Uhr (50% Zuschlag) holiday_125_hours: float # gesetzl. Feiertag (125% Zuschlag) holiday_150_hours: float # besondere Feiertage 25.12, 26.12, 01.05 etc. (150%) holiday_name: str | None # Name des Feiertags falls zutreffend class TimeReportRow(BaseModel): date: date user_id: uuid.UUID user_name: str personnel_number: str | None = None department: str | None start_time: time end_time: time | None break_minutes: int worked_hours: float | None status: str source: str note: str | None breakdown: HoursBreakdown | None = None # None wenn kein Bundesland konfiguriert class TimeReport(BaseModel): date_from: date date_to: date total_rows: int total_hours: float rows: list[TimeReportRow] # ── Absence Report ───────────────────────────────────────────────────────────── class AbsenceReportRow(BaseModel): user_id: uuid.UUID user_name: str personnel_number: str | None = None department: str | None absence_type: str start_date: date end_date: date working_days: float status: str note: str | None class AbsenceReport(BaseModel): date_from: date date_to: date total_rows: int total_days: float rows: list[AbsenceReportRow] # ── Overtime Report ──────────────────────────────────────────────────────────── class OvertimeReportRow(BaseModel): user_id: uuid.UUID user_name: str personnel_number: str | None = None department: str | None hours_worked: float hours_expected: float overtime_hours: float class OvertimeReport(BaseModel): date_from: date date_to: date total_employees: int total_overtime: float rows: list[OvertimeReportRow] # ── Overtime Detail Report (Option A: Inline-Expand) ────────────────────────── class DayEntry(BaseModel): """Einzelner Zeiteintrag innerhalb eines Tages (mehrere möglich).""" start_time: time end_time: time break_minutes: int hours_worked: float status: str arbzg_warnings: list[str] = [] breakdown: HoursBreakdown | None = None class OvertimeDay(BaseModel): date: date weekday: str # "Mo", "Di", … hours_worked: float # Summe aller Einträge des Tages hours_expected: float overtime: float entries: list[DayEntry] = [] # leer = kein Eintrag an dem Tag class OvertimeWeek(BaseModel): week_nr: int week_start: date week_end: date hours_worked: float hours_expected: float overtime: float days: list[OvertimeDay] class OvertimeReportRowDetailed(OvertimeReportRow): weeks: list[OvertimeWeek] = [] arbzg_violation_days: int = 0 # Tage > 10h special_hours_total: HoursBreakdown | None = None class OvertimeReportDetailed(BaseModel): date_from: date date_to: date total_employees: int total_overtime: float rows: list[OvertimeReportRowDetailed]