111 lines
3.7 KiB
Python
111 lines
3.7 KiB
Python
"""Routes S2 — Remise de jeton."""
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, desc
|
|
|
|
from app.core.database import get_db
|
|
from app.core.security import get_current_membre, is_sysadmin
|
|
from app.models.jeton import Jeton
|
|
from app.models.membre import Membre
|
|
from app.models.affectation import Affectation
|
|
from app.models.poste import Poste
|
|
from app.schemas.phase5 import JetonCreate, JetonOut, TYPES_JETONS
|
|
|
|
router = APIRouter(prefix="/jetons", tags=["S2 — Remise de jeton"])
|
|
|
|
|
|
async def require_resp_jetons(membre=Depends(get_current_membre), db: AsyncSession = Depends(get_db)):
|
|
"""Vérifie que le membre est responsable des jetons."""
|
|
if is_sysadmin(membre):
|
|
return membre
|
|
result = await db.execute(
|
|
select(Affectation).join(Poste).where(
|
|
Affectation.membre_id == membre.id,
|
|
Affectation.statut == "actif",
|
|
(Poste.nom.ilike("%jeton%") | (Poste.categorie == "executif")),
|
|
)
|
|
)
|
|
if not result.scalars().first():
|
|
raise HTTPException(status_code=403, detail="Réservé au responsable des jetons")
|
|
return membre
|
|
|
|
|
|
@router.get("/types")
|
|
async def types_jetons():
|
|
"""Liste des types de jetons disponibles."""
|
|
return TYPES_JETONS
|
|
|
|
|
|
@router.post("/", response_model=JetonOut)
|
|
async def remettre_jeton(
|
|
req: JetonCreate,
|
|
membre=Depends(require_resp_jetons),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""S2 — Enregistrer la remise d'un jeton."""
|
|
# Validation
|
|
types_valides = [t["value"] for t in TYPES_JETONS]
|
|
if req.type_jeton not in types_valides:
|
|
raise HTTPException(status_code=400, detail=f"Type de jeton invalide. Valeurs: {types_valides}")
|
|
|
|
if req.type_jeton == "multiple" and (not req.annees or req.annees < 2):
|
|
raise HTTPException(status_code=400, detail="Le nombre d'années est requis (≥ 2) pour un jeton multiple")
|
|
|
|
# Vérifier que le membre existe si spécifié
|
|
membre_prenom = None
|
|
if req.membre_id:
|
|
cible = await db.get(Membre, req.membre_id)
|
|
if not cible or not cible.actif:
|
|
raise HTTPException(status_code=404, detail="Membre introuvable")
|
|
membre_prenom = cible.prenom
|
|
|
|
jeton = Jeton(
|
|
groupe_id=membre.groupe_id,
|
|
membre_id=req.membre_id,
|
|
type_jeton=req.type_jeton,
|
|
date_remise=req.date_remise,
|
|
annees=req.annees if req.type_jeton == "multiple" else None,
|
|
remis_par=membre.id,
|
|
)
|
|
db.add(jeton)
|
|
await db.flush()
|
|
|
|
return JetonOut(
|
|
id=jeton.id,
|
|
membre_prenom=membre_prenom,
|
|
type_jeton=jeton.type_jeton,
|
|
date_remise=jeton.date_remise,
|
|
annees=jeton.annees,
|
|
remis_par_prenom=membre.prenom,
|
|
cree_le=jeton.cree_le,
|
|
)
|
|
|
|
|
|
@router.get("/", response_model=list[JetonOut])
|
|
async def liste_jetons(
|
|
limite: int = 30,
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Lister les jetons remis récemment (tout le groupe)."""
|
|
result = await db.execute(
|
|
select(Jeton)
|
|
.where(Jeton.groupe_id == membre.groupe_id)
|
|
.order_by(desc(Jeton.date_remise))
|
|
.limit(limite)
|
|
)
|
|
jetons = result.scalars().all()
|
|
out = []
|
|
for j in jetons:
|
|
m = await db.get(Membre, j.membre_id) if j.membre_id else None
|
|
r = await db.get(Membre, j.remis_par) if j.remis_par else None
|
|
out.append(JetonOut(
|
|
id=j.id,
|
|
membre_prenom=m.prenom if m else None,
|
|
type_jeton=j.type_jeton,
|
|
date_remise=j.date_remise,
|
|
annees=j.annees,
|
|
remis_par_prenom=r.prenom if r else None,
|
|
cree_le=j.cree_le,
|
|
))
|
|
return out
|