Rechnungen sind finanziell sensibel - nur Materialverantwortliche/ Leitungsverantwortliche/Administration dürfen sie in der Liste sehen und herunterladen (403 bei direktem Downloadversuch), Mitarbeiter nicht. Hochladen bleibt für alle offen (z.B. Wareneingang direkt scannen). Andere Dokumenttypen bleiben unverändert für jeden mit Aktenzugriff sichtbar - die werden im Feldeinsatz gebraucht. EINGESCHRAENKTE_DOKUMENTTYPEN als zentrale Stelle für künftige weitere Einschränkungen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
64 lines
3.0 KiB
Python
64 lines
3.0 KiB
Python
import enum
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import ForeignKey, Integer, String
|
|
from sqlalchemy.dialects.postgresql import ENUM as PgEnum, TIMESTAMP, UUID
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.db.base import Base
|
|
|
|
|
|
class DokumentTyp(str, enum.Enum):
|
|
"""DOC-002: feste Kategorie statt Freitext - macht Dokumente filter-/
|
|
wiederfindbar (Nutzer-Vorgabe Modul 10: Prüfprotokolle/Wartungsberichte/
|
|
Bedienungsanleitungen/Rechnungen/Zulassungsdokumente)."""
|
|
|
|
pruefprotokoll = "pruefprotokoll"
|
|
wartungsbericht = "wartungsbericht"
|
|
bedienungsanleitung = "bedienungsanleitung"
|
|
rechnung = "rechnung"
|
|
zulassungsdokument = "zulassungsdokument"
|
|
sonstiges = "sonstiges"
|
|
|
|
|
|
dokument_typ_pg = PgEnum(DokumentTyp, name="dokument_typ", create_type=False)
|
|
|
|
# DOC-005: Rechnungen sind finanziell sensibel - nur Materialverantwortliche/
|
|
# Leitungsverantwortliche/Administration dürfen sie sehen/herunterladen,
|
|
# Mitarbeiter nicht (dürfen sie aber weiterhin hochladen, z.B. direkt beim
|
|
# Wareneingang scannen). Andere Dokumenttypen (Prüfprotokolle, Anleitungen,
|
|
# ...) bleiben für alle mit Zugriff auf die Akte sichtbar - die werden im
|
|
# Feld gebraucht.
|
|
EINGESCHRAENKTE_DOKUMENTTYPEN = {DokumentTyp.rechnung}
|
|
|
|
|
|
class Dokument(Base):
|
|
"""Roadmap Phase 5 (Modul Dokumente): polymorpher Datei-Anhang an beliebige
|
|
Ressource (Objekt, Objektposition, Geräteinstanz, Mangel, Fahrzeugdetails,
|
|
Benutzer, ...) - gleiches entitaet_typ/entitaet_id-Muster wie Historie/
|
|
Mangel. Datei liegt lokal auf Platte (self-hosted, kein Cloud-Zwang),
|
|
speicherpfad ist relativ zu settings.upload_dir."""
|
|
|
|
__tablename__ = "dokument"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
entitaet_typ: Mapped[str] = mapped_column(String, nullable=False)
|
|
entitaet_id: Mapped[str] = mapped_column(String, nullable=False)
|
|
dateiname: Mapped[str] = mapped_column(String, nullable=False)
|
|
speicherpfad: Mapped[str] = mapped_column(String, nullable=False)
|
|
mime_type: Mapped[str] = mapped_column(String, nullable=False)
|
|
groesse_bytes: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
# SHA-256 des Dateiinhalts (DOC-001: Duplikat-Erkennung) - hex-codiert, 64
|
|
# Zeichen. Vergleich nur innerhalb derselben entitaet_typ/entitaet_id, nicht
|
|
# global (gleiche Datei an zwei verschiedenen Objekten ist kein Duplikat).
|
|
# Nullable wegen Altbestand vor dieser Migration (Hash nachträglich ohne
|
|
# Dateizugriff nicht sinnvoll befüllbar); jeder neue Upload setzt ihn.
|
|
dateihash: Mapped[str | None] = mapped_column(String(64))
|
|
dokumenttyp: Mapped[DokumentTyp] = mapped_column(
|
|
dokument_typ_pg, nullable=False, default=DokumentTyp.sonstiges
|
|
)
|
|
beschreibung: Mapped[str | None] = mapped_column(String)
|
|
hochgeladen_von: Mapped[int] = mapped_column(ForeignKey("benutzer.id"), nullable=False)
|
|
hochgeladen_am: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), nullable=False)
|