# Admin organisation : gestion des membres et import massif Excel avec quota ## Contexte - Un **administrateur d’organisation** (ADMIN_ORGANISATION) doit pouvoir **gérer les membres de son organisation** (liste, création unitaire, modification). - Il doit pouvoir **créer des membres en masse** via un **fichier Excel strictement formaté**. - Le nombre de créations doit être **plafonné** par le **quota de la souscription** (tranche/forme d’abonnement) de l’organisation. ## Règles métier 1. **Droits** - ADMIN_ORGANISATION : accès limité aux membres des organisations qu’il gère (liste, détail, création, mise à jour, import). - ADMIN / SUPER_ADMIN : accès à tous les membres (comportement actuel). 2. **Import massif** - Format : **Excel (.xlsx)** (et optionnellement CSV) avec colonnes obligatoires strictes (ex. nom, prénom, email, téléphone). - **organisationId** obligatoire pour un org admin ; les membres créés sont rattachés à cette organisation (création de `MembreOrganisation`). - **Quota** : avant d’accepter l’import, vérifier que `quota_utilise + nombre de nouveaux membres à créer ≤ quota_max` (ou pas de limite si `quota_max` est null, ex. formule Crystal). - À chaque membre **nouvellement créé** (pas les mises à jour) : créer le lien `MembreOrganisation` et incrémenter `quota_utilise` de la souscription. - Si le quota est dépassé en cours d’import : rejeter la requête (ou arrêter et retourner les erreurs selon le choix métier). 3. **Souscription** - Une organisation (racine) a au plus une souscription active (`souscriptions_organisation`). - `quota_max` = snapshot de la formule (ex. 50 pour Starter, null pour Crystal). - `quota_utilise` = nombre de membres comptabilisés pour cette souscription (incrémenté à chaque adhésion validée / membre créé dans l’org). ## Existant (WOU/DRY) - **Backend** - `MembreResource` : GET list, GET /recherche, POST create, POST /import, GET /import/modele — existants ; à sécuriser et à scoper pour ADMIN_ORGANISATION. - `MembreImportExportService.importerMembres` : import Excel/CSV existant ; prend déjà `organisationId` ; **manque** : création de `MembreOrganisation`, vérification et incrément du quota. - Entités : `SouscriptionOrganisation` (quota_max, quota_utilise, incrementerQuota), `FormuleAbonnement` (max_membres), `MembreOrganisation` (lien membre–organisation). - **Mobile** - Annuaire membres : critères de recherche avec `organisationIds` ; pour org admin, passer les IDs de “mes organisations” (déjà possible côté app si l’API les filtre). ## Implémentation préconisée ### Backend 1. **Sécurité et périmètre** - Sur `MembreResource` : ajouter `@RolesAllowed` adaptés (ex. MEMBRE, ADMIN, ADMIN_ORGANISATION pour liste/création/import). - Pour un utilisateur avec rôle ADMIN_ORGANISATION (et sans ADMIN/SUPER_ADMIN) : - Lister les organisations du membre connecté (ex. `OrganisationService.listerOrganisationsPourUtilisateur(email)`). - **Liste / recherche** : filtrer les membres par ces `organisationIds` (via `MembreOrganisation`). - **Création** : exiger un `organisationId` dans le corps (ou le déduire) et vérifier qu’il appartient à ses organisations ; créer le `MembreOrganisation` après création du membre. - **Import** : exiger `organisationId` et vérifier qu’il appartient à ses organisations ; appliquer la règle de quota et créer les `MembreOrganisation` + incrément de quota. 2. **Quota et import** - **Repository** : `SouscriptionOrganisationRepository` avec `findByOrganisationId(UUID)` (souscription active si besoin). - **Import** (dans `MembreImportExportService` ou service appelant) : - Si `organisationId != null` : charger la souscription active de l’organisation. - Pour chaque ligne du fichier : si c’est un **nouveau** membre (création, pas mise à jour) : - Vérifier `souscription.getPlacesRestantes() > 0` (ou pas de limite si `quota_max == null`). - Si dépassement : erreur explicite (ex. “Quota souscription atteint (max N membres)”) et arrêt ou rapport d’erreur. - Après `creerMembre` : créer `MembreOrganisation` (membre, organisation, statut, dateAdhesion), persister, puis `souscription.incrementerQuota()` et persister la souscription. 3. **Modèle Excel** - Conserver le modèle actuel (GET `/api/membres/import/modele`) ; documenter les colonnes obligatoires et le fait que le fichier doit être strict (pas de colonnes en plus / types cohérents si besoin). - Optionnel : endpoint GET pour “quota actuel / places restantes” par organisation (pour affichage côté client). ### Mobile (optionnel dans un second temps) - Pour un org admin : envoyer en requête liste/recherche les `organisationIds` (ses organisations) pour n’afficher que les membres de son périmètre. - Écran “Import membres” : choix de l’organisation (pré-rempli si une seule), upload du fichier Excel, affichage du quota restant (si l’API le fournit) et du résultat d’import (succès / erreurs). ## Critères d’acceptation - [ ] Un admin d’organisation ne voit que les membres de ses organisations (liste, recherche). - [ ] Un admin d’organisation peut créer un membre dans une de ses organisations (et le lien MembreOrganisation est créé). - [ ] Un admin d’organisation peut lancer un import Excel avec `organisationId` ; le fichier est validé (format strict), le quota souscription est vérifié avant/pendant l’import. - [ ] Les nouveaux membres créés lors de l’import sont rattachés à l’organisation et le quota souscription est incrémenté. - [ ] Si le quota est dépassé (fichier trop gros ou quota déjà saturé), l’import est refusé ou s’arrête avec un message clair (quota max N, X demandés, etc.).