import enum import uuid from datetime import date from decimal import Decimal from sqlalchemy import Date, ForeignKey, Numeric, 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 ObjektpositionStatus(str, enum.Enum): aktiv = "aktiv" entfernt = "entfernt" objektposition_status_pg = PgEnum( ObjektpositionStatus, name="objektposition_status", create_type=False ) class Objektposition(Base): """Prompt 10: Ist-Bestand + individuelle Soll-Abweichung je Objekt/Material. UUID-PK (Karte 13: sync-relevant, siehe ergebnisse/20_datenbank_schema.md).""" __tablename__ = "objektposition" __table_args__ = (UniqueConstraint("objekt_id", "material_id"),) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) objekt_id: Mapped[int] = mapped_column(ForeignKey("objekt.id"), nullable=False) material_id: Mapped[int] = mapped_column(ForeignKey("material.id"), nullable=False) # NULL = Sollmenge folgt dynamisch der aktuellen Vorlagenposition (Prompt 10). sollmenge_override: Mapped[Decimal | None] = mapped_column(Numeric) ist_status: Mapped[ObjektpositionStatus] = mapped_column( objektposition_status_pg, nullable=False, default=ObjektpositionStatus.aktiv ) istmenge: Mapped[Decimal] = mapped_column(Numeric, nullable=False, default=0) seriennummer: Mapped[str | None] = mapped_column(String) ablaufdatum: Mapped[date | None] = mapped_column(Date) chargennummer: Mapped[str | None] = mapped_column(String) # Code128-Etikett für Geräte-Exemplare (Konzept-Ergänzung Karte 10/Prompt 09), # separat von seriennummer: Code identifiziert das gedruckte Label, SN das # Herstellerattribut - beide können divergieren (Etikett verloren/neu vergeben). code: Mapped[str | None] = mapped_column(String, unique=True)