Rework balances around per-parent days left and deduce the partner from FK

Manual entry now takes one parent's sjukpenningnivå, lägstanivå and
dubbeldagar left (plus optional reserved days) and derives the rest in
build_snapshot, shared with the scraper. The scraper also reads the
family panel and exposes a partner deduction; with two parents it is
saved as a 'deduced' snapshot (migration 002). Parent count is the single
source of entitlement: one member gets 480 days and 96 savable at age 4,
two get 240 and 48 each. Workspaces are capped at two parents.

Also lands the in-flight squash of migrations 002–011 into the initial
schema and the removal of planning_mode.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-19 12:27:29 +02:00
parent 375bc64f2f
commit e4719cb9ae
71 changed files with 5705 additions and 1859 deletions
+3 -9
View File
@@ -214,7 +214,6 @@ async def _seed(conn: aiosqlite.Connection, *, reset: bool) -> None:
email=DEMO_EMAIL, password=DEMO_PASSWORD, display_name=DEMO_NAME
)
workspace_id = alex.workspace_id
await services.workspace.update_workspace(workspace_id, planning_mode="couple")
# -- 2. Partner (no login — shared/partner planning needs a second parent
# on the workspace, but nothing requires them to have registered) -------
@@ -261,15 +260,10 @@ async def _seed(conn: aiosqlite.Connection, *, reset: bool) -> None:
workspace_id=workspace_id,
child_id=child.id,
total_days=240,
days_used=240,
reserved_days_total=90,
sjukpenning_left=0,
lagsta_niva_left=0,
reserved_days_left=0,
transferable_days_left=0,
dubbeldagar_left=55,
sjukpenning_total=195,
sjukpenning_used=195,
lagsta_niva_total=45,
lagsta_niva_used=45,
)
# -- 6. Day overrides -----------------------------------------------
@@ -398,7 +392,7 @@ def _print_summary(
print(f" Password: {DEMO_PASSWORD}")
print()
print("Created:")
print(f" Workspace id: {workspace_id} (planning_mode=couple)")
print(f" Workspace id: {workspace_id} (couple: 2 parents)")
print(f" Parent 1: {DEMO_NAME} ({alex.uuid}) — has a login, near-drained FP pool")
print(f" Parent 2: {PARTNER_NAME} ({sam.uuid}) — no login, large surplus pool")
print(f" Child: {CHILD_NAME} ({child_id}), born {birth_date.isoformat()}")