100 lines
3.4 KiB
Python
100 lines
3.4 KiB
Python
|
|
"""Routes G7 — Jumelage parrain/filleul (confidentiel)."""
|
||
|
|
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 require_executif
|
||
|
|
from app.models.jumelage import Jumelage
|
||
|
|
from app.models.membre import Membre
|
||
|
|
from app.schemas.phase8 import JumelageCreate, JumelageOut, JumelageUpdate
|
||
|
|
|
||
|
|
router = APIRouter(prefix="/jumelages", tags=["G7 — Parrainage"])
|
||
|
|
|
||
|
|
|
||
|
|
async def _to_out(j: Jumelage, db: AsyncSession) -> JumelageOut:
|
||
|
|
parrain = await db.get(Membre, j.parrain_id)
|
||
|
|
filleul = await db.get(Membre, j.filleul_id)
|
||
|
|
cree = await db.get(Membre, j.cree_par) if j.cree_par else None
|
||
|
|
return JumelageOut(
|
||
|
|
id=j.id,
|
||
|
|
parrain_prenom=parrain.prenom if parrain else "?",
|
||
|
|
filleul_prenom=filleul.prenom if filleul else "?",
|
||
|
|
date_jumelage=j.date_jumelage,
|
||
|
|
statut=j.statut,
|
||
|
|
note=j.note,
|
||
|
|
cree_par_prenom=cree.prenom if cree else None,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/", response_model=JumelageOut)
|
||
|
|
async def creer_jumelage(
|
||
|
|
req: JumelageCreate,
|
||
|
|
membre=Depends(require_executif),
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
):
|
||
|
|
"""G7 — Jumeler un parrain et un filleul."""
|
||
|
|
if req.parrain_id == req.filleul_id:
|
||
|
|
raise HTTPException(status_code=400, detail="Le parrain et le filleul doivent être différents")
|
||
|
|
|
||
|
|
parrain = await db.get(Membre, req.parrain_id)
|
||
|
|
filleul = await db.get(Membre, req.filleul_id)
|
||
|
|
if not parrain or not parrain.actif:
|
||
|
|
raise HTTPException(status_code=404, detail="Parrain introuvable ou inactif")
|
||
|
|
if not filleul or not filleul.actif:
|
||
|
|
raise HTTPException(status_code=404, detail="Filleul introuvable ou inactif")
|
||
|
|
|
||
|
|
jumelage = Jumelage(
|
||
|
|
groupe_id=membre.groupe_id,
|
||
|
|
parrain_id=req.parrain_id,
|
||
|
|
filleul_id=req.filleul_id,
|
||
|
|
date_jumelage=req.date_jumelage,
|
||
|
|
note=req.note,
|
||
|
|
cree_par=membre.id,
|
||
|
|
)
|
||
|
|
db.add(jumelage)
|
||
|
|
await db.flush()
|
||
|
|
|
||
|
|
return await _to_out(jumelage, db)
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/", response_model=list[JumelageOut])
|
||
|
|
async def liste_jumelages(
|
||
|
|
statut: str | None = None,
|
||
|
|
membre=Depends(require_executif),
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
):
|
||
|
|
"""Liste des jumelages (confidentiel — exécutif seulement)."""
|
||
|
|
query = select(Jumelage).where(Jumelage.groupe_id == membre.groupe_id)
|
||
|
|
if statut:
|
||
|
|
query = query.where(Jumelage.statut == statut)
|
||
|
|
query = query.order_by(desc(Jumelage.date_jumelage))
|
||
|
|
|
||
|
|
result = await db.execute(query)
|
||
|
|
jumelages = result.scalars().all()
|
||
|
|
return [await _to_out(j, db) for j in jumelages]
|
||
|
|
|
||
|
|
|
||
|
|
@router.patch("/{jumelage_id}", response_model=JumelageOut)
|
||
|
|
async def modifier_jumelage(
|
||
|
|
jumelage_id: str,
|
||
|
|
req: JumelageUpdate,
|
||
|
|
membre=Depends(require_executif),
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
):
|
||
|
|
"""Modifier ou terminer un jumelage."""
|
||
|
|
result = await db.execute(
|
||
|
|
select(Jumelage).where(Jumelage.id == jumelage_id, Jumelage.groupe_id == membre.groupe_id)
|
||
|
|
)
|
||
|
|
jumelage = result.scalar_one_or_none()
|
||
|
|
if not jumelage:
|
||
|
|
raise HTTPException(status_code=404, detail="Jumelage introuvable")
|
||
|
|
|
||
|
|
if req.statut and req.statut in ("actif", "termine"):
|
||
|
|
jumelage.statut = req.statut
|
||
|
|
if req.note is not None:
|
||
|
|
jumelage.note = req.note
|
||
|
|
await db.flush()
|
||
|
|
|
||
|
|
return await _to_out(jumelage, db)
|