146 lines
4.7 KiB
Python
146 lines
4.7 KiB
Python
"""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.scalars().first():
|
|
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,
|
|
)
|