groupe-meditation/backend/app/routers/accueil.py

195 lines
9.4 KiB
Python

"""Route accueil — écran dynamique par rôle."""
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.core.database import get_db
from app.core.security import get_current_membre, is_sysadmin
from app.models.affectation import Affectation
from app.models.poste import Poste
from app.models.groupe import Groupe
from app.models.poste_module import PosteModule
from app.schemas.schemas import AccueilResponse, ModuleTuile, MembrePublic
router = APIRouter(prefix="/accueil", tags=["Accueil"])
# ── Définition des modules ──
MODULES_CONSULTATION = [
ModuleTuile(code="C1", nom="Rapports PDF", description="Finances, PV, résolutions", icone="📄", couleur="blue"),
ModuleTuile(code="C2", nom="Événements", description="Anniversaires et événements", icone="📅", couleur="green"),
ModuleTuile(code="C4", nom="Littérature", description="Inventaire et prix", icone="📚", couleur="purple"),
ModuleTuile(code="C5", nom="Gouvernance", description="Décisions du groupe", icone="📌", couleur="red"),
ModuleTuile(code="C7", nom="Mon profil", description="Modifier, PIN, notifications", icone="👤", couleur="gray"),
ModuleTuile(code="C9", nom="Postes à pourvoir", description="Postes disponibles, candidature", icone="🙋", couleur="yellow"),
ModuleTuile(code="C11", nom="Charte d'utilisation", description="Outil de service et limites", icone="🧭", couleur="indigo"),
ModuleTuile(code="C13", nom="Confidentialité", description="Données, accès et journal", icone="🔒", couleur="gray"),
ModuleTuile(code="C12", nom="Mode papier", description="Formulaires de reprise en main", icone="🖨️", couleur="gray"),
ModuleTuile(code="S1T", nom="Trésorerie", description="État des résultats, soldes, registre", icone="🏦", couleur="green"),
]
MODULES_PAR_CODE = {m.code: m for m in MODULES_CONSULTATION}
MODULES_PAR_CODE["S0"] = ModuleTuile(code="S0", nom="Rencontres", description="Saisies, ventes, jetons et rapports", icone="🗓️", couleur="green")
MODULES_PAR_CODE["M0"] = ModuleTuile(code="M0", nom="Assemblées", description="Présences, procès-verbal et rapports", icone="🏛️", couleur="indigo")
MODULES_PAR_CODE["S1"] = ModuleTuile(code="S1", nom="Collecte 7e", description="Saisir le panier", icone="💰", couleur="green")
MODULES_SAISIE_TOUS = [
ModuleTuile(code="S5", nom="Dépense", description="Soumettre une dépense", icone="💸", couleur="red"),
]
# Modules de saisie par poste
MODULES_SAISIE = {
"Trésorier(ière)": [
ModuleTuile(code="M4", nom="Donner au suivant", description="Destinataires et contributions", icone="📮", couleur="blue"),
],
"Secrétaire": [
ModuleTuile(code="M1", nom="Rédiger PV", description="Procès-verbal", icone="📝", couleur="blue"),
ModuleTuile(code="M2", nom="Présences", description="Réunion d'affaires", icone="✅", couleur="green"),
],
"RSG": [
ModuleTuile(code="M3", nom="Services", description="District, région, sujets et suivis", icone="📋", couleur="blue"),
],
"RSG Substitut(e)": [
ModuleTuile(code="M3", nom="Services", description="District, région, sujets et suivis", icone="📋", couleur="blue"),
],
"Animateur(trice)": [],
"Responsable littérature": [
ModuleTuile(code="S3", nom="Vente littérature", description="Enregistrer une vente", icone="📖", couleur="purple"),
ModuleTuile(code="M5", nom="Gestion des inventaires", description="Littérature et jetons", icone="📦", couleur="orange"),
],
"Responsable jetons": [
ModuleTuile(code="S2", nom="Remise jeton", description="Enregistrer un jeton", icone="🏅", couleur="yellow"),
ModuleTuile(code="M5", nom="Gestion des inventaires", description="Littérature et jetons", icone="📦", couleur="orange"),
],
}
MODULES_GESTION = [
ModuleTuile(code="G2", nom="Gestion des membres", description="Membres, invitations, désactivation", icone="👥", couleur="blue"),
ModuleTuile(code="G9", nom="Paramètres groupe", description="Nom, horaire, adresse", icone="🔧", couleur="gray"),
ModuleTuile(code="G11", nom="Gestion des mandats", description="Affecter, terminer, rotations", icone="🎯", couleur="purple"),
ModuleTuile(code="G12", nom="Gestion des postes", description="Postes, candidatures, accès", icone="📋", couleur="purple"),
ModuleTuile(code="G13", nom="Journal", description="Changements enregistrés", icone="🧾", couleur="gray"),
]
MODULE_SYSADMIN = ModuleTuile(code="G14", nom="Gestion des groupes", description="Groupes et démonstration", icone="🏷️", couleur="indigo")
for _modules in [MODULES_SAISIE_TOUS, MODULES_GESTION, *MODULES_SAISIE.values()]:
for _m in _modules:
MODULES_PAR_CODE[_m.code] = _m
@router.get("/", response_model=AccueilResponse)
async def accueil(
membre=Depends(get_current_membre),
db: AsyncSession = Depends(get_db),
):
"""Écran d'accueil dynamique — retourne les modules selon les postes du membre."""
if is_sysadmin(membre):
modules_saisie_sysadmin = []
codes_vus = set()
for module in [MODULES_PAR_CODE["S0"], MODULES_PAR_CODE["M0"], *MODULES_SAISIE_TOUS, *[m for mods in MODULES_SAISIE.values() for m in mods]]:
if module.code not in codes_vus:
modules_saisie_sysadmin.append(module)
codes_vus.add(module.code)
groupe = await db.get(Groupe, membre.groupe_id)
groupe_info = None
if groupe:
groupe_info = {
"id": str(groupe.id),
"nom": groupe.nom,
"jour_reunion": groupe.jour_reunion,
"heure_reunion": groupe.heure_reunion.strftime("%H:%M") if groupe.heure_reunion else None,
"assemblee_affaires_ordre": groupe.assemblee_affaires_ordre,
"adresse_local": groupe.adresse_local,
}
return AccueilResponse(
membre=MembrePublic.model_validate(membre),
postes=["Sysadmin"],
est_executif=True,
modules_consultation=MODULES_CONSULTATION,
modules_saisie=modules_saisie_sysadmin,
modules_gestion=[MODULE_SYSADMIN, *MODULES_GESTION],
groupe=groupe_info,
)
# Récupérer les affectations actives
result = await db.execute(
select(Affectation).join(Poste).where(
Affectation.membre_id == membre.id,
Affectation.groupe_id == membre.groupe_id,
Affectation.statut == "actif",
Poste.groupe_id == membre.groupe_id,
)
)
affectations = result.scalars().all()
postes_noms = []
postes_categories = []
poste_ids = []
for a in affectations:
poste = await db.get(Poste, a.poste_id)
if poste and poste.groupe_id == membre.groupe_id:
postes_noms.append(poste.nom)
postes_categories.append(poste.categorie)
poste_ids.append(poste.id)
# Modules de consultation : toujours visibles
modules_consultation = MODULES_CONSULTATION
# Modules de saisie : collecte pour tous + modules par poste
modules_saisie = list(MODULES_SAISIE_TOUS)
codes_vus = {"S5"}
result = await db.execute(select(PosteModule).where(PosteModule.poste_id.in_(poste_ids))) if poste_ids else None
modules_configures = result.scalars().all() if result else []
if modules_configures:
codes = sorted({pm.module_code for pm in modules_configures})
for code in codes:
if code == "S1" and "executif" not in postes_categories:
continue
m = MODULES_PAR_CODE.get(code)
if m and not code.startswith("G") and m.code not in codes_vus:
modules_saisie.append(m)
codes_vus.add(m.code)
else:
for nom_poste in postes_noms:
for m in MODULES_SAISIE.get(nom_poste, []):
if m.code not in codes_vus:
modules_saisie.append(m)
codes_vus.add(m.code)
if "executif" in postes_categories and "S1" not in codes_vus:
modules_saisie.insert(0, MODULES_PAR_CODE["S0"])
modules_saisie.insert(1, MODULES_PAR_CODE["M0"])
codes_vus.add("S0")
codes_vus.add("M0")
# Modules de gestion : seulement si exécutif
if modules_configures:
modules_gestion = [
MODULES_PAR_CODE[code]
for code in sorted({pm.module_code for pm in modules_configures})
if code.startswith("G") and code in MODULES_PAR_CODE
]
else:
modules_gestion = MODULES_GESTION if "executif" in postes_categories else []
# Info groupe pour le frontend
groupe = await db.get(Groupe, membre.groupe_id)
groupe_info = None
if groupe:
groupe_info = {
"id": str(groupe.id),
"nom": groupe.nom,
"jour_reunion": groupe.jour_reunion,
"heure_reunion": groupe.heure_reunion.strftime("%H:%M") if groupe.heure_reunion else None,
"assemblee_affaires_ordre": groupe.assemblee_affaires_ordre,
"adresse_local": groupe.adresse_local,
}
return AccueilResponse(
membre=MembrePublic.model_validate(membre),
postes=postes_noms,
est_executif="executif" in postes_categories,
modules_consultation=modules_consultation,
modules_saisie=modules_saisie,
modules_gestion=modules_gestion,
groupe=groupe_info,
)