767ff9fb9d
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
76 lines
2.6 KiB
Python
76 lines
2.6 KiB
Python
"""Sondervertretungs-Faktoren: special_assignments Tabelle
|
||
|
||
Revision ID: 0029
|
||
Revises: 0028
|
||
Create Date: 2026-05-25
|
||
|
||
Neue Tabelle special_assignments:
|
||
- user_id + company_id (ForeignKeys mit CASCADE)
|
||
- date_from / date_to
|
||
- factor NUMERIC(5,3) – Multiplikator (z.B. 1.5)
|
||
- mode ENUM(fza|payroll|both)
|
||
- label / description (optional)
|
||
- Overlap-Check per Constraint (date_from <= date_to) + App-seitige Prüfung
|
||
"""
|
||
from alembic import op
|
||
|
||
revision = "0029"
|
||
down_revision = "0028"
|
||
branch_labels = None
|
||
depends_on = None
|
||
|
||
|
||
def upgrade() -> None:
|
||
op.execute("CREATE EXTENSION IF NOT EXISTS btree_gist")
|
||
|
||
# Enum erzeugen (nur falls nicht vorhanden – CREATE TYPE IF NOT EXISTS nicht überall unterstützt)
|
||
op.execute("""
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'assignment_mode') THEN
|
||
CREATE TYPE assignment_mode AS ENUM ('fza', 'payroll', 'both');
|
||
END IF;
|
||
END $$
|
||
""")
|
||
|
||
# Tabelle nur anlegen falls noch nicht vorhanden (idempotent)
|
||
op.execute("""
|
||
CREATE TABLE IF NOT EXISTS special_assignments (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||
company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
|
||
date_from DATE NOT NULL,
|
||
date_to DATE NOT NULL,
|
||
factor NUMERIC(5,3) NOT NULL,
|
||
mode assignment_mode NOT NULL DEFAULT 'both',
|
||
label VARCHAR(100),
|
||
description TEXT,
|
||
CONSTRAINT ck_special_assignment_factor CHECK (factor > 0 AND factor <= 10),
|
||
CONSTRAINT ck_special_assignment_dates CHECK (date_from <= date_to)
|
||
)
|
||
""")
|
||
op.execute("CREATE INDEX IF NOT EXISTS ix_special_assignments_user_id ON special_assignments(user_id)")
|
||
op.execute("CREATE INDEX IF NOT EXISTS ix_special_assignments_company_id ON special_assignments(company_id)")
|
||
|
||
# Exclusion Constraint (nur falls noch nicht vorhanden)
|
||
op.execute("""
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'special_assignments_no_overlap'
|
||
) THEN
|
||
ALTER TABLE special_assignments
|
||
ADD CONSTRAINT special_assignments_no_overlap
|
||
EXCLUDE USING gist (
|
||
user_id WITH =,
|
||
daterange(date_from, date_to, '[]') WITH &&
|
||
);
|
||
END IF;
|
||
END $$
|
||
""")
|
||
|
||
|
||
def downgrade() -> None:
|
||
op.execute("DROP TABLE IF EXISTS special_assignments")
|
||
op.execute("DROP TYPE IF EXISTS assignment_mode")
|