"""API-level tests for `GET /api/analytics/{workspace_id}/overview` and the per-parent age4 endpoint — specifically that the new per-year balance series (`year_balances`/`year_totals`) survives the wire boundary (§4.2's service-computed-but-dropped-on-the-wire gotcha), matching the `test_calendar_router.py` pattern. """ from datetime import date, datetime from uuid import uuid4 from httpx import AsyncClient from app.entities.child import Child from app.repositories_impl.sqlite.child_repository import SQLiteChildRepository from tests.conftest import SeededIds class TestGetOverviewYearBalances: async def test_wire_shape_includes_year_balances_and_year_totals( self, authed_client: AsyncClient, child_repo: SQLiteChildRepository, seeded_ids: SeededIds, ) -> None: ws = seeded_ids.workspace_id pd_uuid = seeded_ids.personal_data_uuid birth = date(2025, 1, 1) child = await child_repo.create( Child( id=uuid4(), workspace_id=ws, name="Kid", birth_date=birth, created_at=datetime.now(), ) ) response = await authed_client.get( f"/api/analytics/{ws}/overview", params={"child_id": str(child.id)} ) assert response.status_code == 200 body = response.json() assert "year_totals" in body assert [yt["year"] for yt in body["year_totals"]] == [2025, 2026, 2027, 2028, 2029] for yt in body["year_totals"]: assert set(yt) == {"year", "pl_left", "vacation_left"} assert len(body["parent_projections"]) == 1 projection = body["parent_projections"][0] assert projection["personal_data_uuid"] == str(pd_uuid) assert "year_balances" in projection assert [yb["year"] for yb in projection["year_balances"]] == [ 2025, 2026, 2027, 2028, 2029, ] birth_year = projection["year_balances"][0] assert birth_year["personal_data_uuid"] == str(pd_uuid) assert birth_year["child_id"] == str(child.id) vacation = birth_year["vacation"] assert set(vacation) == { "year", "earned", "is_assumed", "carried_in", "planned_use", "left", "carried_out", "expiring", "expiring_age", "expiring_over_cap", } assert vacation["earned"] == 25 # statutory default — no vacation_days row entered assert vacation["is_assumed"] is True assert vacation["carried_in"] == 0 assert vacation["planned_use"] == 0 assert vacation["left"] == 25 parental_leave = birth_year["parental_leave"] assert set(parental_leave) == { "year", "sjukpenning_used", "lagsta_used", "sjukpenning_left", "lagsta_left", } # `seeded_ids`'s workspace has exactly one member -> full pool. assert parental_leave["sjukpenning_left"] == 390 assert parental_leave["lagsta_left"] == 90