feat(personal): Personal/Qualifikationen-Modul (Roadmap Phase 1)
Neues Modul für die BOS-Ressourcenplattform-Erweiterung: Einheit (Zug/Gruppe,
self-referenzierend), Qualifikationstyp (Führerschein/Lehrgang/Berechtigung),
BenutzerQualifikation (mit Gültigkeit) und ObjekttypQualifikationsanforderung
(M:N) - beantwortet "wer darf dieses Fahrzeug fahren?" über
GET /objekte/{id}/berechtigung/{benutzer_id}.
Benutzer und Objekt bekommen optionale einheit_id (additiv, analog
fahrzeug_id-Muster). Nebenbei Bugfix: PATCH /benutzer konnte einheit_id nicht
auf null setzen (Feld-vorhanden-Check via model_fields_set statt is not None).
Frontend: neuer Admin-Tab "Personal" (Einheiten, Qualifikationstypen,
Benutzer-Qualifikationszuordnung), Einheit-Auswahl im Benutzer-Formular.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""Personal/Qualifikationen-Modul (Roadmap-Erweiterung, Phase 1 nach BOS-
|
||||
Ressourcenplattform-Anforderung): Einheit-Hierarchie, Qualifikationstypen
|
||||
(Führerschein/Lehrgang/Berechtigung), Benutzer-Qualifikationszuordnung mit
|
||||
Gültigkeit, sowie welche Qualifikation ein Objekttyp (z.B. Fahrzeug) zum
|
||||
Bedienen voraussetzt - beantwortet "wer darf dieses Fahrzeug fahren?".
|
||||
|
||||
Revision ID: 0012_personal_qualifikationen
|
||||
Revises: 0011_objekttyp_zugfahrzeug
|
||||
Create Date: 2026-09-05
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision: str = "0012_personal_qualifikationen"
|
||||
down_revision: Union[str, None] = "0011_objekttyp_zugfahrzeug"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.execute("CREATE TYPE qualifikationskategorie AS ENUM ('fuehrerschein', 'lehrgang', 'berechtigung')")
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TABLE einheit (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
uebergeordnete_einheit_id INTEGER REFERENCES einheit(id),
|
||||
standort_id INTEGER REFERENCES standort(id),
|
||||
CONSTRAINT einheit_kein_selbstbezug CHECK (uebergeordnete_einheit_id <> id)
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute("CREATE INDEX idx_einheit_uebergeordnet ON einheit (uebergeordnete_einheit_id)")
|
||||
|
||||
op.execute("ALTER TABLE benutzer ADD COLUMN einheit_id INTEGER REFERENCES einheit(id)")
|
||||
# Fahrzeuge/Objekte künftig einer Einheit zuordenbar (analog fahrzeug_id-Muster
|
||||
# aus Migration 0010: additiv, NULL = keiner Einheit zugeordnet).
|
||||
op.execute("ALTER TABLE objekt ADD COLUMN einheit_id INTEGER REFERENCES einheit(id)")
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TABLE qualifikationstyp (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
kategorie qualifikationskategorie NOT NULL,
|
||||
gueltigkeit_monate INTEGER
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TABLE benutzer_qualifikation (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
benutzer_id INTEGER NOT NULL REFERENCES benutzer(id),
|
||||
qualifikationstyp_id INTEGER NOT NULL REFERENCES qualifikationstyp(id),
|
||||
erworben_am DATE NOT NULL,
|
||||
gueltig_bis DATE,
|
||||
nachweis_nummer TEXT,
|
||||
UNIQUE (benutzer_id, qualifikationstyp_id, erworben_am)
|
||||
)
|
||||
"""
|
||||
)
|
||||
op.execute("CREATE INDEX idx_benutzer_qualifikation_benutzer ON benutzer_qualifikation (benutzer_id)")
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TABLE objekttyp_qualifikationsanforderung (
|
||||
objekttyp_id INTEGER NOT NULL REFERENCES objekttyp(id),
|
||||
qualifikationstyp_id INTEGER NOT NULL REFERENCES qualifikationstyp(id),
|
||||
PRIMARY KEY (objekttyp_id, qualifikationstyp_id)
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute("DROP TABLE objekttyp_qualifikationsanforderung")
|
||||
op.execute("DROP TABLE benutzer_qualifikation")
|
||||
op.execute("DROP TABLE qualifikationstyp")
|
||||
op.execute("ALTER TABLE objekt DROP COLUMN einheit_id")
|
||||
op.execute("ALTER TABLE benutzer DROP COLUMN einheit_id")
|
||||
op.execute("DROP TABLE einheit")
|
||||
op.execute("DROP TYPE IF EXISTS qualifikationskategorie")
|
||||
Reference in New Issue
Block a user