Files
timemaster/backend/app/schemas/company.py
T
patrick 23ba7f1762 feat: Überstunden-Kappung + Jahresverfall pro Firma konfigurierbar
Backend:
- Company: overtime_cap_hours, overtime_expiry_enabled/month/day,
  overtime_max_carryover_hours
- OvertimeBalance: last_expiry_applied_at
- Migration 0031: neue Spalten in companies + overtime_balances
- _recalculate_overtime_balance: Kappung direkt nach Berechnung
- apply_overtime_expiry_if_needed(): lazy Verfall beim Balance-Abruf
- GET /absences/overtime-balance: prüft + wendet Verfall automatisch an
- POST /absences/overtime-balance/apply-expiry: manueller Trigger (Admin)

Frontend:
- CompanySettingsPage: neuer Block 'Überstunden-Konto'
  - Toggle Kappungsgrenze + Stunden-Input
  - Toggle Jahresverfall + Stichtag (Tag/Monat) + max. Übertrag
  - 'Verfall anwenden'-Button für Admins

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:48:30 +02:00

74 lines
2.3 KiB
Python

import uuid
from typing import Literal
from pydantic import BaseModel, Field
PersonnelNumberModeT = Literal["manual", "auto"]
class CompanyOut(BaseModel):
model_config = {"from_attributes": True}
id: uuid.UUID
name: str
slug: str
plan: str
logo_url: str | None
country: str
state: str | None
settings: dict
personnel_number_required: bool = False
personnel_number_mode: PersonnelNumberModeT = "manual"
personnel_number_next: int = 1
mobile_stamping_enabled: bool = True
overtime_overdraft_allowed: bool = True
overtime_warning_threshold_hours: int = 0
overtime_cap_hours: int | None = None
overtime_expiry_enabled: bool = False
overtime_expiry_month: int = 3
overtime_expiry_day: int = 31
overtime_max_carryover_hours: int | None = None
kiosk_require_approval: bool = True
kiosk_track_current_user: bool = True
kiosk_heartbeat_interval_sec: int = 30
class CompanyUpdate(BaseModel):
name: str | None = Field(None, min_length=2, max_length=255)
state: str | None = Field(None, max_length=10)
settings: dict | None = None
personnel_number_required: bool | None = None
personnel_number_mode: PersonnelNumberModeT | None = None
personnel_number_next: int | None = Field(None, ge=1)
mobile_stamping_enabled: bool | None = None
overtime_overdraft_allowed: bool | None = None
overtime_warning_threshold_hours: int | None = Field(None, ge=0)
overtime_cap_hours: int | None = Field(None, ge=1, le=9999)
overtime_expiry_enabled: bool | None = None
overtime_expiry_month: int | None = Field(None, ge=1, le=12)
overtime_expiry_day: int | None = Field(None, ge=1, le=31)
overtime_max_carryover_hours: int | None = Field(None, ge=0, le=9999)
kiosk_require_approval: bool | None = None
kiosk_track_current_user: bool | None = None
kiosk_heartbeat_interval_sec: int | None = Field(None, ge=10, le=120)
class DepartmentOut(BaseModel):
model_config = {"from_attributes": True}
id: uuid.UUID
company_id: uuid.UUID
name: str
manager_id: uuid.UUID | None
class DepartmentCreate(BaseModel):
name: str = Field(min_length=1, max_length=255)
manager_id: uuid.UUID | None = None
class DepartmentUpdate(BaseModel):
name: str | None = Field(None, min_length=1, max_length=255)
manager_id: uuid.UUID | None = None