feat(identity): IDENT-003 konfigurierbare Nummernschemata je Objekttyp
Neue Stammdaten-Tabelle nummernschema (Migration 0032): Präfix + Stellenzahl einmal je Objekttyp festlegen statt bei jeder Objekt-Anlage manuell einzutippen (Fehlerquelle - Tippfehler, uneinheitliche Schreibweise, falsches Präfix für den Typ). GET /objekte/naechster-code akzeptiert jetzt objekttyp_id als Alternative zu praefix; ohne konfiguriertes Schema bleibt der bisherige manuelle Präfix-Weg nutzbar (Rückwärtskompatibilität). Admin-UI: Nummernschema-Pflege direkt in der Objekttyp-Verwaltung (ObjekttypSection). ObjektAnlegenFormular versucht zuerst das Schema des gewählten Objekttyps, fällt bei 404 auf manuelles Präfix zurück. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
@@ -12,7 +12,7 @@ from app.models.auth import KnotenTyp, RolleTyp, Systemknoten
|
||||
from app.models.fahrzeugdetails import Fahrzeugdetails
|
||||
from app.models.objekt import Objekt
|
||||
from app.models.objektposition import Objektposition
|
||||
from app.models.stammdaten import Material, Objekttyp
|
||||
from app.models.stammdaten import Material, Nummernschema, Objekttyp
|
||||
from app.models.vorlage import Beladungsvorlage
|
||||
from app.services import historie as historie_service
|
||||
from app.services.label import generiere_code128_label_pdf, generiere_qr_label_pdf
|
||||
@@ -105,11 +105,32 @@ async def hole_objekt_per_code(
|
||||
|
||||
@router.get("/objekte/naechster-code")
|
||||
async def naechster_objekt_code(
|
||||
praefix: str, db: AsyncSession = Depends(get_db), _=Depends(get_current_user)
|
||||
praefix: str | None = None,
|
||||
objekttyp_id: int | None = None,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_=Depends(get_current_user),
|
||||
) -> dict[str, str]:
|
||||
"""Code-Vorschlag beim Anlegen/Duplizieren (Konzept-Ergänzung Karte 10/Prompt 09).
|
||||
Vorschlag ist überschreibbar, Eindeutigkeit erzwingt weiterhin objekt.code UNIQUE."""
|
||||
return {"code": await naechster_freier_code(db, Objekt.code, praefix)}
|
||||
Vorschlag ist überschreibbar, Eindeutigkeit erzwingt weiterhin objekt.code UNIQUE.
|
||||
|
||||
IDENT-003: `objekttyp_id` statt `praefix` nutzt das konfigurierte
|
||||
Nummernschema (Präfix + Mindest-Stellenzahl) - kein manuelles Eintippen/
|
||||
Merken des richtigen Präfix je Objekttyp mehr nötig. `praefix` bleibt für
|
||||
Objekttypen ohne konfiguriertes Schema nutzbar (Rückwärtskompatibilität)."""
|
||||
stellenzahl = 5
|
||||
if objekttyp_id is not None:
|
||||
result = await db.execute(select(Nummernschema).where(Nummernschema.objekttyp_id == objekttyp_id))
|
||||
schema = result.scalar_one_or_none()
|
||||
if schema is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Kein Nummernschema für diesen Objekttyp konfiguriert - Präfix manuell angeben",
|
||||
)
|
||||
praefix = schema.praefix
|
||||
stellenzahl = schema.stellenzahl
|
||||
if not praefix:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Präfix oder Objekttyp angeben")
|
||||
return {"code": await naechster_freier_code(db, Objekt.code, praefix, stellenzahl)}
|
||||
|
||||
|
||||
@router.get("/objektpositionen/naechster-code")
|
||||
|
||||
@@ -6,7 +6,7 @@ from app.api.deps import get_current_user, require_roles, require_roles_or_permi
|
||||
from app.db.session import get_db
|
||||
from app.models.auth import RolleTyp
|
||||
from app.models.objekt import Objekt
|
||||
from app.models.stammdaten import Bereich, Fach, Hersteller, Kategorie, Material, Modell, Objekttyp, Standort
|
||||
from app.models.stammdaten import Bereich, Fach, Hersteller, Kategorie, Material, Modell, Nummernschema, Objekttyp, Standort
|
||||
from app.models.vorlage import Beladungsvorlage, Vorlagenposition
|
||||
from app.services.material_merge import finde_konflikte, fuehre_zusammen, hole_verwendung
|
||||
from app.schemas.stammdaten import (
|
||||
@@ -25,6 +25,9 @@ from app.schemas.stammdaten import (
|
||||
KategorieUpdate,
|
||||
ModellCreate,
|
||||
ModellRead,
|
||||
NummernschemaCreate,
|
||||
NummernschemaRead,
|
||||
NummernschemaUpdate,
|
||||
MaterialCreate,
|
||||
MaterialRead,
|
||||
MaterialUpdate,
|
||||
@@ -141,6 +144,53 @@ async def erstelle_modell(
|
||||
return modell
|
||||
|
||||
|
||||
# -- Nummernschema (IDENT-003) ---------------------------------------------------
|
||||
|
||||
@router.get("/nummernschemata", response_model=list[NummernschemaRead])
|
||||
async def liste_nummernschemata(
|
||||
db: AsyncSession = Depends(get_db), _=Depends(get_current_user)
|
||||
) -> list[Nummernschema]:
|
||||
result = await db.execute(select(Nummernschema))
|
||||
return list(result.scalars().all())
|
||||
|
||||
|
||||
@router.post("/nummernschemata", response_model=NummernschemaRead, status_code=status.HTTP_201_CREATED)
|
||||
async def erstelle_nummernschema(
|
||||
payload: NummernschemaCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_=Depends(require_roles(RolleTyp.administration)),
|
||||
) -> Nummernschema:
|
||||
if await db.get(Objekttyp, payload.objekttyp_id) is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Objekttyp nicht gefunden")
|
||||
bestehendes = await db.execute(
|
||||
select(Nummernschema).where(Nummernschema.objekttyp_id == payload.objekttyp_id)
|
||||
)
|
||||
if bestehendes.scalar_one_or_none() is not None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="Für diesen Objekttyp existiert bereits ein Nummernschema"
|
||||
)
|
||||
schema = Nummernschema(**payload.model_dump())
|
||||
db.add(schema)
|
||||
await db.flush()
|
||||
return schema
|
||||
|
||||
|
||||
@router.patch("/nummernschemata/{schema_id}", response_model=NummernschemaRead)
|
||||
async def aendere_nummernschema(
|
||||
schema_id: int,
|
||||
payload: NummernschemaUpdate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_=Depends(require_roles(RolleTyp.administration)),
|
||||
) -> Nummernschema:
|
||||
schema = await db.get(Nummernschema, schema_id)
|
||||
if schema is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Nummernschema nicht gefunden")
|
||||
for feld, wert in payload.model_dump(exclude_unset=True).items():
|
||||
setattr(schema, feld, wert)
|
||||
await db.flush()
|
||||
return schema
|
||||
|
||||
|
||||
# -- Kategorie ------------------------------------------------------------------
|
||||
|
||||
@router.get("/kategorien", response_model=list[KategorieRead])
|
||||
|
||||
Reference in New Issue
Block a user