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
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
"""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")
|
||||
Reference in New Issue
Block a user