157 lines
5 KiB
Python
157 lines
5 KiB
Python
"""Routes M1 — Rédiger un PV de réunion d'affaires."""
|
|
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.pv_reunion import PvReunion
|
|
from app.models.reunion import Reunion
|
|
from app.models.membre import Membre
|
|
from app.models.decision import Decision
|
|
from app.models.affectation import Affectation
|
|
from app.models.poste import Poste
|
|
from app.schemas.phase4 import PvCreate, PvOut, PvUpdate
|
|
|
|
router = APIRouter(prefix="/pv", tags=["M1 — Procès-verbal"])
|
|
|
|
|
|
async def require_secretaire(membre=Depends(get_current_membre), db=Depends(get_db)):
|
|
result = await db.execute(
|
|
select(Affectation).join(Poste).where(
|
|
Affectation.membre_id == membre.id,
|
|
Affectation.statut == "actif",
|
|
(Poste.nom.ilike("%secrétaire%") | (Poste.categorie == "executif")),
|
|
)
|
|
)
|
|
if not result.scalar_one_or_none():
|
|
raise HTTPException(status_code=403, detail="Réservé au secrétaire ou à l'exécutif")
|
|
return membre
|
|
|
|
|
|
async def _to_out(pv: PvReunion, db: AsyncSession) -> PvOut:
|
|
redacteur = await db.get(Membre, pv.redacteur_id)
|
|
reunion = await db.get(Reunion, pv.reunion_id) if pv.reunion_id else None
|
|
return PvOut(
|
|
id=pv.id,
|
|
reunion_id=pv.reunion_id,
|
|
redacteur_prenom=redacteur.prenom if redacteur else "?",
|
|
contenu=pv.contenu,
|
|
decisions=pv.decisions,
|
|
approuve=pv.approuve,
|
|
cree_le=pv.cree_le,
|
|
date_reunion=reunion.date_reunion if reunion else None,
|
|
)
|
|
|
|
|
|
@router.get("/", response_model=list[PvOut])
|
|
async def liste_pv(
|
|
limite: int = 12,
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Lister les PV des réunions d'affaires."""
|
|
# Récupérer les PV via les réunions du groupe
|
|
result = await db.execute(
|
|
select(PvReunion)
|
|
.join(Reunion, PvReunion.reunion_id == Reunion.id)
|
|
.where(Reunion.groupe_id == membre.groupe_id)
|
|
.order_by(desc(PvReunion.cree_le))
|
|
.limit(limite)
|
|
)
|
|
return [await _to_out(pv, db) for pv in result.scalars().all()]
|
|
|
|
|
|
@router.get("/{pv_id}", response_model=PvOut)
|
|
async def detail_pv(
|
|
pv_id: str,
|
|
membre=Depends(get_current_membre),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(
|
|
select(PvReunion)
|
|
.join(Reunion, PvReunion.reunion_id == Reunion.id)
|
|
.where(PvReunion.id == pv_id, Reunion.groupe_id == membre.groupe_id)
|
|
)
|
|
pv = result.scalar_one_or_none()
|
|
if not pv:
|
|
raise HTTPException(status_code=404, detail="PV introuvable")
|
|
return await _to_out(pv, db)
|
|
|
|
|
|
@router.post("/", response_model=PvOut)
|
|
async def creer_pv(
|
|
req: PvCreate,
|
|
membre=Depends(require_secretaire),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""M1 — Rédiger un procès-verbal."""
|
|
# Vérifier la réunion
|
|
result = await db.execute(
|
|
select(Reunion).where(
|
|
Reunion.id == req.reunion_id,
|
|
Reunion.groupe_id == membre.groupe_id,
|
|
)
|
|
)
|
|
reunion = result.scalar_one_or_none()
|
|
if not reunion:
|
|
raise HTTPException(status_code=404, detail="Réunion introuvable")
|
|
|
|
decisions_data = None
|
|
if req.decisions:
|
|
decisions_data = [d.model_dump() for d in req.decisions]
|
|
|
|
pv = PvReunion(
|
|
reunion_id=req.reunion_id,
|
|
redacteur_id=membre.id,
|
|
contenu=req.contenu.strip(),
|
|
decisions=decisions_data,
|
|
)
|
|
db.add(pv)
|
|
await db.flush()
|
|
|
|
# Créer les décisions dans la table decisions (pour C5)
|
|
if req.decisions:
|
|
for d in req.decisions:
|
|
decision = Decision(
|
|
groupe_id=membre.groupe_id,
|
|
reunion_id=req.reunion_id,
|
|
sujet=d.sujet,
|
|
description=d.decision,
|
|
statut=d.statut,
|
|
proposeur=d.proposeur,
|
|
secondeur=d.secondeur,
|
|
date_decision=reunion.date_reunion.date() if reunion.date_reunion else None,
|
|
cree_par=membre.id,
|
|
)
|
|
db.add(decision)
|
|
await db.flush()
|
|
|
|
return await _to_out(pv, db)
|
|
|
|
|
|
@router.patch("/{pv_id}", response_model=PvOut)
|
|
async def modifier_pv(
|
|
pv_id: str,
|
|
req: PvUpdate,
|
|
membre=Depends(require_secretaire),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Modifier un PV existant."""
|
|
result = await db.execute(
|
|
select(PvReunion)
|
|
.join(Reunion, PvReunion.reunion_id == Reunion.id)
|
|
.where(PvReunion.id == pv_id, Reunion.groupe_id == membre.groupe_id)
|
|
)
|
|
pv = result.scalar_one_or_none()
|
|
if not pv:
|
|
raise HTTPException(status_code=404, detail="PV introuvable")
|
|
|
|
if req.contenu is not None:
|
|
pv.contenu = req.contenu.strip()
|
|
if req.decisions is not None:
|
|
pv.decisions = [d.model_dump() for d in req.decisions]
|
|
if req.approuve is not None:
|
|
pv.approuve = req.approuve
|
|
await db.flush()
|
|
return await _to_out(pv, db)
|