diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d69f6..5ec864b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,7 +84,7 @@ et ce projet adhère au [Semantic Versioning](https://semver.org/lang/fr/). - ✅ **FavorisBean** - Favoris utilisateur - ✅ **WaveBean** - Intégration Wave Money - ✅ **LoginBean** - Authentification -- ✅ **EntitesGestionBean** - Gestion des entités +- ✅ **OrganisationsBean** - Gestion des organisations - ✅ Et 9 autres beans... ##### Changements par Bean diff --git a/README.md b/README.md index d7172a8..3806b5a 100644 --- a/README.md +++ b/README.md @@ -253,7 +253,7 @@ export LOCKOUT_DURATION="300" - Web Origins: `https://votre-domaine.com` 3. Configurer les rôles: - `SUPER_ADMIN`: Administrateur système - - `ADMIN_ENTITE`: Administrateur d'organisation + - `ADMIN_ORGANISATION`: Administrateur d'organisation - `MEMBRE`: Membre standard 4. Configurer les mappers pour inclure les rôles dans les tokens JWT @@ -302,7 +302,7 @@ docker run -p 8080:8080 \ - **Méthode**: OpenID Connect (OIDC) via Keycloak - **Tokens**: JWT (JSON Web Tokens) -- **Rôles supportés**: SUPER_ADMIN, ADMIN_ENTITE, MEMBRE +- **Rôles supportés**: SUPER_ADMIN, ADMIN_ORGANISATION, MEMBRE - **Permissions granulaires**: Basées sur les rôles et fonctionnalités ### Headers de Sécurité (Production) diff --git a/SECURITY.md b/SECURITY.md index 673bd4a..145d778 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -98,7 +98,7 @@ quarkus.oidc.tls.verification=required # JAMAIS 'none' en production #### Hiérarchie des Rôles 1. **SUPER_ADMIN** - Accès complet système -2. **ADMIN_ENTITE** - Administration organisation +2. **ADMIN_ORGANISATION** - Administration organisation 3. **ADMIN** - Administration locale 4. **GESTIONNAIRE_*** - Gestion fonctionnelle 5. **TRESORIER** - Gestion financière diff --git a/setup-keycloak.bat b/setup-keycloak.bat index c23b4f2..41f2858 100644 --- a/setup-keycloak.bat +++ b/setup-keycloak.bat @@ -82,8 +82,8 @@ echo ✅ Rôle SUPER_ADMIN créé curl -s -X POST "%KEYCLOAK_URL%/admin/realms/%REALM_NAME%/roles" ^ -H "Authorization: Bearer %ADMIN_TOKEN%" ^ -H "Content-Type: application/json" ^ - -d "{\"name\":\"ADMIN_ENTITE\",\"description\":\"Administrateur d'entité\"}" > nul 2>&1 -echo ✅ Rôle ADMIN_ENTITE créé + -d "{\"name\":\"ADMIN_ORGANISATION\",\"description\":\"Administrateur d'entité\"}" > nul 2>&1 +echo ✅ Rôle ADMIN_ORGANISATION créé curl -s -X POST "%KEYCLOAK_URL%/admin/realms/%REALM_NAME%/roles" ^ -H "Authorization: Bearer %ADMIN_TOKEN%" ^ @@ -205,9 +205,9 @@ if not "%USER_ID%"=="" ( curl -s -X GET "%KEYCLOAK_URL%/admin/realms/%REALM_NAME%/roles" ^ -H "Authorization: Bearer %ADMIN_TOKEN%" > roles.json - REM Assigner les rôles MEMBRE et ADMIN_ENTITE + REM Assigner les rôles MEMBRE et ADMIN_ORGANISATION for /f "delims=" %%i in ('powershell -Command "(Get-Content roles.json | ConvertFrom-Json) | Where-Object {$_.name -eq 'MEMBRE'} | Select-Object -ExpandProperty id"') do set ROLE_MEMBRE_ID=%%i - for /f "delims=" %%i in ('powershell -Command "(Get-Content roles.json | ConvertFrom-Json) | Where-Object {$_.name -eq 'ADMIN_ENTITE'} | Select-Object -ExpandProperty id"') do set ROLE_ADMIN_ID=%%i + for /f "delims=" %%i in ('powershell -Command "(Get-Content roles.json | ConvertFrom-Json) | Where-Object {$_.name -eq 'ADMIN_ORGANISATION'} | Select-Object -ExpandProperty id"') do set ROLE_ADMIN_ID=%%i if not "%ROLE_MEMBRE_ID%"=="" ( curl -s -X POST "%KEYCLOAK_URL%/admin/realms/%REALM_NAME%/users/%USER_ID%/role-mappings/realm" ^ @@ -221,8 +221,8 @@ if not "%USER_ID%"=="" ( curl -s -X POST "%KEYCLOAK_URL%/admin/realms/%REALM_NAME%/users/%USER_ID%/role-mappings/realm" ^ -H "Authorization: Bearer %ADMIN_TOKEN%" ^ -H "Content-Type: application/json" ^ - -d "[{\"id\":\"%ROLE_ADMIN_ID%\",\"name\":\"ADMIN_ENTITE\"}]" > nul 2>&1 - echo ✅ Rôle ADMIN_ENTITE assigné + -d "[{\"id\":\"%ROLE_ADMIN_ID%\",\"name\":\"ADMIN_ORGANISATION\"}]" > nul 2>&1 + echo ✅ Rôle ADMIN_ORGANISATION assigné ) ) else ( echo ⚠️ Impossible de configurer l'utilisateur @@ -262,7 +262,7 @@ echo - Client ID: %CLIENT_ID% echo - Client Secret: %CLIENT_SECRET% echo - Utilisateur test: test@unionflow.dev echo - Mot de passe: test123 -echo - Rôles assignés: MEMBRE, ADMIN_ENTITE +echo - Rôles assignés: MEMBRE, ADMIN_ORGANISATION echo. echo 📄 Le client secret a été sauvegardé dans le fichier .env echo. diff --git a/setup-keycloak.sh b/setup-keycloak.sh index 2ad6897..604ff78 100644 --- a/setup-keycloak.sh +++ b/setup-keycloak.sh @@ -78,8 +78,8 @@ echo " ✅ Rôle SUPER_ADMIN créé" curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM_NAME/roles" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ - -d '{"name":"ADMIN_ENTITE","description":"Administrateur d'\''entité"}' > /dev/null 2>&1 -echo " ✅ Rôle ADMIN_ENTITE créé" + -d '{"name":"ADMIN_ORGANISATION","description":"Administrateur d'\''entité"}' > /dev/null 2>&1 +echo " ✅ Rôle ADMIN_ORGANISATION créé" curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM_NAME/roles" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ @@ -240,11 +240,11 @@ if [ -n "$USER_ID" ]; then -H "Authorization: Bearer $ADMIN_TOKEN") ROLE_MEMBRE_ID=$(echo "$ROLES" | grep -B2 '"name":"MEMBRE"' | grep '"id"' | cut -d'"' -f4) - ROLE_ADMIN_ID=$(echo "$ROLES" | grep -B2 '"name":"ADMIN_ENTITE"' | grep '"id"' | cut -d'"' -f4) + ROLE_ADMIN_ID=$(echo "$ROLES" | grep -B2 '"name":"ADMIN_ORGANISATION"' | grep '"id"' | cut -d'"' -f4) if command -v jq &> /dev/null; then ROLE_MEMBRE_ID=$(echo "$ROLES" | jq -r '.[] | select(.name=="MEMBRE") | .id') - ROLE_ADMIN_ID=$(echo "$ROLES" | jq -r '.[] | select(.name=="ADMIN_ENTITE") | .id') + ROLE_ADMIN_ID=$(echo "$ROLES" | jq -r '.[] | select(.name=="ADMIN_ORGANISATION") | .id') fi if [ -n "$ROLE_MEMBRE_ID" ]; then @@ -259,8 +259,8 @@ if [ -n "$USER_ID" ]; then curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM_NAME/users/$USER_ID/role-mappings/realm" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ - -d "[{\"id\":\"$ROLE_ADMIN_ID\",\"name\":\"ADMIN_ENTITE\"}]" > /dev/null 2>&1 - echo " ✅ Rôle ADMIN_ENTITE assigné" + -d "[{\"id\":\"$ROLE_ADMIN_ID\",\"name\":\"ADMIN_ORGANISATION\"}]" > /dev/null 2>&1 + echo " ✅ Rôle ADMIN_ORGANISATION assigné" fi else echo "⚠️ Impossible de configurer l'utilisateur" @@ -297,7 +297,7 @@ echo " - Client ID: $CLIENT_ID" echo " - Client Secret: $CLIENT_SECRET" echo " - Utilisateur test: test@unionflow.dev" echo " - Mot de passe: test123" -echo " - Rôles assignés: MEMBRE, ADMIN_ENTITE" +echo " - Rôles assignés: MEMBRE, ADMIN_ORGANISATION" echo "" echo "📄 Le client secret a été sauvegardé dans le fichier .env" echo "" diff --git a/src/main/java/dev/lions/unionflow/client/UnionFlowClientApplication.java b/src/main/java/dev/lions/unionflow/client/UnionFlowClientApplication.java index b594346..fdffe88 100644 --- a/src/main/java/dev/lions/unionflow/client/UnionFlowClientApplication.java +++ b/src/main/java/dev/lions/unionflow/client/UnionFlowClientApplication.java @@ -85,7 +85,7 @@ import org.jboss.logging.Logger; *
  • OIDC avec Keycloak (realm: unionflow)
  • *
  • JWT dans HTTP-only cookies (protection XSS)
  • *
  • CSRF protection avec PrimeFaces ViewState
  • - *
  • RBAC avec rôles: SUPER_ADMIN, ADMIN_ENTITE, MEMBRE
  • + *
  • RBAC avec rôles: SUPER_ADMIN, ADMIN_ORGANISATION, MEMBRE
  • *
  • ViewExpiredException handling pour timeout session
  • *
  • HTTPS obligatoire en production
  • *
  • Content Security Policy headers
  • diff --git a/src/main/java/dev/lions/unionflow/client/bean/MenuBean.java b/src/main/java/dev/lions/unionflow/client/bean/MenuBean.java index fb54b23..cdf294e 100644 --- a/src/main/java/dev/lions/unionflow/client/bean/MenuBean.java +++ b/src/main/java/dev/lions/unionflow/client/bean/MenuBean.java @@ -152,15 +152,6 @@ public class MenuBean implements Serializable { // MEMBRE_ACTIF retiré intentionnellement pour raisons UX et RGPD } - /** - * DEPRECATED: Utilisez isGestionMembresMenuVisible() ou isAnnuaireMembresVisible() - * @deprecated Remplacé par isGestionMembresMenuVisible() et isAnnuaireMembresVisible() - */ - @Deprecated - public boolean isMembresMenuVisible() { - return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "SECRETAIRE", "MEMBRE_BUREAU", "MEMBRE_ACTIF"); - } - /** * Gestion Financière - Administration finances (trésorerie, budgets, comptabilité) * Visible pour TRESORIER et ADMIN uniquement @@ -199,33 +190,6 @@ public class MenuBean implements Serializable { return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "SECRETAIRE", "MEMBRE_BUREAU"); } - /** - * DEPRECATED: Utilisez isGestionFinancesMenuVisible() ou isMesFinancesMenuVisible() - * @deprecated Remplacé par isGestionFinancesMenuVisible() (admin) et isMesFinancesMenuVisible() (membre) - */ - @Deprecated - public boolean isFinancesMenuVisible() { - return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "TRESORIER", "RESPONSABLE_CREDIT", "MEMBRE_BUREAU"); - } - - /** - * DEPRECATED: Utilisez isGestionAidesSocialesMenuVisible() ou isMesAidesSocialesMenuVisible() - * @deprecated Remplacé par isGestionAidesSocialesMenuVisible() (admin) et isMesAidesSocialesMenuVisible() (membre) - */ - @Deprecated - public boolean isAidesMenuVisible() { - return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "RESPONSABLE_SOCIAL", "SECRETAIRE", "MEMBRE_BUREAU"); - } - - /** - * DEPRECATED: Utilisez isGestionEvenementsMenuVisible() ou isMesEvenementsMenuVisible() - * @deprecated Remplacé par isGestionEvenementsMenuVisible() (admin) et isMesEvenementsMenuVisible() (membre) - */ - @Deprecated - public boolean isEvenementsMenuVisible() { - return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "RESPONSABLE_EVENEMENTS", "SECRETAIRE", "MEMBRE_BUREAU", "MEMBRE_ACTIF"); - } - /** * Communication - Visible pour admins, secrétaires, bureau */ diff --git a/src/main/java/dev/lions/unionflow/client/view/EntitesGestionBean.java b/src/main/java/dev/lions/unionflow/client/view/EntitesGestionBean.java deleted file mode 100644 index f67d3f0..0000000 --- a/src/main/java/dev/lions/unionflow/client/view/EntitesGestionBean.java +++ /dev/null @@ -1,1217 +0,0 @@ -package dev.lions.unionflow.client.view; - -import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse; -import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationSummaryResponse; -import dev.lions.unionflow.server.api.dto.common.PagedResponse; -import dev.lions.unionflow.server.api.dto.souscription.SouscriptionStatutResponse; -import dev.lions.unionflow.server.api.dto.common.PagedResponse; -import dev.lions.unionflow.client.service.OrganisationService; -import dev.lions.unionflow.client.service.CotisationService; -import dev.lions.unionflow.client.service.ErrorHandlerService; -import dev.lions.unionflow.client.service.SouscriptionService; -import dev.lions.unionflow.client.service.TypeCatalogueService; -import jakarta.faces.model.SelectItem; -import java.util.Map; -import jakarta.enterprise.context.SessionScoped; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.annotation.PostConstruct; -import org.eclipse.microprofile.rest.client.inject.RestClient; -import java.io.Serializable; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; -import org.jboss.logging.Logger; - -@Named("entitesGestionBean") -@SessionScoped -public class EntitesGestionBean implements Serializable { - - private static final long serialVersionUID = 1L; - private static final Logger LOG = Logger.getLogger(EntitesGestionBean.class); - - // Constantes de navigation outcomes (WOU/DRY - réutilisables) - private static final String OUTCOME_ENTITE_DETAILS = "entiteDetailsPage"; - private static final String OUTCOME_ADMIN_MEMBRES_GESTION = "adminMembresGestionPage"; - private static final String OUTCOME_ENTITE_CONFIGURATION = "entiteConfigurationPage"; - private static final String OUTCOME_ENTITE_RAPPORTS = "entiteRapportsPage"; - - @Inject - @RestClient - private OrganisationService organisationService; - - @Inject - @RestClient - private CotisationService cotisationService; - - @Inject - @RestClient - private SouscriptionService souscriptionService; - - @Inject - TypeCatalogueService typeCatalogueService; - - @Inject - ErrorHandlerService errorHandler; - - private List toutesLesEntites; - private List entitesFiltrees; - private List entitesSelectionnees; - private Entite entiteSelectionne; - private OrganisationResponse entiteEnEdition; - private Entite nouvelleEntite; - private Filtres filtres; - private Statistiques statistiques; - - @PostConstruct - public void init() { - initializeFiltres(); - initializeEntites(); - initializeStatistiques(); - initializeNouvelleEntite(); - appliquerFiltres(); - } - - public List getTypesSelectItems() { - return typeCatalogueService.getSelectItems("Tous les types"); - } - - public List getTypesSelectItemsForForm() { - return typeCatalogueService.getSelectItems("Sélectionner un type *"); - } - - public List getRegionsDisponibles() { - List items = new ArrayList<>(); - items.add(new SelectItem("", "Toutes les régions")); - if (toutesLesEntites != null) { - toutesLesEntites.stream() - .map(Entite::getRegion) - .filter(r -> r != null && !r.trim().isEmpty()) - .distinct() - .sorted() - .forEach(r -> items.add(new SelectItem(r, r))); - } - return items; - } - - private void initializeFiltres() { - filtres = new Filtres(); - entitesSelectionnees = new ArrayList<>(); - } - - private void initializeStatistiques() { - statistiques = new Statistiques(); - try { - PagedResponse response = organisationService.listerToutes(0, 1000); - List associations = new ArrayList<>(); - if (response != null && response.getData() != null) { - associations = response.getData(); - } - statistiques.setTotalEntites(associations.size()); - long actives = associations.stream().filter(a -> "ACTIVE".equals(a.getStatut())).count(); - statistiques.setEntitesActives((int) actives); - int totalMembres = associations.stream() - .mapToInt(a -> a.getNombreMembres() != null ? a.getNombreMembres() : 0) - .sum(); - statistiques.setTotalMembres(totalMembres); - double moyenne = associations.isEmpty() ? 0 : (double) totalMembres / associations.size(); - statistiques.setMoyenneMembresParEntite((int) moyenne); - initializeRevenusStats(); - statistiques.setSouscriptionsExpirantes(0); - statistiques.setEntitesQuotaAtteint(0); - initializeSouscriptionStats(associations); - statistiques.setFormulairePopulaire("N/A"); - statistiques.setTauxRenouvellement(0.0f); - } catch (Exception e) { - LOG.errorf(e, "Erreur lors du calcul des statistiques"); - statistiques.setTotalEntites(0); - statistiques.setEntitesActives(0); - statistiques.setTotalMembres(0); - statistiques.setMoyenneMembresParEntite(0); - } - calculerStatistiquesSouscriptions(); - } - - private void initializeEntites() { - toutesLesEntites = new ArrayList<>(); - try { - PagedResponse response = organisationService.listerToutes(0, 1000); - if (response != null && response.getData() != null) { - for (OrganisationSummaryResponse dto : response.getData()) { - Entite entite = convertToEntite(dto); - toutesLesEntites.add(entite); - } - } - } catch (Exception e) { - LOG.errorf(e, "Erreur lors du chargement des entités"); - } - } - - private Entite convertToEntite(OrganisationSummaryResponse dto) { - Entite entite = new Entite(); - entite.setId(dto.getId()); - entite.setNom(dto.getNom()); - entite.setCodeEntite(dto.getNomCourt()); // Using nomCourt as code - entite.setType(dto.getTypeOrganisation()); - entite.setTypeLibelle(typeCatalogueService.resolveLibelle(dto.getTypeOrganisation())); - entite.setRegion(null); // Not available in Summary - entite.setStatut(dto.getStatut()); - entite.setNombreMembres(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0); - entite.setMembresUtilises(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0); - entite.setAdresse(null); // Not available in Summary - entite.setTelephone(null); // Not available in Summary - entite.setEmail(null); // Not available in Summary - entite.setDescription(null); // Not available in Summary - entite.setDerniereActivite(null); // Not available in Summary - - try { - SouscriptionStatutResponse souscription = souscriptionService.obtenirActive(dto.getId()); - if (souscription != null) { - entite.setForfaitSouscrit( - souscription.getPlanCommercial() != null ? souscription.getPlanCommercial() : "Non défini"); - entite.setMembresQuota( - souscription.getQuotaMax() != null ? souscription.getQuotaMax() : 0); - entite.setMontantMensuel(souscription.getMontantTotal() != null - ? String.format("%,.0f FCFA", souscription.getMontantTotal().doubleValue()) - : "0 FCFA"); - entite.setDateExpirationSouscription(souscription.getDateFin()); - entite.setStatutSouscription( - souscription.getStatut() != null ? souscription.getStatut() : "NON_DEFINI"); - } else { - entite.setForfaitSouscrit("Non défini"); - entite.setMembresQuota(0); - entite.setMontantMensuel("0 FCFA"); - entite.setDateExpirationSouscription(null); - entite.setStatutSouscription("NON_DEFINI"); - } - } catch (Exception e) { - entite.setForfaitSouscrit("Non défini"); - entite.setMembresQuota(0); - entite.setMontantMensuel("0 FCFA"); - entite.setDateExpirationSouscription(null); - entite.setStatutSouscription("NON_DEFINI"); - } - - return entite; - } - - // Overload for full OrganisationResponse (CRUD operations) - private Entite convertToEntite(OrganisationResponse dto) { - Entite entite = new Entite(); - entite.setId(dto.getId()); - entite.setNom(dto.getNom()); - entite.setCodeEntite(dto.getNomCourt()); - entite.setType(dto.getTypeOrganisation()); - entite.setTypeLibelle(typeCatalogueService.resolveLibelle(dto.getTypeOrganisation())); - entite.setRegion(dto.getRegion()); - entite.setVille(dto.getVille()); - entite.setStatut(dto.getStatut()); - entite.setNombreMembres(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0); - entite.setMembresUtilises(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0); - entite.setAdresse(dto.getAdresse()); - entite.setTelephone(dto.getTelephone()); - entite.setEmail(dto.getEmail()); - entite.setDescription(dto.getDescription()); - entite.setDerniereActivite(null); - - try { - SouscriptionStatutResponse souscription = souscriptionService.obtenirActive(dto.getId()); - if (souscription != null) { - entite.setForfaitSouscrit( - souscription.getPlanCommercial() != null ? souscription.getPlanCommercial() : "Non défini"); - entite.setMembresQuota( - souscription.getQuotaMax() != null ? souscription.getQuotaMax() : 0); - entite.setMontantMensuel(souscription.getMontantTotal() != null - ? String.format("%,.0f FCFA", souscription.getMontantTotal().doubleValue()) - : "0 FCFA"); - entite.setDateExpirationSouscription(souscription.getDateFin()); - entite.setStatutSouscription( - souscription.getStatut() != null ? souscription.getStatut() : "NON_DEFINI"); - } else { - entite.setForfaitSouscrit("Non défini"); - entite.setMembresQuota(0); - entite.setMontantMensuel("0 FCFA"); - entite.setDateExpirationSouscription(null); - entite.setStatutSouscription("NON_DEFINI"); - } - } catch (Exception e) { - entite.setForfaitSouscrit("Non défini"); - entite.setMembresQuota(0); - entite.setMontantMensuel("0 FCFA"); - entite.setDateExpirationSouscription(null); - entite.setStatutSouscription("NON_DEFINI"); - } - - return entite; - } - - private void initializeNouvelleEntite() { - nouvelleEntite = new Entite(); - } - - private void appliquerFiltres() { - entitesFiltrees = toutesLesEntites.stream() - .filter(this::appliquerFiltre) - .collect(Collectors.toList()); - } - - private boolean appliquerFiltre(Entite entite) { - // Filtre par nom - if (filtres.getNom() != null && !filtres.getNom().trim().isEmpty()) { - if (!entite.getNom().toLowerCase().contains(filtres.getNom().toLowerCase())) { - return false; - } - } - - // Filtre par type - if (filtres.getType() != null && !filtres.getType().trim().isEmpty()) { - if (!entite.getType().equals(filtres.getType())) { - return false; - } - } - - // Filtre par statut - if (filtres.getStatut() != null && !filtres.getStatut().trim().isEmpty()) { - if (!entite.getStatut().equals(filtres.getStatut())) { - return false; - } - } - - // Filtre par région - if (filtres.getRegion() != null && !filtres.getRegion().trim().isEmpty()) { - if (!entite.getRegion().equals(filtres.getRegion())) { - return false; - } - } - - // Filtre par forfait - if (filtres.getForfait() != null && !filtres.getForfait().trim().isEmpty()) { - if (!entite.getForfaitSouscrit().equals(filtres.getForfait())) { - return false; - } - } - - // Filtre par alerte quota - if (filtres.getAlerteQuota() != null && !filtres.getAlerteQuota().trim().isEmpty()) { - if ("OUI".equals(filtres.getAlerteQuota()) && !entite.isQuotaProche()) { - return false; - } - if ("NON".equals(filtres.getAlerteQuota()) && entite.isQuotaProche()) { - return false; - } - } - - // Filtre par alerte expiration - if (filtres.getAlerteExpiration() != null && !filtres.getAlerteExpiration().trim().isEmpty()) { - if ("OUI".equals(filtres.getAlerteExpiration()) && !entite.isExpirationProche()) { - return false; - } - if ("NON".equals(filtres.getAlerteExpiration()) && entite.isExpirationProche()) { - return false; - } - } - - // Filtre par statut souscription - if (filtres.getStatutSouscription() != null && !filtres.getStatutSouscription().trim().isEmpty()) { - if (!entite.getStatutSouscription().equals(filtres.getStatutSouscription())) { - return false; - } - } - - return true; - } - - // Actions - public void rechercher() { - appliquerFiltres(); - } - - public void reinitialiserFiltres() { - filtres = new Filtres(); - appliquerFiltres(); - } - - public String voirEntite(Entite entite) { - return "/pages/secure/organisation/detail.xhtml?id=" + entite.getId() + "&faces-redirect=true"; - } - - public void creerEntite() { - if (nouvelleEntite == null || nouvelleEntite.getNom() == null || nouvelleEntite.getNom().isBlank()) { - LOG.warn("Tentative de création d'une entité sans nom"); - return; - } - - try { - OrganisationResponse dto = new OrganisationResponse(); - dto.setNom(nouvelleEntite.getNom()); - dto.setTypeOrganisation(nouvelleEntite.getType()); - dto.setRegion(nouvelleEntite.getRegion()); - dto.setAdresse(nouvelleEntite.getAdresse()); - dto.setVille(nouvelleEntite.getVille()); - dto.setTelephone(nouvelleEntite.getTelephone()); - dto.setEmail(nouvelleEntite.getEmail()); - dto.setDescription(nouvelleEntite.getDescription()); - dto.setStatut("ACTIVE"); - - OrganisationResponse creee = organisationService.creer(dto); - LOG.infof("Entité créée avec succès : id=%s, nom=%s", creee.getId(), creee.getNom()); - - toutesLesEntites.add(convertToEntite(creee)); - appliquerFiltres(); - initializeNouvelleEntite(); - - } catch (Exception e) { - LOG.errorf(e, "Erreur lors de la création de l'entité"); - } - } - - // ── Préparation du dialog Modifier ────────────────────────────────────── - - public void preparerModification(Entite entite) { - this.entiteSelectionne = entite; - try { - entiteEnEdition = organisationService.obtenirParId(entite.getId()); - } catch (Exception e) { - LOG.errorf(e, "Impossible de charger les détails de l'entité %s pour modification", entite.getId()); - entiteEnEdition = new OrganisationResponse(); - entiteEnEdition.setId(entite.getId()); - entiteEnEdition.setNom(entite.getNom()); - entiteEnEdition.setTypeOrganisation(entite.getType()); - entiteEnEdition.setRegion(entite.getRegion()); - entiteEnEdition.setAdresse(entite.getAdresse()); - entiteEnEdition.setVille(entite.getVille()); - entiteEnEdition.setTelephone(entite.getTelephone()); - entiteEnEdition.setEmail(entite.getEmail()); - entiteEnEdition.setStatut(entite.getStatut()); - } - } - - public void modifierEntite() { - if (entiteEnEdition == null || entiteEnEdition.getId() == null) return; - try { - OrganisationResponse maj = organisationService.modifier(entiteEnEdition.getId(), entiteEnEdition); - Entite entiteMaj = convertToEntite(maj); - int idx = -1; - for (int i = 0; i < toutesLesEntites.size(); i++) { - if (toutesLesEntites.get(i).getId().equals(maj.getId())) { - idx = i; - break; - } - } - if (idx >= 0) toutesLesEntites.set(idx, entiteMaj); - appliquerFiltres(); - errorHandler.showSuccess("Succès", "Entité '" + maj.getNom() + "' modifiée."); - } catch (Exception e) { - LOG.errorf(e, "Erreur lors de la modification de l'entité"); - errorHandler.handleException(e, "lors de la modification de l'entité", null); - } - } - - // ── Navigation depuis le dialog Actions ───────────────────────────────── - - public String gererMembres() { - if (entiteSelectionne == null) return null; - return "/pages/secure/membre/liste.xhtml?organisationId=" + entiteSelectionne.getId() + "&faces-redirect=true"; - } - - public String configurerEntite() { - if (entiteSelectionne == null) return null; - return "/pages/secure/organisation/detail.xhtml?id=" + entiteSelectionne.getId() + "&faces-redirect=true"; - } - - public String voirRapports() { - if (entiteSelectionne == null) return null; - return "/pages/admin/rapports/statistiques.xhtml?faces-redirect=true"; - } - - // ── Actions de statut (persistées en base) ──────────────────────────────── - - public void suspendreEntite() { - if (entiteSelectionne == null) return; - try { - OrganisationResponse maj = organisationService.suspendre(entiteSelectionne.getId()); - mettreAJourStatutEntite(maj); - errorHandler.showSuccess("Suspendues", "Entité '" + entiteSelectionne.getNom() + "' suspendue."); - } catch (Exception e) { - LOG.errorf(e, "Erreur lors de la suspension de l'entité"); - errorHandler.handleException(e, "lors de la suspension de l'entité", null); - } - } - - public void reactiverEntite() { - if (entiteSelectionne == null) return; - try { - OrganisationResponse maj = organisationService.activer(entiteSelectionne.getId()); - mettreAJourStatutEntite(maj); - errorHandler.showSuccess("Réactivée", "Entité '" + entiteSelectionne.getNom() + "' réactivée."); - } catch (Exception e) { - LOG.errorf(e, "Erreur lors de la réactivation de l'entité"); - errorHandler.handleException(e, "lors de la réactivation de l'entité", null); - } - } - - private void mettreAJourStatutEntite(OrganisationResponse maj) { - for (Entite e : toutesLesEntites) { - if (e.getId().equals(maj.getId())) { - e.setStatut(maj.getStatut()); - break; - } - } - appliquerFiltres(); - } - - public void supprimerEntite() { - if (entiteSelectionne == null) return; - try { - organisationService.supprimer(entiteSelectionne.getId()); - toutesLesEntites.removeIf(e -> e.getId().equals(entiteSelectionne.getId())); - appliquerFiltres(); - errorHandler.showSuccess("Supprimée", "Entité supprimée avec succès."); - entiteSelectionne = null; - } catch (Exception e) { - LOG.errorf(e, "Erreur lors de la suppression de l'entité"); - errorHandler.handleException(e, "lors de la suppression de l'entité", null); - } - } - - public void exporterEntites() { - LOG.infof("Export de %d entités", entitesFiltrees.size()); - } - - // Getters et Setters - public List getToutesLesEntites() { - return toutesLesEntites; - } - - public void setToutesLesEntites(List toutesLesEntites) { - this.toutesLesEntites = toutesLesEntites; - } - - public List getEntitesFiltrees() { - return entitesFiltrees; - } - - public void setEntitesFiltrees(List entitesFiltrees) { - this.entitesFiltrees = entitesFiltrees; - } - - public List getEntitesSelectionnees() { - return entitesSelectionnees; - } - - public void setEntitesSelectionnees(List entitesSelectionnees) { - this.entitesSelectionnees = entitesSelectionnees; - } - - public Entite getEntiteSelectionne() { - return entiteSelectionne; - } - - public void setEntiteSelectionne(Entite entiteSelectionne) { - this.entiteSelectionne = entiteSelectionne; - } - - public OrganisationResponse getEntiteEnEdition() { return entiteEnEdition; } - public void setEntiteEnEdition(OrganisationResponse entiteEnEdition) { this.entiteEnEdition = entiteEnEdition; } - - public Entite getNouvelleEntite() { - return nouvelleEntite; - } - - public void setNouvelleEntite(Entite nouvelleEntite) { - this.nouvelleEntite = nouvelleEntite; - } - - public Filtres getFiltres() { - return filtres; - } - - public void setFiltres(Filtres filtres) { - this.filtres = filtres; - } - - public Statistiques getStatistiques() { - return statistiques; - } - - public void setStatistiques(Statistiques statistiques) { - this.statistiques = statistiques; - } - - private void initializeRevenusStats() { - try { - Map stats = cotisationService.obtenirStatistiques(); - if (stats != null) { - Object montantTotal = stats.get("montantTotal"); - if (montantTotal instanceof Number) { - statistiques.setRevenus(String.format("%,.0f FCFA", ((Number) montantTotal).doubleValue())); - } else { - statistiques.setRevenus("0 FCFA"); - } - } else { - statistiques.setRevenus("0 FCFA"); - } - } catch (Exception e) { - LOG.debugf("Impossible de charger les stats cotisations: %s", e.getMessage()); - statistiques.setRevenus("0 FCFA"); - } - } - - private void initializeSouscriptionStats(List associations) { - try { - int expirantes = 0; - int totalSouscriptions = 0; - int souscriptionsActives = 0; - String forfaitLePlusPopulaire = "N/A"; - Map forfaitCount = new java.util.HashMap<>(); - - for (OrganisationSummaryResponse assoc : associations) { - try { - SouscriptionStatutResponse souscription = souscriptionService.obtenirActive(assoc.getId()); - if (souscription != null) { - totalSouscriptions++; - if ("ACTIVE".equals(souscription.getStatut())) { - souscriptionsActives++; - } - if (souscription.getDateFin() != null - && souscription.getDateFin().isAfter(LocalDate.now()) - && souscription.getDateFin().isBefore(LocalDate.now().plusDays(30))) { - expirantes++; - } - String forfait = souscription.getPlanCommercial() != null ? souscription.getPlanCommercial() - : "Inconnu"; - forfaitCount.merge(forfait, 1, Integer::sum); - } - } catch (Exception ignored) { - // Organisation sans souscription active - } - } - - statistiques.setSouscriptionsExpirantes(expirantes); - if (!forfaitCount.isEmpty()) { - forfaitLePlusPopulaire = forfaitCount.entrySet().stream() - .max(Map.Entry.comparingByValue()) - .map(Map.Entry::getKey) - .orElse("N/A"); - } - statistiques.setFormulairePopulaire(forfaitLePlusPopulaire); - statistiques.setTauxRenouvellement(totalSouscriptions > 0 - ? (float) souscriptionsActives / totalSouscriptions * 100 - : 0.0f); - } catch (Exception e) { - LOG.debugf("Impossible de charger les stats souscriptions: %s", e.getMessage()); - } - } - - // Méthodes utilitaires pour les souscriptions - private void calculerStatistiquesSouscriptions() { - if (toutesLesEntites == null || statistiques == null) { - return; // Sécurité si appelé avant initialisation complète - } - - int expirantes = 0; - int quotaAtteint = 0; - - for (Entite entite : toutesLesEntites) { - if (entite.isExpirationProche()) { - expirantes++; - } - if (entite.isQuotaAtteint()) { - quotaAtteint++; - } - } - - statistiques.setSouscriptionsExpirantes(expirantes); - statistiques.setEntitesQuotaAtteint(quotaAtteint); - } - - public void renouvelerSouscription() { - if (entiteSelectionne != null) { - entiteSelectionne.setDateExpirationSouscription(LocalDate.now().plusMonths(12)); - entiteSelectionne.setStatutSouscription("ACTIVE"); - LOG.infof("Souscription renouvelée pour: %s", entiteSelectionne.getNom()); - appliquerFiltres(); - } - } - - public void upgraderForfait() { - if (entiteSelectionne != null) { - String forfaitActuel = entiteSelectionne.getForfaitSouscrit(); - switch (forfaitActuel) { - case "Starter": - entiteSelectionne.setForfaitSouscrit("Standard"); - entiteSelectionne.setMembresQuota(200); - entiteSelectionne.setMontantMensuel("3 000 FCFA"); - break; - case "Standard": - entiteSelectionne.setForfaitSouscrit("Premium"); - entiteSelectionne.setMembresQuota(500); - entiteSelectionne.setMontantMensuel("4 000 FCFA"); - break; - case "Premium": - entiteSelectionne.setForfaitSouscrit("Cristal"); - entiteSelectionne.setMembresQuota(2000); - entiteSelectionne.setMontantMensuel("5 000 FCFA"); - break; - } - LOG.infof("Forfait upgradé pour: %s", entiteSelectionne.getNom()); - appliquerFiltres(); - } - } - - public void gererQuotas() { - LOG.info("Gestion des quotas pour toutes les entités"); - } - - public void envoyerRelancesSouscriptions() { - int compteur = 0; - for (Entite entite : toutesLesEntites) { - if (entite.isExpirationProche()) { - LOG.infof("Relance envoyée à: %s", entite.getNom()); - compteur++; - } - } - LOG.infof("%d relances de souscription envoyées", compteur); - } - - // Actions groupées - public void renouvelerSouscriptionsGroupees() { - int compteur = 0; - for (Entite entite : entitesSelectionnees) { - entite.setDateExpirationSouscription(LocalDate.now().plusMonths(12)); - entite.setStatutSouscription("ACTIVE"); - compteur++; - } - LOG.infof("%d souscriptions renouvelées en masse", compteur); - entitesSelectionnees.clear(); - appliquerFiltres(); - } - - public void suspendreEntitesGroupees() { - int compteur = 0; - for (Entite entite : entitesSelectionnees) { - entite.setStatut("SUSPENDUE"); - compteur++; - } - LOG.infof("%d entités suspendues en masse", compteur); - entitesSelectionnees.clear(); - appliquerFiltres(); - } - - public void reactiverEntitesGroupees() { - int compteur = 0; - for (Entite entite : entitesSelectionnees) { - entite.setStatut("ACTIVE"); - compteur++; - } - LOG.infof("%d entités réactivées en masse", compteur); - entitesSelectionnees.clear(); - appliquerFiltres(); - } - - public void proposerUpgradeGroupees() { - int compteur = 0; - for (Entite entite : entitesSelectionnees) { - if (entite.isQuotaProche()) { - // Simulation d'envoi de proposition d'upgrade - LOG.infof("Proposition d'upgrade envoyée à: %s", entite.getNom()); - compteur++; - } - } - LOG.infof("%d propositions d'upgrade envoyées", compteur); - } - - // Classes internes - public static class Entite { - private UUID id; - private String nom; - private String codeEntite; - private String type; - private String typeLibelle; - private String region; - private String statut; - private int nombreMembres; - private String adresse; - private String ville; // Ajouté: champ manquant - private String telephone; - private String email; - private String description; - private LocalDateTime derniereActivite; - private Administrateur administrateur; - - // Informations de souscription - private String forfaitSouscrit = "Standard"; - private int membresQuota = 200; - private int membresUtilises; - private LocalDate dateExpirationSouscription; - private String statutSouscription = "ACTIVE"; - private String montantMensuel = "3 000 FCFA"; - - // Getters et setters - public UUID getId() { - return id; - } - - public void setId(UUID id) { - this.id = id; - } - - public String getNom() { - return nom; - } - - public void setNom(String nom) { - this.nom = nom; - } - - public String getCodeEntite() { - return codeEntite; - } - - public void setCodeEntite(String codeEntite) { - this.codeEntite = codeEntite; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getRegion() { - return region; - } - - public void setRegion(String region) { - this.region = region; - } - - public String getStatut() { - return statut; - } - - public void setStatut(String statut) { - this.statut = statut; - } - - public int getNombreMembres() { - return nombreMembres; - } - - public void setNombreMembres(int nombreMembres) { - this.nombreMembres = nombreMembres; - } - - public String getAdresse() { - return adresse; - } - - public void setAdresse(String adresse) { - this.adresse = adresse; - } - - public String getVille() { - return ville; - } - - public void setVille(String ville) { - this.ville = ville; - } - - public String getTelephone() { - return telephone; - } - - public void setTelephone(String telephone) { - this.telephone = telephone; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public LocalDateTime getDerniereActivite() { - return derniereActivite; - } - - public void setDerniereActivite(LocalDateTime derniereActivite) { - this.derniereActivite = derniereActivite; - } - - public Administrateur getAdministrateur() { - return administrateur; - } - - public void setAdministrateur(Administrateur administrateur) { - this.administrateur = administrateur; - } - - public String getTypeLibelle() { return typeLibelle != null ? typeLibelle : type; } - public void setTypeLibelle(String typeLibelle) { this.typeLibelle = typeLibelle; } - - // Propriétés dérivées - - public String getTypeSeverity() { - return switch (type) { - case "ASSOCIATION" -> "info"; - case "CLUB" -> "success"; - case "GROUPE" -> "warning"; - case "GROUPE_JEUNES" -> "primary"; - case "BRANCHE" -> "secondary"; - default -> "secondary"; - }; - } - - public String getTypeIcon() { - return switch (type) { - case "ASSOCIATION" -> "pi-users"; - case "CLUB" -> "pi-home"; - case "GROUPE" -> "pi-sitemap"; - case "GROUPE_JEUNES" -> "pi-star"; - case "BRANCHE" -> "pi-share-alt"; - default -> "pi-building"; - }; - } - - public String getStatutSeverity() { - return switch (statut) { - case "ACTIVE" -> "success"; - case "INACTIVE" -> "warning"; - case "SUSPENDUE" -> "danger"; - default -> "secondary"; - }; - } - - public String getStatutIcon() { - return switch (statut) { - case "ACTIVE" -> "pi-check"; - case "INACTIVE" -> "pi-pause"; - case "SUSPENDUE" -> "pi-ban"; - default -> "pi-circle"; - }; - } - - public String getDerniereActiviteFormatee() { - if (derniereActivite == null) - return "N/A"; - return derniereActivite.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")); - } - - public String getDerniereActiviteRelative() { - if (derniereActivite == null) - return ""; - long jours = ChronoUnit.DAYS.between(derniereActivite.toLocalDate(), LocalDate.now()); - if (jours == 0) - return "Aujourd'hui"; - if (jours == 1) - return "Hier"; - if (jours < 7) - return "Il y a " + jours + " jours"; - if (jours < 30) - return "Il y a " + (jours / 7) + " semaine" + (jours / 7 > 1 ? "s" : ""); - return "Il y a " + (jours / 30) + " mois"; - } - - // Getters et setters pour les informations de souscription - public String getForfaitSouscrit() { - return forfaitSouscrit; - } - - public void setForfaitSouscrit(String forfaitSouscrit) { - this.forfaitSouscrit = forfaitSouscrit; - } - - public int getMembresQuota() { - return membresQuota; - } - - public void setMembresQuota(int membresQuota) { - this.membresQuota = membresQuota; - } - - public int getMembresUtilises() { - return membresUtilises; - } - - public void setMembresUtilises(int membresUtilises) { - this.membresUtilises = membresUtilises; - } - - public LocalDate getDateExpirationSouscription() { - return dateExpirationSouscription; - } - - public void setDateExpirationSouscription(LocalDate dateExpirationSouscription) { - this.dateExpirationSouscription = dateExpirationSouscription; - } - - public String getStatutSouscription() { - return statutSouscription; - } - - public void setStatutSouscription(String statutSouscription) { - this.statutSouscription = statutSouscription; - } - - public String getMontantMensuel() { - return montantMensuel; - } - - public void setMontantMensuel(String montantMensuel) { - this.montantMensuel = montantMensuel; - } - - // Méthodes utilitaires pour les souscriptions - public boolean isQuotaProche() { - return getMembresUtilises() >= (getMembresQuota() * 0.85); - } - - public boolean isQuotaAtteint() { - return getMembresUtilises() >= getMembresQuota(); - } - - public boolean isExpirationProche() { - if (dateExpirationSouscription == null) - return false; - return ChronoUnit.DAYS.between(LocalDate.now(), dateExpirationSouscription) <= 30; - } - - public int getPourcentageUtilisationQuota() { - if (membresQuota == 0) - return 0; - return (membresUtilises * 100) / membresQuota; - } - - public String getForfaitCouleur() { - return switch (forfaitSouscrit) { - case "Starter" -> "primary"; - case "Standard" -> "success"; - case "Premium" -> "warning"; - case "Cristal" -> "info"; - default -> "secondary"; - }; - } - - public String getForfaitIcone() { - return switch (forfaitSouscrit) { - case "Starter" -> "pi-star"; - case "Standard" -> "pi-users"; - case "Premium" -> "pi-crown"; - case "Cristal" -> "pi-diamond"; - default -> "pi-circle"; - }; - } - - public long getJoursAvantExpiration() { - if (dateExpirationSouscription == null) - return 0; - return ChronoUnit.DAYS.between(LocalDate.now(), dateExpirationSouscription); - } - } - - public static class Administrateur { - private String nomComplet; - private String email; - - // Getters et setters - public String getNomComplet() { - return nomComplet; - } - - public void setNomComplet(String nomComplet) { - this.nomComplet = nomComplet; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - } - - public static class Filtres { - private String nom; - private String type; - private String statut; - private String region; - private String forfait; - private String alerteQuota; - private String alerteExpiration; - private String statutSouscription; - - // Getters et setters - public String getNom() { - return nom; - } - - public void setNom(String nom) { - this.nom = nom; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getStatut() { - return statut; - } - - public void setStatut(String statut) { - this.statut = statut; - } - - public String getRegion() { - return region; - } - - public void setRegion(String region) { - this.region = region; - } - - public String getForfait() { - return forfait; - } - - public void setForfait(String forfait) { - this.forfait = forfait; - } - - public String getAlerteQuota() { - return alerteQuota; - } - - public void setAlerteQuota(String alerteQuota) { - this.alerteQuota = alerteQuota; - } - - public String getAlerteExpiration() { - return alerteExpiration; - } - - public void setAlerteExpiration(String alerteExpiration) { - this.alerteExpiration = alerteExpiration; - } - - public String getStatutSouscription() { - return statutSouscription; - } - - public void setStatutSouscription(String statutSouscription) { - this.statutSouscription = statutSouscription; - } - } - - public static class Statistiques { - private int totalEntites; - private int entitesActives; - private int totalMembres; - private String revenus; - private int souscriptionsExpirantes; - private int entitesQuotaAtteint; - private String formulairePopulaire; - private float tauxRenouvellement; - private int moyenneMembresParEntite; - - // Getters et setters - public int getTotalEntites() { - return totalEntites; - } - - public void setTotalEntites(int totalEntites) { - this.totalEntites = totalEntites; - } - - public int getEntitesActives() { - return entitesActives; - } - - public void setEntitesActives(int entitesActives) { - this.entitesActives = entitesActives; - } - - public int getTotalMembres() { - return totalMembres; - } - - public void setTotalMembres(int totalMembres) { - this.totalMembres = totalMembres; - } - - public String getRevenus() { - return revenus; - } - - public void setRevenus(String revenus) { - this.revenus = revenus; - } - - public int getSouscriptionsExpirantes() { - return souscriptionsExpirantes; - } - - public void setSouscriptionsExpirantes(int souscriptionsExpirantes) { - this.souscriptionsExpirantes = souscriptionsExpirantes; - } - - public int getEntitesQuotaAtteint() { - return entitesQuotaAtteint; - } - - public void setEntitesQuotaAtteint(int entitesQuotaAtteint) { - this.entitesQuotaAtteint = entitesQuotaAtteint; - } - - public String getFormulairePopulaire() { - return formulairePopulaire; - } - - public void setFormulairePopulaire(String formulairePopulaire) { - this.formulairePopulaire = formulairePopulaire; - } - - public float getTauxRenouvellement() { - return tauxRenouvellement; - } - - public void setTauxRenouvellement(float tauxRenouvellement) { - this.tauxRenouvellement = tauxRenouvellement; - } - - public int getMoyenneMembresParEntite() { - return moyenneMembresParEntite; - } - - public void setMoyenneMembresParEntite(int moyenneMembresParEntite) { - this.moyenneMembresParEntite = moyenneMembresParEntite; - } - - public String getTauxRenouvellementFormat() { - return String.format("%.1f%%", tauxRenouvellement); - } - } -} diff --git a/src/main/java/dev/lions/unionflow/client/view/NavigationBean.java b/src/main/java/dev/lions/unionflow/client/view/NavigationBean.java index 93ea91d..d89487d 100644 --- a/src/main/java/dev/lions/unionflow/client/view/NavigationBean.java +++ b/src/main/java/dev/lions/unionflow/client/view/NavigationBean.java @@ -127,8 +127,8 @@ public class NavigationBean implements Serializable { return "Tableau de Bord"; } else if (viewId.contains("membres")) { return "Gestion des Membres"; - } else if (viewId.contains("entites")) { - return "Gestion des Entités"; + } else if (viewId.contains("organisation")) { + return "Gestion des Organisations"; } else if (viewId.contains("configuration")) { return "Configuration"; } else if (viewId.contains("rapports")) { diff --git a/src/main/java/dev/lions/unionflow/client/view/SuperAdminBean.java b/src/main/java/dev/lions/unionflow/client/view/SuperAdminBean.java index 685c780..1730e1f 100644 --- a/src/main/java/dev/lions/unionflow/client/view/SuperAdminBean.java +++ b/src/main/java/dev/lions/unionflow/client/view/SuperAdminBean.java @@ -37,8 +37,8 @@ public class SuperAdminBean implements Serializable { private static final Logger LOG = Logger.getLogger(SuperAdminBean.class); // Constantes de navigation outcomes (WOU/DRY - réutilisables) - private static final String OUTCOME_ENTITE_NOUVELLE = "entiteNouvellePage"; - private static final String OUTCOME_ENTITE_GESTION = "entiteGestionPage"; + private static final String OUTCOME_ORGANISATION_NOUVELLE = "organisationNouvellePage"; + private static final String OUTCOME_ORGANISATION_GESTION = "organisationGestionPage"; private static final String OUTCOME_SUPER_ADMIN_RAPPORTS = "superAdminRapportsPage"; private static final String OUTCOME_SUPER_ADMIN_CONFIGURATION = "superAdminConfigurationPage"; private static final String OUTCOME_SUPER_ADMIN_ALERTES = "superAdminAlertesPage"; @@ -431,12 +431,12 @@ public class SuperAdminBean implements Serializable { } // Actions (WOU/DRY - utilisation de navigation outcomes) - public String creerEntite() { - return OUTCOME_ENTITE_NOUVELLE + "?faces-redirect=true"; + public String creerOrganisation() { + return OUTCOME_ORGANISATION_NOUVELLE + "?faces-redirect=true"; } - public String gererEntites() { - return OUTCOME_ENTITE_GESTION + "?faces-redirect=true"; + public String gererOrganisations() { + return OUTCOME_ORGANISATION_GESTION + "?faces-redirect=true"; } public String genererRapport() { diff --git a/src/main/resources/META-INF/faces-config.xml b/src/main/resources/META-INF/faces-config.xml index b33ce1f..9d36116 100644 --- a/src/main/resources/META-INF/faces-config.xml +++ b/src/main/resources/META-INF/faces-config.xml @@ -546,16 +546,16 @@ - Page de création d'entité (Super Admin) - entiteNouvellePage - /pages/super-admin/entites/nouvelle.xhtml + Page de création d'organisation (Super Admin) + organisationNouvellePage + /pages/secure/organisation/nouvelle.xhtml - Page de gestion des entités (Super Admin) - entiteGestionPage - /pages/super-admin/entites/gestion.xhtml + Page de gestion des organisations (Super Admin) + organisationGestionPage + /pages/secure/organisation/liste.xhtml @@ -588,9 +588,9 @@ - Page de détails d'entité - entiteDetailsPage - /pages/super-admin/entites/details.xhtml + Page de détails d'organisation + organisationDetailsPage + /pages/secure/organisation/detail.xhtml @@ -602,16 +602,9 @@ - Page de configuration d'entité - entiteConfigurationPage - /pages/super-admin/entites/configuration.xhtml - - - - - Page de rapports d'entité - entiteRapportsPage - /pages/super-admin/entites/rapports.xhtml + Page de statistiques d'organisation + organisationStatistiquesPage + /pages/secure/organisation/statistiques.xhtml diff --git a/src/main/resources/META-INF/resources/pages/super-admin/dashboard.xhtml b/src/main/resources/META-INF/resources/pages/super-admin/dashboard.xhtml index 740a934..bca4387 100644 --- a/src/main/resources/META-INF/resources/pages/super-admin/dashboard.xhtml +++ b/src/main/resources/META-INF/resources/pages/super-admin/dashboard.xhtml @@ -32,7 +32,7 @@ - + @@ -67,7 +67,7 @@ - + @@ -103,18 +103,18 @@
    - + - +
    - + - + @@ -205,12 +205,12 @@
    - +
    - Top 5 Entités + Top 5 Organisations
    -
    Aucune entité enregistrée
    +
    Aucune organisation enregistrée
    @@ -346,7 +346,7 @@
    #{superAdminBean.revenus.moyenne}
    -
    Revenu moyen / entité
    +
    Revenu moyen / organisation
    diff --git a/src/main/resources/META-INF/resources/pages/super-admin/entites/gestion-enhanced.xhtml b/src/main/resources/META-INF/resources/pages/super-admin/entites/gestion-enhanced.xhtml deleted file mode 100644 index 34f2f88..0000000 --- a/src/main/resources/META-INF/resources/pages/super-admin/entites/gestion-enhanced.xhtml +++ /dev/null @@ -1,641 +0,0 @@ - - - - Gestion des Entités Enhanced - UnionFlow - - - - - - - > -
    -
    -
    -
    -
    -

    - - Gestion des Entités - Stratégie Volume -

    -

    Administration complète avec suivi des souscriptions et quotas

    -
    - -
    - - - - -
    -
    -
    -
    -
    -
    - - > -
    -
    -
    -
    -
    -
    #{entitesGestionBean.statistiques.totalEntites}
    -
    Total Entités
    -
    - - #{entitesGestionBean.statistiques.entitesActives} actives -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    #{entitesGestionBean.statistiques.totalMembres}
    -
    Total Membres
    -
    - - Moyenne: 146/entité -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    #{entitesGestionBean.statistiques.souscriptionsExpirantes}
    -
    Expirations Proches
    -
    - - Sous 30 jours -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    #{entitesGestionBean.statistiques.entitesQuotaAtteint}
    -
    Quotas Atteints
    -
    - - Nécessitent upgrade -
    -
    -
    - -
    -
    -
    -
    -
    - - > -
    -
    -
    -
    Répartition par Forfait - Nouvelle Grille Tarifaire
    -
    -
    -
    -
    44
    -
    Starter
    -
    2K FCFA/mois
    -
    100 membres max
    -
    -
    -
    -
    -
    60
    -
    Standard
    -
    3K FCFA/mois
    -
    200 membres max
    -
    -
    -
    -
    -
    20
    -
    Premium
    -
    4K FCFA/mois
    -
    500 membres max
    -
    -
    -
    -
    -
    3
    -
    Cristal
    -
    5K FCFA/mois
    -
    2000 membres max
    -
    -
    -
    -
    -
    - -
    -
    -
    Performance Commerciale
    -
    -
    -
    -
    #{entitesGestionBean.statistiques.revenus}
    -
    Revenus Mensuels
    -
    -
    -
    -
    -
    #{entitesGestionBean.statistiques.tauxRenouvellementFormat}
    -
    Taux Renouvellement
    -
    -
    -
    -
    -
    Forfait le plus populaire
    -
    - - 60 souscriptions -
    -
    -
    -
    -
    - - > -
    -
    Filtres et Recherche Avancée
    - -
    -
    -
    -
    - - - - -
    -
    -
    -
    - - - - - - - - - -
    -
    -
    -
    - - - - - - - - -
    -
    -
    -
    - - - - - - - - -
    -
    -
    -
    - -
    - - -
    -
    -
    -
    - - - -
    -
    -
    - - - - - - - - - -
    -
    -
    -
    - - - - - - - -
    -
    -
    -
    - - - - - - - -
    -
    -
    -
    - - - - - - - - -
    -
    -
    -
    -
    -
    - - - - > -
    -
    -
    Entités avec Souscriptions (#{entitesGestionBean.entitesFiltrees.size()})
    -
    - - - - - #{entitesGestionBean.entitesFiltrees.size()} sur #{entitesGestionBean.toutesLesEntites.size()} entités - -
    -
    - - - - - - -
    -
    - -
    -
    -
    #{entite.nom}
    -
    #{entite.codeEntite}
    -
    -
    -
    - - -
    - -
    #{entite.montantMensuel}
    -
    -
    - - -
    -
    #{entite.membresUtilises}/#{entite.membresQuota}
    -
    -
    -
    -
    #{entite.pourcentageUtilisationQuota}%
    -
    -
    - - -
    -
    - #{entite.dateExpirationSouscription != null ? entite.dateExpirationSouscription.format(java.time.format.DateTimeFormatter.ofPattern('dd/MM/yyyy')) : 'N/A'} -
    -
    - - #{entite.joursAvantExpiration} jours -
    -
    -
    - - - #{entite.region} - - - - - - - - -
    - - - - - - - - - - -
    -
    -
    -
    -
    - - > - - -
    -
    - -

    Confirmer le renouvellement

    -

    - Entité: #{entitesGestionBean.entiteSelectionne.nom}
    - Forfait: #{entitesGestionBean.entiteSelectionne.forfaitSouscrit}
    - Montant: #{entitesGestionBean.entiteSelectionne.montantMensuel} -

    -
    - -
    - - -
    -
    -
    -
    - - > - - -
    -
    - -

    Upgrader le forfait

    -

    - Entité: #{entitesGestionBean.entiteSelectionne.nom}
    - Forfait actuel: #{entitesGestionBean.entiteSelectionne.forfaitSouscrit}
    - Quota utilisé: #{entitesGestionBean.entiteSelectionne.pourcentageUtilisationQuota}% -

    -
    - -
    - - -
    -
    -
    -
    - - > - - -
    -
    - -

    Actions sur #{entitesGestionBean.entitesSelectionnees.size()} entités sélectionnées

    -
    - -
    -
    -
    Actions de Souscription
    - - - - - -
    - -
    -
    Actions Administratives
    - - - - - -
    -
    - -
    - -
    -
    -
    -
    - - > - - -
    -
    - - - - - - - - - -
    -
    - -
    - -
    -
    -
    -
    - -
    \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/super-admin/entites/gestion.xhtml b/src/main/resources/META-INF/resources/pages/super-admin/entites/gestion.xhtml deleted file mode 100644 index 68c5a6d..0000000 --- a/src/main/resources/META-INF/resources/pages/super-admin/entites/gestion.xhtml +++ /dev/null @@ -1,426 +0,0 @@ - - - - Gestion des Entités - UnionFlow - - -
    - -
    -
    -
    -

    - - Gestion des Entités -

    -

    - Administration complète des clubs et entités Lions • - #{entitesGestionBean.statistiques.totalEntites} entités • - #{entitesGestionBean.statistiques.entitesActives} actives -

    -
    -
    - - - - - -
    -
    -
    - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    -
    - - Filtres et Recherche -
    - -
    -
    - - - - - - - -
    - -
    - - - - - -
    - -
    - - - - - - - - -
    - -
    - - - - - -
    -
    - -
    - -
    -
    -
    - - -
    - -
    -
    - - Liste des Entités -
    -
    - - -
    -
    - - - - - - -
    -
    - -
    -
    -
    #{entite.nom}
    -
    #{entite.codeEntite}
    -
    -
    -
    - - - - - - - #{entite.region} - - - -
    -
    #{entite.nombreMembres}
    -
    membres
    -
    -
    - - -
    -
    -
    -
    #{entite.administrateur.nomComplet}
    -
    #{entite.administrateur.email}
    -
    -
    - - Aucun administrateur - -
    - - -
    #{entite.derniereActiviteFormatee}
    -
    #{entite.derniereActiviteRelative}
    -
    - - - - - - -
    - - - - - -
    -
    -
    -
    -
    -
    - - - - - - -
    -
    - - -
    - -
    - - - - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    -
    - -
    - - -
    -
    -
    - - - - -
    -
    Entité sélectionnée
    -
    #{entitesGestionBean.entiteSelectionne.nom}
    -
    #{entitesGestionBean.entiteSelectionne.codeEntite}
    -
    - -
    - - - - - - - - - - -
    - - -
    -
    -
    -
    -
    \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/pages/super-admin/organisations.xhtml b/src/main/resources/META-INF/resources/pages/super-admin/organisations.xhtml deleted file mode 100644 index 9d9e958..0000000 --- a/src/main/resources/META-INF/resources/pages/super-admin/organisations.xhtml +++ /dev/null @@ -1,223 +0,0 @@ - - - - Gestion des Organisations - - - - - -
    -
    -
    -
    Organisations
    - - CRUD complet des organisations. Respect DRY/WOU: composants réutilisés et simplicité. - -
    -
    - - -
    -
    -
    - - -
    - - Total - - -
    -
    - - Actives - - -
    -
    - - Inactives - - -
    -
    - -
    -
    -
    - - - -
    -
    - - - - -
    -
    - - - - -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -

    Confirmez l'action sur le statut de l'organisation ?

    - - - - -
    - -

    Supprimer cette organisation ? Cette action est irréversible.

    - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    diff --git a/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml b/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml index eed332e..1bc1ed9 100644 --- a/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml +++ b/src/main/resources/META-INF/resources/templates/components/layout/menu.xhtml @@ -1,7 +1,7 @@ - @@ -24,271 +24,202 @@
    - + + + + - - + + + + - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + + + + + + + + + + + + + + + + - + - - - + + + + - - + + - + + + + - - - + + + + - - + + + + + - + - + + - - - - - - - - - - - - - - - - + + + + + - - - - + - - - - - - - - - - - + - - - - + - - - - - + - - - - + - - - + - - - - + - - + + + + - - + + + + + - - - - - - - - - + + + + - - + + + + + + - - - - - - - - - - - - + + + + - - - + + + + - - - - - - - - - - - - + + + + - - - + - - - - - - - - - - - - - - - + + + + - - - - - - - - - - + + + + + - - - - + +