Files
MABEA/backend/app/schemas/kontrolle.py
T
patrickandClaude Sonnet 5 8fd507cc5d
CI / backend-tests (push) Successful in 38s
Sprint 3: Kontroll-Kern (Statusmaschine, Objekt-Sperre, automatische Fehlbestand-Erzeugung)
- Kontrolle/Kontrollposition-Modelle: Kontrolle ändert NIEMALS Objektposition.istmenge
  (Vier-Kernbegriffe-Tabelle, Prompt 02.9) - reine Erfassung/Snapshot
- Objekt-Sperre (Prompt 02.8): Kontrolle.status='in_bearbeitung' + benutzer_id IST die
  Sperre, kein separates Sperr-Modell. Zweiter Zugriff -> 409 mit wer/seit; Übernahme
  bricht alte Kontrolle ab (Datensatz bleibt, Prompt 16.6-Analogie) und protokolliert
  das Ereignis in einer neuen, minimalen Historie-Tabelle (volle Ausbaustufe Sprint 5)
- Automatische Fehlbestand-Erzeugung bei Ist < Soll (U1), Überbestand erzeugt
  ausdrücklich KEINEN Fehlbestand (Prompt 02.4); Korrektur vor Abschluss möglich
  (von derselben Kontrolle erzeugter Fehlbestand ist bis zum Abschluss nicht final)
- Abschluss verweigert bei unbestätigten Positionen, liefert deren IDs (U11)
- Abbruch verwirft Kontrollpositionen UND von dieser Kontrolle erzeugte Fehlbestände,
  Kontrolle selbst bleibt als Datensatz mit Status "abgebrochen" erhalten (U12)
- Tests: U1, U11, U12, Sperre/409, Übernahme, Fremdzugriff/403, parallele Objekte

Mitarbeiter-UI (PWA-Frontend) ist bewusst noch nicht Teil dieses Commits - eigenes
Techstack-Setup, wird als nächster Schritt separat angegangen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-03 23:40:26 +02:00

48 lines
1.0 KiB
Python

import uuid
from datetime import datetime
from decimal import Decimal
from pydantic import BaseModel, ConfigDict
from app.models.kontrolle import KontrollStatus
class KontrolleCreate(BaseModel):
uebernehmen: bool = False
class KontrolleRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
objekt_id: int
benutzer_id: int
status: KontrollStatus
gestartet_am: datetime
beendet_am: datetime | None
abbruch_grund: str | None
class KontrollpositionInput(BaseModel):
istmenge: Decimal
class KontrollpositionRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
kontrolle_id: uuid.UUID
material_id: int
sollmenge_snapshot: Decimal
istmenge_erfasst: Decimal
abweichung: bool
class KontrolleAbbrechenRequest(BaseModel):
grund: str | None = None
class KontrolleFortschritt(BaseModel):
kontrolle: KontrolleRead
positionen: list[KontrollpositionRead]
anzahl_positionen_gesamt: int
anzahl_positionen_erfasst: int