from dataclasses import dataclass from datetime import date, timedelta import pytest from app.services.calculations import ( aggregate_week, automatic_break_minutes, compute_net_minutes, cumulative_delta, iso_week_bounds, parse_time_to_minutes, required_break_minutes_for_span, ) @dataclass class FakeEntry: date: date start_minutes: int end_minutes: int break_minutes: int def test_compute_net_minutes_and_validation() -> None: assert compute_net_minutes(8 * 60, 15 * 60, 30) == 390 with pytest.raises(ValueError): compute_net_minutes(8 * 60, 8 * 60, 0) with pytest.raises(ValueError): compute_net_minutes(8 * 60, 12 * 60, 300) def test_parse_time_to_minutes() -> None: assert parse_time_to_minutes("08:30") == 510 with pytest.raises(ValueError): parse_time_to_minutes("8:30") def test_required_break_minutes_follow_german_thresholds() -> None: assert required_break_minutes_for_span(6 * 60) == 0 assert required_break_minutes_for_span((6 * 60) + 1) == 30 assert required_break_minutes_for_span(9 * 60) == 30 assert required_break_minutes_for_span((9 * 60) + 1) == 45 def test_automatic_break_minutes_uses_work_span() -> None: assert automatic_break_minutes(8 * 60, 14 * 60) == 0 assert automatic_break_minutes(8 * 60, (14 * 60) + 1) == 30 assert automatic_break_minutes(8 * 60, 17 * 60) == 30 assert automatic_break_minutes(8 * 60, (17 * 60) + 1) == 45 with pytest.raises(ValueError): automatic_break_minutes(8 * 60, 8 * 60) def test_week_aggregation_and_delta() -> None: week_start, _ = iso_week_bounds(date(2026, 2, 25)) entries = [ FakeEntry(date=week_start, start_minutes=8 * 60, end_minutes=13 * 60, break_minutes=15), FakeEntry(date=week_start + timedelta(days=1), start_minutes=9 * 60, end_minutes=14 * 60, break_minutes=30), ] report = aggregate_week(entries, week_start, weekly_target_minutes=1500) assert report["weekly_ist"] == (285 + 270) assert report["weekly_soll"] == 1500 assert report["weekly_delta"] == -945 def test_cumulative_delta_multiple_weeks() -> None: first_week_start, _ = iso_week_bounds(date(2026, 2, 2)) second_week_start = first_week_start + timedelta(days=7) entries = [ FakeEntry(date=first_week_start, start_minutes=8 * 60, end_minutes=13 * 60, break_minutes=0), FakeEntry(date=second_week_start, start_minutes=8 * 60, end_minutes=16 * 60, break_minutes=30), ] result = cumulative_delta(entries, second_week_start, weekly_target_minutes=1500) # Woche 1: 300 - 1500, Woche 2: 450 - 1500 assert result == -2250