Files
F-r-ldraledigplannerare/backend/app/models/planned_leave.py
T
jacobh2 cc3ced905e Link planned days to their wish, fix the age-4 cap, drop the planning goal
Three changes that together unblock treating a calendar period as one
editable object.

Migration 008 adds `planned_leave_day.wish_id` (nullable, ON DELETE SET NULL)
so a persisted day knows which `leave_wish` produced it, `is_pinned` to mark a
day the user hand-edited, and `leave_wish.target_days` so a period drawn on a
calendar need not be a whole number of weeks. Apply-time identity still keys on
day_type/is_dubbeldag only, so a wish_id-only difference is a metadata update
rather than a collision.

The age-4 savable ceiling was applying the per-child figure of 96 to each
parent's pool, modelling a two-parent family as able to save 192 days past the
child's fourth birthday. `resolve_age4_savable_cap` is now the single place
that decides 48 (couple with two parents) versus 96 (everyone else), and both
AnalyticsService and the allocator read it.

Migration 009 drops `workspace.planning_goal` and `leave_wish.goal_override`.
The allocator's tier-3 policy collapses to one rule; `salary_type` still
branches, since that reflects what a vacation day actually costs a parent
rather than a user preference.
2026-09-15 20:28:06 +02:00

64 lines
1.8 KiB
Python

"""API schemas (Pydantic) for PlannedLeaveDay.
Schemas validate request bodies and shape responses. Separate from domain entities
so the wire format can evolve independently.
"""
from datetime import date, datetime
from uuid import UUID
from pydantic import BaseModel, Field
from app.entities.planned_leave import PlannedLeaveDay
class PlannedLeaveDayCreate(BaseModel):
workspace_id: UUID
child_id: UUID
parent_personal_data_uuid: UUID
date: date
day_type: str = Field(pattern="^(sjukpenning|lagsta|vacation)$")
is_dubbeldag: bool = False
# Which `LeaveWish` produced this day; None = ad-hoc.
wish_id: UUID | None = None
is_pinned: bool = False
class PlannedLeaveDayUpdate(BaseModel):
"""Partial update — all fields optional."""
day_type: str | None = Field(None, pattern="^(sjukpenning|lagsta|vacation)$")
is_dubbeldag: bool | None = None
wish_id: UUID | None = None
is_pinned: bool | None = None
class PlannedLeaveDayResponse(BaseModel):
id: UUID
workspace_id: UUID
child_id: UUID
parent_personal_data_uuid: UUID
date: date
day_type: str
is_dubbeldag: bool
wish_id: UUID | None
is_pinned: bool
created_at: datetime | None
updated_at: datetime | None
@classmethod
def from_entity(cls, entity: PlannedLeaveDay) -> "PlannedLeaveDayResponse":
return cls(
id=entity.id,
workspace_id=entity.workspace_id,
child_id=entity.child_id,
parent_personal_data_uuid=entity.parent_personal_data_uuid,
date=entity.date,
day_type=entity.day_type,
is_dubbeldag=entity.is_dubbeldag,
wish_id=entity.wish_id,
is_pinned=entity.is_pinned,
created_at=entity.created_at,
updated_at=entity.updated_at,
)