IT-Stock/app/routers/materiels.py
maxsoch 7ce6540924 Refonte des listings et arborescence de catégories à profondeur illimitée
Catégorie/SousCategorie fusionnées en un seul modèle auto-référencé
(parent_id), pour permettre une imbrication sans limite de niveaux. Les
listings matériels/catégories/destinataires passent en lignes repliées
(<details>) avec recherche côté serveur, ce qui corrige le débordement
horizontal du tableau tout-en-input et reste utilisable sur de longues
listes. Style de l'écran de scan également retravaillé (frontend-design).
2026-07-14 19:06:37 +02:00

104 lines
3.4 KiB
Python

"""
Routes pour la gestion des matériels : le cœur du stock.
Un "matériel" représente un type d'objet suivi en stock (nom + code-barre
optionnel + quantité), pas un exemplaire individuel — voir app/models.py.
"""
from fastapi import APIRouter, Depends, Form
from fastapi.requests import Request
from fastapi.responses import RedirectResponse
from sqlmodel import Session, select
from app.categories_arbre import aplatir, categories_racines
from app.database import get_session
from app.email_alerts import verifier_et_alerter
from app.models import Materiel
from app.templates_engine import templates
router = APIRouter()
@router.get("/materiels")
def lister_materiels(request: Request, q: str = "", session: Session = Depends(get_session)):
"""Liste les matériels, filtrés par nom ou code-barre si ?q=... est
fourni (recherche insensible à la casse). Indispensable dès que la
liste devient longue : pas de pagination, juste un filtre texte."""
tous = session.exec(select(Materiel)).all()
if q:
q_normalise = q.lower()
materiels = [
m
for m in tous
if q_normalise in m.nom.lower()
or (m.code_barre and q_normalise in m.code_barre.lower())
]
else:
materiels = tous
categories_aplaties = aplatir(categories_racines(session))
return templates.TemplateResponse(
request,
"materiels.html",
{"materiels": materiels, "categories_aplaties": categories_aplaties, "q": q},
)
@router.post("/materiels")
def creer_materiel(
nom: str = Form(...),
categorie_id: int = Form(...),
code_barre: str = Form(""),
quantite: int = Form(0),
seuil_alerte: str = Form(""),
session: Session = Depends(get_session),
):
"""Crée un nouveau type de matériel dans le stock."""
materiel = Materiel(
nom=nom,
categorie_id=categorie_id,
code_barre=code_barre or None,
quantite=quantite,
seuil_alerte=int(seuil_alerte) if seuil_alerte else None,
)
session.add(materiel)
session.commit()
session.refresh(materiel)
verifier_et_alerter(materiel, session)
return RedirectResponse(url="/materiels", status_code=303)
@router.post("/materiels/{materiel_id}/modifier")
def modifier_materiel(
materiel_id: int,
nom: str = Form(...),
categorie_id: int = Form(...),
code_barre: str = Form(""),
quantite: int = Form(0),
seuil_alerte: str = Form(""),
session: Session = Depends(get_session),
):
"""Met à jour un matériel existant."""
materiel = session.get(Materiel, materiel_id)
if materiel:
materiel.nom = nom
materiel.categorie_id = categorie_id
materiel.code_barre = code_barre or None
materiel.quantite = quantite
materiel.seuil_alerte = int(seuil_alerte) if seuil_alerte else None
session.add(materiel)
session.commit()
session.refresh(materiel)
verifier_et_alerter(materiel, session)
return RedirectResponse(url="/materiels", status_code=303)
@router.post("/materiels/{materiel_id}/supprimer")
def supprimer_materiel(materiel_id: int, session: Session = Depends(get_session)):
"""Supprime définitivement un matériel du stock."""
materiel = session.get(Materiel, materiel_id)
if materiel:
session.delete(materiel)
session.commit()
return RedirectResponse(url="/materiels", status_code=303)