Files
timemaster/backend/app/schemas/report.py
T
sysops 1fedd683e0 Initial commit – TimeMaster Zeiterfassung & HR-Tool
Stand: agent-06 (Audit-Log), agent-05 (Krankmeldung), agent-07 Phase 1 (Personalnummer),
Busylight-Pull-Integration, TOTP/2FA, Abwesenheiten, Zeiterfassung, Kiosk-Grundgerüst.
Migrations 0001–0023 deployed auf 192.168.1.137 + .164.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 20:03:27 +02:00

191 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 # MoFr, 0620 Uhr, kein Feiertag
night_25_hours: float # 2024 + 0406 Uhr (25% Zuschlag)
night_40_hours: float # 0004 Uhr (40% Zuschlag)
sunday_hours: float # Sonntag 0024 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]