Neue Stammdaten-Tabelle einsatzfunktion (Migration 0031), benutzer bekommt optionales einsatzfunktion_id-Feld - analog zu einheit_id modelliert, eine Person hat im Regelfall genau eine primäre Einsatzfunktion. Bewusst getrennt von den technischen App-Rollen (RolleTyp), die nur steuern, was jemand in MABEA tun darf, nicht welche Funktion er im Einsatz hat. CRUD-Endpunkt /einsatzfunktionen nach Kategorie-Muster, Duplikat-Prüfung vorab (Projekt-Konvention). Admin-UI: Auswahl + Inline-Neuanlage in der Benutzerverwaltung (BenutzerSection). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
102 lines
4.1 KiB
Python
102 lines
4.1 KiB
Python
import enum
|
|
import uuid
|
|
from datetime import date
|
|
|
|
from sqlalchemy import CheckConstraint, Date, ForeignKey, String, UniqueConstraint
|
|
from sqlalchemy.dialects.postgresql import ENUM as PgEnum, UUID
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.db.base import Base
|
|
|
|
|
|
class Qualifikationskategorie(str, enum.Enum):
|
|
fuehrerschein = "fuehrerschein"
|
|
lehrgang = "lehrgang"
|
|
berechtigung = "berechtigung"
|
|
|
|
|
|
qualifikationskategorie_pg = PgEnum(
|
|
Qualifikationskategorie, name="qualifikationskategorie", create_type=False
|
|
)
|
|
|
|
|
|
class Einheit(Base):
|
|
"""Roadmap-Erweiterung (Personal-Modul): Organisationseinheit (Zug/Gruppe),
|
|
self-referenzierend für Hierarchie (analog Kategorie.ueberkategorie_id).
|
|
Bewusst eigenständig statt an Standort gekoppelt - eine Einheit kann
|
|
ortsübergreifend sein, ein Standort mehrere Einheiten beherbergen."""
|
|
|
|
__tablename__ = "einheit"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String, nullable=False)
|
|
uebergeordnete_einheit_id: Mapped[int | None] = mapped_column(ForeignKey("einheit.id"))
|
|
standort_id: Mapped[int | None] = mapped_column(ForeignKey("standort.id"))
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("uebergeordnete_einheit_id <> id", name="einheit_kein_selbstbezug"),
|
|
)
|
|
|
|
|
|
class Qualifikationstyp(Base):
|
|
"""Führerschein/Lehrgang/Berechtigung als ein Stammdaten-Konzept, damit
|
|
"welche Qualifikation braucht Objekttyp X" generisch bleibt (kein separates
|
|
Führerschein-Feld am Fahrzeug nötig, Karte-Nachtrag Personal-Modul)."""
|
|
|
|
__tablename__ = "qualifikationstyp"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String, nullable=False)
|
|
kategorie: Mapped[Qualifikationskategorie] = mapped_column(
|
|
qualifikationskategorie_pg, nullable=False
|
|
)
|
|
# NULL = unbefristet (z.B. manche Berechtigungen), sonst Gültigkeitsdauer in
|
|
# Monaten ab erworben_am - Ablauf wird nicht hier, sondern je
|
|
# BenutzerQualifikation über gueltig_bis geführt (individuelles Datum je
|
|
# Nachweis, nicht rein rechnerisch aus dem Typ abgeleitet).
|
|
gueltigkeit_monate: Mapped[int | None] = mapped_column()
|
|
|
|
|
|
class BenutzerQualifikation(Base):
|
|
__tablename__ = "benutzer_qualifikation"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
benutzer_id: Mapped[int] = mapped_column(ForeignKey("benutzer.id"), nullable=False)
|
|
qualifikationstyp_id: Mapped[int] = mapped_column(ForeignKey("qualifikationstyp.id"), nullable=False)
|
|
erworben_am: Mapped[date] = mapped_column(Date, nullable=False)
|
|
gueltig_bis: Mapped[date | None] = mapped_column(Date)
|
|
nachweis_nummer: Mapped[str | None] = mapped_column(String)
|
|
|
|
__table_args__ = (
|
|
UniqueConstraint(
|
|
"benutzer_id", "qualifikationstyp_id", "erworben_am", name="uq_benutzer_qualifikation"
|
|
),
|
|
)
|
|
|
|
|
|
class Einsatzfunktion(Base):
|
|
"""PERS-004: Funktion im Einsatzkontext (z.B. Gruppenführer, Truppführer,
|
|
Melder, Maschinist, Atemschutzgeräteträger) - unabhängig von den
|
|
technischen App-Rollen (RolleTyp: mitarbeiter/materialverantwortlicher/
|
|
...), die nur steuern, was jemand in MABEA tun darf, nicht welche Funktion
|
|
er im Einsatz hat. Bewusst analog zu Benutzer.einheit_id als einzelnes
|
|
optionales Feld modelliert, nicht als M:N - eine Person hat im Regelfall
|
|
genau eine primäre Einsatzfunktion, keine Historie/Zeitraum nötig."""
|
|
|
|
__tablename__ = "einsatzfunktion"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String, unique=True, nullable=False)
|
|
|
|
|
|
class ObjekttypQualifikationsanforderung(Base):
|
|
"""M:N: welche Qualifikationstypen braucht man, um Objekte dieses Objekttyps
|
|
zu bedienen/fahren (Nutzer-Beispiel: "wer darf GW-San 01 fahren?")."""
|
|
|
|
__tablename__ = "objekttyp_qualifikationsanforderung"
|
|
|
|
objekttyp_id: Mapped[int] = mapped_column(ForeignKey("objekttyp.id"), primary_key=True)
|
|
qualifikationstyp_id: Mapped[int] = mapped_column(
|
|
ForeignKey("qualifikationstyp.id"), primary_key=True
|
|
)
|