feat(maintenance): MAINT-Epic (Wartungspläne/-aufträge, Werkstatt) + Akte-Redesign
CI / backend-tests (push) Failing after 2m4s
CI / frontend-build (push) Successful in 18s

Neues Wartungskonzept: Wartungsplan+Position+Intervall (zeit/km/
Betriebsstunden, kombinierbar - fällig sobald ein Kriterium erreicht
ist), Wartungsauftrag mit intern/externer Werkstatt, Status offen/
in_arbeit/erledigt, Kosten, Historie, Dokument-Anhang. Ad-hoc-Aufträge
ohne Plan möglich (z.B. kleinere Reparatur). Admin-Tab "Wartungspläne".

Objektakte-Redesign (Epic 21, Nutzer-Feedback "wirkt nicht modern"):
CSS-Grid statt Karten-Stapel, einspaltig mobil, zweispaltig ab 900px;
Fahrzeug-Objekte zeigen Wartung/Fahrzeugdaten prominent, Geräte/
Rucksäcke die Beladung. Dabei gefundene Lücke: Beladung (Soll/Ist je
Position) fehlte in der Akte komplett, nur über eine laufende
Kontrolle sichtbar - jetzt eigene Karte.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
2026-09-06 23:17:39 +02:00
co-authored by Claude Sonnet 5
parent d607a1101d
commit 2a4d391711
23 changed files with 1505 additions and 44 deletions
+30 -3
View File
@@ -9,9 +9,10 @@ from app.models.historie import Historie
from app.models.mangel import Mangel
from app.models.objekt import Objekt
from app.models.objektposition import Objektposition
from app.models.stammdaten import Objekttyp, Standort
from app.models.stammdaten import Material, Objekttyp, Standort
from app.models.vorlage import Vorlagenposition
from app.models.zustaendigkeit import Kontrollverantwortung, Zustaendigkeit
from app.schemas.akte import AkteRead, ZustaendigerBenutzer
from app.schemas.akte import AkteRead, BeladungsPosition, ZustaendigerBenutzer
from app.schemas.dokument import DokumentRead
from app.schemas.geraet_instanz import GeraetInstanzRead
from app.schemas.historie import HistorieRead
@@ -19,7 +20,7 @@ from app.schemas.mangel import MangelRead
from app.schemas.objekt import FahrzeugdetailsRead, ObjektRead
from app.schemas.zustaendigkeit import KontrollverantwortungRead
from app.services.dashboard import objekt_readiness
from app.services.objekte import letzte_kontrollen_map
from app.services.objekte import letzte_kontrollen_map, sollmenge_effektiv
async def _zustaendige_benutzer(db: AsyncSession, objekt: Objekt) -> list[ZustaendigerBenutzer]:
@@ -90,6 +91,31 @@ async def akte_fuer_objekt(db: AsyncSession, objekt_id: int) -> AkteRead | None:
maengel_result = await db.execute(select(Mangel).where(Mangel.objekt_id == objekt_id))
fach_by_material_id: dict[int, str | None] = {}
if objekt.vorlage_id is not None:
vorlagenpositionen_result = await db.execute(
select(Vorlagenposition).where(Vorlagenposition.vorlage_id == objekt.vorlage_id)
)
fach_by_material_id = {vp.material_id: vp.fach for vp in vorlagenpositionen_result.scalars().all()}
beladung_result = await db.execute(
select(Objektposition, Material)
.join(Material, Objektposition.material_id == Material.id)
.where(Objektposition.objekt_id == objekt_id)
)
beladung = [
BeladungsPosition(
objektposition_id=position.id,
material_id=material.id,
material_name=material.name,
einheit=material.einheit,
fach=fach_by_material_id.get(material.id),
sollmenge=sollmenge_effektiv(position),
istmenge=position.istmenge,
)
for position, material in beladung_result.all()
]
readiness = await objekt_readiness(db, objekt_id)
objekt_read = ObjektRead.model_validate(objekt).model_copy(
@@ -115,4 +141,5 @@ async def akte_fuer_objekt(db: AsyncSession, objekt_id: int) -> AkteRead | None:
dokumente=[DokumentRead.model_validate(d) for d in dokumente_result.scalars().all()],
geraete=[GeraetInstanzRead.model_validate(g) for g in geraete],
maengel=[MangelRead.model_validate(m) for m in maengel_result.scalars().all()],
beladung=beladung,
)