Files
MABEA/backend/alembic/versions/0013_mangel.py
T
patrickandClaude Sonnet 5 eb20affd5d
CI / backend-tests (push) Failing after 1m37s
CI / frontend-build (push) Successful in 18s
feat(mangel): Mangel-Ticket-System (Roadmap Phase 2)
Eigener Workflow für Schäden/Defekte, getrennt von Fehlbestand (Mengen-
Abweichung Soll/Ist). Status: neu → in_bearbeitung → ersatzteil_bestellt/
reparatur_geplant → erledigt. entitaet_typ/entitaet_id optional (Objektposition
oder Geräteinstanz), analog zum bestehenden historie.entitaet_typ-Muster,
objekt_id immer gesetzt für Dashboard-Abfragen.

Ein offener Mangel mit prioritaet=hoch macht das Objekt "nicht einsatzbereit"
(neuer Grund mangel_kritisch_offen in dashboard.einsatzbereitschaft) -
niedrige/normale Mängel blockieren nicht.

Melden/Lesen: alle Mitarbeiter+. Status ändern: Materialverantwortliche+.
Neue Seite /maengel für alle eingeloggten Nutzer (Nav-Link "Mängel").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:23:38 +02:00

63 lines
2.4 KiB
Python

"""Mangel-Ticket-System (Roadmap Phase 2, BOS-Ressourcenplattform-Erweiterung).
Eigener Workflow für Schäden/Defekte - getrennt von Fehlbestand (Mengen-
Abweichung Soll/Ist), da fachlich verschieden (Nutzer-Beispiel: "Blaulicht
vorne rechts defekt" ist kein Fehlbestand). entitaet_typ/entitaet_id als
String-Polymorphie analog historie.entitaet_typ/entitaet_id (bestehendes
Muster, keine FK-Integrität nötig - Mangel bleibt auch dann lesbar, wenn die
konkrete Objektposition/Geraet-Instanz später gelöscht wird). objekt_id
zusätzlich direkt/redundant gespeichert (wie fehlbestand.objekt_id), damit die
Einsatzbereitschafts-Abfrage (Dashboard) nicht über die polymorphe Spalte
joinen muss.
Revision ID: 0013_mangel
Revises: 0012_personal_qualifikationen
Create Date: 2026-09-05
"""
from typing import Sequence, Union
from alembic import op
revision: str = "0013_mangel"
down_revision: Union[str, None] = "0012_personal_qualifikationen"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.execute(
"CREATE TYPE mangel_status AS ENUM "
"('neu', 'in_bearbeitung', 'ersatzteil_bestellt', 'reparatur_geplant', 'erledigt')"
)
op.execute("CREATE TYPE mangel_prioritaet AS ENUM ('niedrig', 'normal', 'hoch')")
op.execute(
"""
CREATE TABLE mangel (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
objekt_id INTEGER NOT NULL REFERENCES objekt(id),
entitaet_typ TEXT,
entitaet_id TEXT,
beschreibung TEXT NOT NULL,
prioritaet mangel_prioritaet NOT NULL DEFAULT 'normal',
status mangel_status NOT NULL DEFAULT 'neu',
gemeldet_von INTEGER NOT NULL REFERENCES benutzer(id),
gemeldet_am TIMESTAMPTZ NOT NULL,
erledigt_von INTEGER REFERENCES benutzer(id),
erledigt_am TIMESTAMPTZ,
CONSTRAINT mangel_entitaet_beide_oder_keins CHECK (
(entitaet_typ IS NULL AND entitaet_id IS NULL)
OR (entitaet_typ IS NOT NULL AND entitaet_id IS NOT NULL)
)
)
"""
)
op.execute("CREATE INDEX idx_mangel_objekt ON mangel (objekt_id)")
op.execute("CREATE INDEX idx_mangel_status ON mangel (status)")
def downgrade() -> None:
op.execute("DROP TABLE mangel")
op.execute("DROP TYPE IF EXISTS mangel_prioritaet")
op.execute("DROP TYPE IF EXISTS mangel_status")