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>
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
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]
|
||||
Reference in New Issue
Block a user