fix: Überstunden tages-weise berechnen statt Gesamtzeitraum

Vorher: worked_total vs expected_total über den gesamten Zeitraum
→ Urlaubs-/Kranktage senkten das Konto obwohl keine Überstunden gemacht wurden

Jetzt: pro Tag mit Eintrag wird worked_on_day vs scheduled_on_day verglichen
→ nur echte Mehrarbeit zählt als Überstunde

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 22:29:13 +02:00
parent 549783a05e
commit 23b45881a1
+16 -3
View File
@@ -223,9 +223,22 @@ async def _recalculate_overtime_balance(
return float(sa.factor)
return 1.0
expected = _expected_hours(schedule, date_from_all, date_to_all)
worked = sum((e.worked_hours or 0.0) * _fza_factor(e.date) for e in entries)
overtime = max(0.0, worked - expected)
# Tages-weise Berechnung: nur Tage mit Eintrag werden verglichen.
# Hintergrund: Fehl- und Urlaubstage sollen das Überstunden-Konto nicht
# senken nur an Arbeitstagen wo tatsächlich gestempelt wurde, wird
# geprüft ob mehr als das Soll gearbeitet wurde.
daily_schedule = _schedule_daily(schedule)
# Einträge nach Datum gruppieren (mehrere Einträge am gleichen Tag summieren)
hours_by_date: dict[date, float] = {}
for e in entries:
fac = _fza_factor(e.date)
hours_by_date[e.date] = hours_by_date.get(e.date, 0.0) + (e.worked_hours or 0.0) * fac
overtime = 0.0
for entry_date, worked_on_day in hours_by_date.items():
expected_on_day = daily_schedule.get(entry_date.weekday(), 0.0)
overtime += max(0.0, worked_on_day - expected_on_day)
bal.total_hours = Decimal(str(round(overtime, 2)))
bal.last_calculated = datetime.utcnow()