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:
@@ -32,36 +32,40 @@ def weekly_intensity(planned_days: list[PlannedLeaveDay], period_weeks: float) -
|
||||
return len(fp_days) / period_weeks
|
||||
|
||||
|
||||
def default_tier_pool_share(rules: LeaveRules) -> tuple[int, int]:
|
||||
def default_tier_pool_share(rules: LeaveRules, parent_count: int) -> tuple[int, int]:
|
||||
"""The per-parent (sjukpenning_left, lagsta_left) assumed when no FK
|
||||
snapshot exists yet.
|
||||
|
||||
`rules.sjukpenning_days`/`lagsta_niva_days` are the WHOLE CHILD's combined
|
||||
tier totals (390 + 90), split across both parents — halving them gives a
|
||||
single parent's default share. Shared by `AllocationInputLoader.load` and
|
||||
tier totals (390 + 90). A sole parent (`parent_count <= 1`) gets the full
|
||||
pool; with a partner (`parent_count >= 2`) it's split in half per parent
|
||||
(195 + 45) exactly as FK does. Shared by `AllocationInputLoader.load` and
|
||||
`PlanningService._tier_pool_left` so they can never derive it differently
|
||||
(see "Bug A": they once did, 390/90 in one place vs. 195/45 in the other).
|
||||
"""
|
||||
if parent_count <= 1:
|
||||
return rules.sjukpenning_days, rules.lagsta_niva_days
|
||||
return rules.sjukpenning_days // 2, rules.lagsta_niva_days // 2
|
||||
|
||||
|
||||
def resolve_age4_savable_cap(planning_mode: str, parent_count: int) -> int:
|
||||
def resolve_age4_savable_cap(parent_count: int) -> int:
|
||||
"""Single source of truth for which age-4 savable-days ceiling applies.
|
||||
|
||||
`rules.max_savable_days_at_age_4` (96) is the per-CHILD ceiling. When a
|
||||
child actually has two parents in a workspace explicitly flagged
|
||||
`planning_mode == 'couple'`, each parent's own balance is capped at
|
||||
`rules.max_savable_days_per_parent_at_age_4` (48) instead — 96 each would
|
||||
let the family save 192 combined, double the legal figure.
|
||||
`rules.max_savable_days_at_age_4` (96) is the per-CHILD ceiling, pooled
|
||||
across however many parents the child legally has. The per-parent cut is
|
||||
strictly **non-poolable**: each parent's own savable balance is capped at
|
||||
`rules.max_savable_days_per_parent_at_age_4` (48) whenever the child has
|
||||
two (or more) parents — 96 each would let the family save 192 combined,
|
||||
double the legal figure. A genuine single parent keeps the full 96.
|
||||
|
||||
Requiring both conditions (couple mode AND >=2 parents) is a safety belt:
|
||||
a workspace flagged 'couple' that only has one member so far still gets
|
||||
the per-child (96) figure, since there is no second parent to divide it
|
||||
with. `AnalyticsService` and `allocation_service`'s `_Ledger` both call
|
||||
This is a fact about the family (how many parents the child has), not a
|
||||
workspace display preference — it is purely a function of parent count.
|
||||
A workspace with two real members must always get the 48/48 split, never
|
||||
96/96. `AnalyticsService` and `allocation_service`'s `_Ledger` both call
|
||||
this so they can never disagree on which cap applies.
|
||||
"""
|
||||
rules = settings.rules
|
||||
if planning_mode == "couple" and parent_count >= 2:
|
||||
if parent_count >= 2:
|
||||
return rules.max_savable_days_per_parent_at_age_4
|
||||
return rules.max_savable_days_at_age_4
|
||||
|
||||
|
||||
Reference in New Issue
Block a user