feat(identity): IDENT-003 konfigurierbare Nummernschemata je Objekttyp
CI / backend-tests (push) Successful in 2m24s
CI / frontend-build (push) Successful in 27s

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:
2026-09-08 20:23:14 +02:00
co-authored by Claude Sonnet 5
parent 15f783fb5e
commit 3b5cf8feab
12 changed files with 380 additions and 53 deletions
+51 -1
View File
@@ -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])