feat: agent-11 PR2 – Urlaubsanspruch (Verfall scharf, Pro-rata, Teilzeit)
Security Audit / Python Dependency Audit (push) Has been cancelled
Security Audit / Node.js Dependency Audit (push) Has been cancelled

Korrektheit der Urlaubskonten (Feature-Parität mit Urlaubsverwaltung):

- Verfall scharfgeschaltet: neuer effektiv verfügbarer Saldo (available_days)
  schließt verfallenen, noch nicht verbrauchten Resturlaub aus; Konto-Warnung
  beim Antrag nutzt jetzt available statt remaining. (Verfallsdatum bleibt in
  company.settings, UI bereits vorhanden.)
- Anteilige Berechnung (Zwölftel) im Ein-/Austrittsjahr anhand neuer Felder
  users.entry_date / exit_date; opt-in pro Firma (vacation_prorate_first_year).
- Teilzeit: Anspruch optional aus Arbeitstagen/Woche des WorkSchedule abgeleitet
  (vacation_from_schedule), Basis vacation_default_days.
- _get_or_create_balance berechnet den Grundanspruch jetzt frisch
  (_compute_entitlement); _carryover_expired/effective_available als Service-API,
  Router delegiert.

Frontend: CompanySettingsPage (Jahresurlaub + Pro-rata- und Teilzeit-Toggles),
UsersPage (Ein-/Austrittsdatum im Edit-Modal), AbsencesPage ("Verfügbar" + Hinweis
bei verfallenem Resturlaub).

Migration 0036. 183/183 Tests grün. Deployed auf 137 + 164.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 12:03:42 +02:00
co-authored by Claude Opus 4.8
parent 3b2df1c978
commit c9c197ddae
13 changed files with 277 additions and 20 deletions
+8
View File
@@ -70,6 +70,14 @@ class Company(Base):
# Mobile-Konfiguration
mobile_stamping_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
# Urlaubsanspruch-Konfiguration
# Basis-Jahresurlaub (Vollzeit) für neu angelegte Urlaubskonten.
vacation_default_days: Mapped[int] = mapped_column(Integer, nullable=False, default=30)
# Anteilige Berechnung im Ein-/Austrittsjahr (Zwölftel-Regel).
vacation_prorate_first_year: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
# Teilzeit: Anspruch aus Arbeitstagen/Woche des WorkSchedule ableiten (opt-in).
vacation_from_schedule: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
# Freizeitausgleich-Konfiguration
overtime_overdraft_allowed: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
overtime_warning_threshold_hours: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
+6 -2
View File
@@ -1,9 +1,9 @@
import uuid
import enum
from datetime import datetime
from datetime import datetime, date
from typing import TYPE_CHECKING
from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, String, Text, func
from sqlalchemy import Boolean, Date, DateTime, Enum, ForeignKey, String, Text, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
@@ -50,6 +50,10 @@ class User(Base):
UUID(as_uuid=True), ForeignKey("work_schedules.id", ondelete="SET NULL")
)
# Ein-/Austrittsdatum Basis für anteilige Urlaubsberechnung (Zwölftel-Regel)
entry_date: Mapped[date | None] = mapped_column(Date)
exit_date: Mapped[date | None] = mapped_column(Date)
# Kiosk auth
kiosk_pin_hash: Mapped[str | None] = mapped_column(Text)
kiosk_qr_token: Mapped[str | None] = mapped_column(Text, unique=True)