Let a household choose to be paid for the red days

Asking for a full week off never spent anything on the Saturday, the
Sunday or a holiday, and a test now says so outright rather than leaving
it to be rediscovered. Those days are free because vacation cannot be
taken on a day that is not a working day.

Parental benefit is a payment rather than a schedule, though, so it can
be drawn on a red day to turn an unpaid day off into a paid one — at the
cost of a day the family would otherwise keep. That is now a workspace
setting, off by default, and it never reaches for a vacation day. With it
off the planner behaves exactly as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ei7gCZzdd751uZtPzb1Pep
This commit is contained in:
2026-09-19 14:28:38 +02:00
parent 1837154225
commit b87ad0e7ad
18 changed files with 511 additions and 10 deletions
@@ -0,0 +1,38 @@
"""Add workspace.take_pl_on_red_days.
Per-workspace opt-in (default off) letting the planning engine fund a free
day (Saturday, Sunday, public holiday) with a parental-benefit day instead of
leaving it unpaid — never with a vacation day, since Swedish law does not let
you "take vacation" on a day that already isn't a working day. See
`app.services.allocation_service.REASON_FP_RED_DAY` and
`AllocationInput.take_pl_on_red_days`.
A plain `ADD COLUMN` suffices here (unlike 002's CHECK-constraint change,
which needed a full table rebuild) since SQLite supports adding a NOT NULL
column with a constant DEFAULT directly.
Must stay byte-for-byte equivalent to the `workspace` table in
`app/db/connection.py`'s `_FULL_SCHEMA` — `tests/integration/test_schema_parity.py`
asserts exactly that.
Revision ID: 003
Revises: 002
Create Date: 2026-09-19
"""
from __future__ import annotations
from alembic import op
revision: str = "003"
down_revision: str | None = "002"
branch_labels: str | None = None
depends_on: str | None = None
def upgrade() -> None:
op.execute("ALTER TABLE workspace ADD COLUMN take_pl_on_red_days BOOLEAN NOT NULL DEFAULT 0")
def downgrade() -> None:
op.execute("ALTER TABLE workspace DROP COLUMN take_pl_on_red_days")