"""Routes S5 — Dépenses (6 champs).""" 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 from app.models.depense import Depense from app.models.membre import Membre from app.models.affectation import Affectation from app.models.poste import Poste from app.schemas.phase1 import DepenseCreate, DepenseOut, DepenseUpdate router = APIRouter(prefix="/depenses", tags=["S5 — Dépenses"]) METHODES_VALIDES = {"DU", "VIREMENT", "CHEQUE", "COLLECTE"} async def require_tresorier(membre=Depends(get_current_membre), db: AsyncSession = Depends(get_db)): """Vérifie que le membre est trésorier.""" result = await db.execute( select(Affectation).join(Poste).where( Affectation.membre_id == membre.id, Affectation.statut == "actif", Poste.nom.ilike("%trésorier%"), ) ) if not result.scalar_one_or_none(): raise HTTPException(status_code=403, detail="Réservé au trésorier") return membre @router.post("/", response_model=DepenseOut) async def saisir_depense( req: DepenseCreate, membre=Depends(require_tresorier), db: AsyncSession = Depends(get_db), ): """S5 — Saisir une dépense avec les 6 champs.""" # Valider la méthode if req.methode.upper() not in METHODES_VALIDES: raise HTTPException(status_code=400, detail=f"Méthode invalide. Choix : {', '.join(METHODES_VALIDES)}") # Valider que le membre 'qui' existe qui_membre = await db.get(Membre, req.qui) if not qui_membre or qui_membre.groupe_id != membre.groupe_id: raise HTTPException(status_code=400, detail="Membre introuvable") depense = Depense( groupe_id=membre.groupe_id, date_depense=req.date_depense, montant=req.montant, qui=req.qui, quoi=req.quoi.strip(), paye=req.paye, methode=req.methode.upper(), saisi_par=membre.id, ) db.add(depense) await db.flush() return DepenseOut( id=depense.id, date_depense=depense.date_depense, montant=float(depense.montant), qui_prenom=qui_membre.prenom, quoi=depense.quoi, paye=depense.paye, methode=depense.methode, saisi_par_prenom=membre.prenom, cree_le=depense.cree_le, ) @router.get("/", response_model=list[DepenseOut]) async def liste_depenses( limite: int = 30, paye: bool | None = None, membre=Depends(get_current_membre), db: AsyncSession = Depends(get_db), ): """Lister les dépenses du groupe avec filtre optionnel sur payé.""" query = select(Depense).where(Depense.groupe_id == membre.groupe_id) if paye is not None: query = query.where(Depense.paye == paye) query = query.order_by(desc(Depense.date_depense)).limit(limite) result = await db.execute(query) depenses = result.scalars().all() out = [] for d in depenses: qui = await db.get(Membre, d.qui) saisi = await db.get(Membre, d.saisi_par) if d.saisi_par else None out.append(DepenseOut( id=d.id, date_depense=d.date_depense, montant=float(d.montant), qui_prenom=qui.prenom if qui else "?", quoi=d.quoi, paye=d.paye, methode=d.methode, saisi_par_prenom=saisi.prenom if saisi else None, cree_le=d.cree_le, )) return out @router.patch("/{depense_id}", response_model=DepenseOut) async def modifier_depense( depense_id: str, req: DepenseUpdate, membre=Depends(require_tresorier), db: AsyncSession = Depends(get_db), ): """Modifier une dépense (ex: marquer comme payé).""" result = await db.execute( select(Depense).where(Depense.id == depense_id, Depense.groupe_id == membre.groupe_id) ) depense = result.scalar_one_or_none() if not depense: raise HTTPException(status_code=404, detail="Dépense introuvable") if req.paye is not None: depense.paye = req.paye if req.methode is not None: if req.methode.upper() not in METHODES_VALIDES: raise HTTPException(status_code=400, detail="Méthode invalide") depense.methode = req.methode.upper() if req.quoi is not None: depense.quoi = req.quoi.strip() await db.flush() qui = await db.get(Membre, depense.qui) return DepenseOut( id=depense.id, date_depense=depense.date_depense, montant=float(depense.montant), qui_prenom=qui.prenom if qui else "?", quoi=depense.quoi, paye=depense.paye, methode=depense.methode, saisi_par_prenom=membre.prenom, cree_le=depense.cree_le, )