Sync: code local unifié
Synchronisation du code source local (fait foi). Signed-off-by: lions dev Team
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
package dev.lions.unionflow.client.api.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* DTO received from the backend for the member dashboard synthesis.
|
||||
*/
|
||||
public record MembreDashboardResponse(
|
||||
String prenom,
|
||||
String nom,
|
||||
LocalDate dateInscription,
|
||||
|
||||
// Cotisations
|
||||
BigDecimal mesCotisationsPaiement,
|
||||
String statutCotisations,
|
||||
Integer tauxCotisationsPerso,
|
||||
|
||||
// Epargne
|
||||
BigDecimal monSoldeEpargne,
|
||||
BigDecimal evolutionEpargneNombre,
|
||||
String evolutionEpargne,
|
||||
Integer objectifEpargne,
|
||||
|
||||
// Evenements
|
||||
Integer mesEvenementsInscrits,
|
||||
Integer evenementsAVenir,
|
||||
Integer tauxParticipationPerso,
|
||||
|
||||
// Aides
|
||||
Integer mesDemandesAide,
|
||||
Integer aidesEnCours,
|
||||
Integer tauxAidesApprouvees) implements Serializable {
|
||||
}
|
||||
@@ -130,12 +130,22 @@ public class MenuBean implements Serializable {
|
||||
|
||||
/**
|
||||
* Annuaire des Membres - Consultation de la liste (pas de modification)
|
||||
* Visible à partir de MEMBRE_ACTIF (pour créer du lien social)
|
||||
* Visible pour les responsables et bureau SEULEMENT (PAS pour MEMBRE_ACTIF)
|
||||
*
|
||||
* Raison métier: Un membre simple n'a généralement pas besoin de voir la liste complète
|
||||
* des autres membres. Cela peut poser des problèmes de:
|
||||
* - RGPD: Exposition non justifiée de données personnelles
|
||||
* - Sécurité: Risque de spam/phishing entre membres
|
||||
* - UX: Surcharge du menu pour un usage limité
|
||||
*
|
||||
* Si l'organisation souhaite activer l'annuaire pour MEMBRE_ACTIF, cela doit être
|
||||
* fait via configuration explicite (future Phase 3).
|
||||
*/
|
||||
public boolean isAnnuaireMembresVisible() {
|
||||
return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "SECRETAIRE", "TRESORIER",
|
||||
"RESPONSABLE_SOCIAL", "RESPONSABLE_EVENEMENTS", "RESPONSABLE_CREDIT",
|
||||
"MEMBRE_BUREAU", "MEMBRE_ACTIF");
|
||||
"MEMBRE_BUREAU");
|
||||
// MEMBRE_ACTIF retiré intentionnellement pour raisons UX et RGPD
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
package dev.lions.unionflow.client.bean;
|
||||
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Bean centralisé pour la sécurisation des pages basée sur les rôles.
|
||||
* Fournit des méthodes réutilisables pour vérifier l'accès et rediriger si nécessaire.
|
||||
*
|
||||
* <p>Principe DRY/WOU : Une seule implémentation de la logique de sécurité,
|
||||
* réutilisée par toutes les pages via un composant Facelet.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-02
|
||||
*/
|
||||
@Named("pageSecurityBean")
|
||||
@ApplicationScoped
|
||||
public class PageSecurityBean {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(PageSecurityBean.class);
|
||||
private static final String ACCESS_DENIED_PAGE = "/pages/secure/access-denied.xhtml";
|
||||
|
||||
@Inject
|
||||
SecurityIdentity securityIdentity;
|
||||
|
||||
@Inject
|
||||
MenuBean menuBean;
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur a le droit d'accéder à une page donnée.
|
||||
* Si non autorisé, redirige vers la page access-denied.
|
||||
*
|
||||
* @param allowedRoles Rôles autorisés séparés par des virgules (ex: "ADMIN,TRESORIER")
|
||||
* @return true si autorisé, false sinon (après redirection)
|
||||
*/
|
||||
public boolean checkAccessOrRedirect(String allowedRoles) {
|
||||
if (allowedRoles == null || allowedRoles.trim().isEmpty()) {
|
||||
// Aucune restriction = accès autorisé pour tous les utilisateurs authentifiés
|
||||
return !securityIdentity.isAnonymous();
|
||||
}
|
||||
|
||||
String[] roles = allowedRoles.split(",");
|
||||
boolean hasAccess = false;
|
||||
|
||||
for (String role : roles) {
|
||||
String trimmedRole = role.trim();
|
||||
if (hasRole(trimmedRole)) {
|
||||
hasAccess = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasAccess) {
|
||||
LOG.warnf("Accès refusé pour l'utilisateur %s à une page nécessitant les rôles: %s",
|
||||
securityIdentity.getPrincipal().getName(), allowedRoles);
|
||||
redirectToAccessDenied();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur possède un rôle spécifique.
|
||||
*
|
||||
* @param role Le rôle à vérifier
|
||||
* @return true si l'utilisateur a ce rôle
|
||||
*/
|
||||
private boolean hasRole(String role) {
|
||||
return switch (role) {
|
||||
case "SUPER_ADMIN" -> menuBean.isSuperAdmin();
|
||||
case "ADMIN_ORGANISATION", "ADMIN" -> menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "TRESORIER" -> menuBean.isTresorier() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "SECRETAIRE" -> menuBean.isSecretaire() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "RESPONSABLE_SOCIAL" -> menuBean.isResponsableSocial() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "RESPONSABLE_EVENEMENTS" -> menuBean.isResponsableEvenements() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "RESPONSABLE_CREDIT" -> menuBean.isResponsableCredit() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "MEMBRE_BUREAU" -> menuBean.isMembreBureau() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "MEMBRE_ACTIF" -> menuBean.isMembreActif() || menuBean.isMembreBureau() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "MEMBRE_SIMPLE" -> menuBean.isMembreSimple() || menuBean.isMembreActif() || menuBean.isMembreBureau() || menuBean.isAdminOrganisation() || menuBean.isSuperAdmin();
|
||||
case "ALL" -> !securityIdentity.isAnonymous(); // Tous les utilisateurs authentifiés
|
||||
default -> {
|
||||
LOG.warnf("Rôle inconnu: %s", role);
|
||||
yield false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirige vers la page d'accès refusé.
|
||||
*/
|
||||
private void redirectToAccessDenied() {
|
||||
try {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
if (ctx != null && !ctx.getResponseComplete()) {
|
||||
String contextPath = ctx.getExternalContext().getRequestContextPath();
|
||||
ctx.getExternalContext().redirect(contextPath + ACCESS_DENIED_PAGE);
|
||||
ctx.responseComplete();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Erreur lors de la redirection vers access-denied", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Méthodes helper pour vérifications rapides (utilisées dans les pages)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur peut gérer les membres.
|
||||
* @return true si SECRETAIRE, ADMIN, ou SUPER_ADMIN
|
||||
*/
|
||||
public boolean canManageMembers() {
|
||||
return hasRole("SECRETAIRE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur peut gérer les finances.
|
||||
* @return true si TRESORIER, ADMIN, ou SUPER_ADMIN
|
||||
*/
|
||||
public boolean canManageFinances() {
|
||||
return hasRole("TRESORIER");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur peut gérer les événements.
|
||||
* @return true si RESPONSABLE_EVENEMENTS, SECRETAIRE, ADMIN, ou SUPER_ADMIN
|
||||
*/
|
||||
public boolean canManageEvents() {
|
||||
return hasRole("RESPONSABLE_EVENEMENTS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur peut gérer les aides sociales.
|
||||
* @return true si RESPONSABLE_SOCIAL, ADMIN, ou SUPER_ADMIN
|
||||
*/
|
||||
public boolean canManageSocialAid() {
|
||||
return hasRole("RESPONSABLE_SOCIAL");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur peut voir les rapports financiers.
|
||||
* @return true si TRESORIER, SECRETAIRE, ADMIN, ou SUPER_ADMIN
|
||||
*/
|
||||
public boolean canViewFinancialReports() {
|
||||
return hasRole("TRESORIER") || hasRole("SECRETAIRE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur peut exporter des données.
|
||||
* @return true si TRESORIER, SECRETAIRE, ADMIN, ou SUPER_ADMIN
|
||||
*/
|
||||
public boolean canExportData() {
|
||||
return hasRole("TRESORIER") || hasRole("SECRETAIRE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur est un simple membre (MEMBRE_ACTIF uniquement).
|
||||
* @return true si MEMBRE_ACTIF mais pas d'autre rôle administratif
|
||||
*/
|
||||
public boolean isSimpleMember() {
|
||||
return menuBean.isMembreActif() &&
|
||||
!menuBean.isSecretaire() &&
|
||||
!menuBean.isTresorier() &&
|
||||
!menuBean.isResponsableSocial() &&
|
||||
!menuBean.isResponsableEvenements() &&
|
||||
!menuBean.isResponsableCredit() &&
|
||||
!menuBean.isMembreBureau() &&
|
||||
!menuBean.isAdminOrganisation() &&
|
||||
!menuBean.isSuperAdmin();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package dev.lions.unionflow.client.converter;
|
||||
|
||||
import jakarta.faces.component.UIComponent;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.faces.convert.Converter;
|
||||
import jakarta.faces.convert.ConverterException;
|
||||
import jakarta.faces.convert.FacesConverter;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Convertisseur JSF pour les paramètres de vue et champs liés à {@link UUID}.
|
||||
* Permet la conversion String ↔ UUID dans les f:viewParam et composants d'entrée.
|
||||
*/
|
||||
@FacesConverter(value = "uuidConverter", managed = true)
|
||||
public class UuidConverter implements Converter<UUID> {
|
||||
|
||||
@Override
|
||||
public UUID getAsObject(FacesContext context, UIComponent component, String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return UUID.fromString(value.trim());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConverterException("Identifiant invalide : " + value, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsString(FacesContext context, UIComponent component, UUID value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.lions.unionflow.client.exception;
|
||||
|
||||
import jakarta.el.PropertyNotFoundException;
|
||||
import jakarta.faces.FacesException;
|
||||
import jakarta.faces.application.ViewExpiredException;
|
||||
import jakarta.faces.context.ExceptionHandler;
|
||||
@@ -12,28 +13,57 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {
|
||||
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ViewExpiredExceptionHandler.class.getName());
|
||||
private ExceptionHandler wrapped;
|
||||
|
||||
|
||||
public ViewExpiredExceptionHandler(ExceptionHandler wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ExceptionHandler getWrapped() {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isPropertyNotFound(Throwable t) {
|
||||
for (Throwable x = t; x != null; x = x.getCause()) {
|
||||
if (x instanceof PropertyNotFoundException) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws FacesException {
|
||||
Iterator<ExceptionQueuedEvent> iterator = getUnhandledExceptionQueuedEvents().iterator();
|
||||
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ExceptionQueuedEvent event = iterator.next();
|
||||
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
|
||||
Throwable throwable = context.getException();
|
||||
|
||||
|
||||
if (isPropertyNotFound(throwable)) {
|
||||
LOG.log(Level.WARNING, "PropertyNotFoundException EL (évite page d''erreur TreeMap): {0}",
|
||||
throwable.getMessage());
|
||||
try {
|
||||
FacesContext fc = FacesContext.getCurrentInstance();
|
||||
if (fc != null && fc.getExternalContext() != null && !fc.getResponseComplete()) {
|
||||
fc.getExternalContext().redirect(
|
||||
fc.getExternalContext().getRequestContextPath() + "/pages/secure/organisation/liste.xhtml");
|
||||
fc.responseComplete();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = e != null ? e.getMessage() : "";
|
||||
if (msg != null && (msg.contains("already commited") || msg.contains("already committed"))) {
|
||||
LOG.log(Level.WARNING, "Redirection impossible (réponse déjà envoyée): {0}", msg);
|
||||
} else {
|
||||
LOG.log(Level.SEVERE, "Redirection après PropertyNotFoundException: {0}", msg);
|
||||
}
|
||||
}
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (throwable instanceof ViewExpiredException) {
|
||||
ViewExpiredException vee = (ViewExpiredException) throwable;
|
||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
@@ -16,41 +17,17 @@ import java.util.UUID;
|
||||
public interface AssociationService {
|
||||
|
||||
@GET
|
||||
PagedResponseDTO<OrganisationResponse> listerToutes(
|
||||
PagedResponse<OrganisationResponse> listerToutes(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("1000") int size);
|
||||
|
||||
class PagedResponseDTO<T> {
|
||||
public List<T> data;
|
||||
public Long total;
|
||||
public Integer page;
|
||||
public Integer size;
|
||||
public Integer totalPages;
|
||||
|
||||
public List<T> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(List<T> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Long getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(Long total) {
|
||||
this.total = total;
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
OrganisationResponse obtenirParId(@PathParam("id") UUID id);
|
||||
|
||||
@GET
|
||||
@Path("/recherche")
|
||||
PagedResponseDTO<OrganisationResponse> rechercher(
|
||||
PagedResponse<OrganisationResponse> rechercher(
|
||||
@QueryParam("nom") String nom,
|
||||
@QueryParam("type") String type,
|
||||
@QueryParam("statut") String statut,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.evenement.response.EvenementResponse;
|
||||
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
@@ -27,7 +28,7 @@ public interface EvenementService {
|
||||
* Liste tous les événements actifs avec pagination
|
||||
*/
|
||||
@GET
|
||||
Map<String, Object> listerTous(
|
||||
PagedResponse<EvenementResponse> listerTous(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size,
|
||||
@QueryParam("sort") @DefaultValue("dateDebut") String sortField,
|
||||
@@ -66,17 +67,17 @@ public interface EvenementService {
|
||||
*/
|
||||
@GET
|
||||
@Path("/a-venir")
|
||||
Map<String, Object> listerAVenir(
|
||||
PagedResponse<EvenementResponse> listerAVenir(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("10") int size
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Recherche d'événements avec filtres
|
||||
*/
|
||||
@GET
|
||||
@Path("/search")
|
||||
Map<String, Object> rechercher(
|
||||
PagedResponse<EvenementResponse> rechercher(
|
||||
@QueryParam("titre") String titre,
|
||||
@QueryParam("type") String type,
|
||||
@QueryParam("statut") String statut,
|
||||
@@ -85,24 +86,24 @@ public interface EvenementService {
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Liste les événements par statut
|
||||
*/
|
||||
@GET
|
||||
@Path("/statut/{statut}")
|
||||
Map<String, Object> listerParStatut(
|
||||
PagedResponse<EvenementResponse> listerParStatut(
|
||||
@PathParam("statut") String statut,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Liste les événements par association
|
||||
*/
|
||||
@GET
|
||||
@Path("/association/{associationId}")
|
||||
Map<String, Object> listerParAssociation(
|
||||
PagedResponse<EvenementResponse> listerParAssociation(
|
||||
@PathParam("associationId") UUID associationId,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.client.api.dto.MembreDashboardResponse;
|
||||
import dev.lions.unionflow.client.security.AuthHeaderFactory;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@RegisterClientHeaders(AuthHeaderFactory.class)
|
||||
@Path("/api/dashboard/membre")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface MembreDashboardRestClient {
|
||||
|
||||
@GET
|
||||
@Path("/me")
|
||||
MembreDashboardResponse getMonDashboard();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
|
||||
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
@@ -16,7 +17,7 @@ import java.util.UUID;
|
||||
public interface MembreService {
|
||||
|
||||
@GET
|
||||
List<MembreResponse> listerTous();
|
||||
PagedResponse<MembreResponse> listerTous();
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
@@ -26,6 +27,10 @@ public interface MembreService {
|
||||
@Path("/numero/{numeroMembre}")
|
||||
MembreResponse obtenirParNumero(@PathParam("numeroMembre") String numeroMembre);
|
||||
|
||||
@GET
|
||||
@Path("/me")
|
||||
MembreResponse obtenirMembreConnecte();
|
||||
|
||||
@GET
|
||||
@Path("/search")
|
||||
List<MembreResponse> rechercher(
|
||||
|
||||
@@ -13,9 +13,13 @@ import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.finance.request.*;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.finance.response.*;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.AdhesionService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
@@ -109,7 +113,7 @@ public class AdhesionsBean implements Serializable {
|
||||
}
|
||||
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
PagedResponse<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
() -> associationService.listerToutes(0, 1000),
|
||||
"chargement des associations");
|
||||
listeAssociations = (response != null && response.getData() != null) ? response.getData()
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.cotisation.request.CreateCotisationRequest;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.cotisation.response.CotisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.paiement.WaveCheckoutSessionDTO;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.CotisationService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
@@ -304,7 +309,7 @@ public class CotisationsGestionBean implements Serializable {
|
||||
this.filtres = new FiltresCotisations();
|
||||
this.listeOrganisations = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
if (response != null && response.getData() != null) {
|
||||
for (OrganisationResponse assoc : response.getData()) {
|
||||
Organisation org = new Organisation();
|
||||
@@ -340,7 +345,7 @@ public class CotisationsGestionBean implements Serializable {
|
||||
private void chargerTopOrganisations() {
|
||||
this.topOrganisations = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
List<OrganisationResponse> associations = response != null && response.getData() != null ? response.getData()
|
||||
: new ArrayList<>();
|
||||
List<CotisationResponse> cotisationsDTO = cotisationService.listerToutes(0, 1000);
|
||||
|
||||
@@ -8,10 +8,12 @@ import dev.lions.unionflow.server.api.dto.dashboard.DashboardStatsResponse;
|
||||
import dev.lions.unionflow.server.api.dto.dashboard.RecentActivityResponse;
|
||||
import dev.lions.unionflow.server.api.dto.dashboard.UpcomingEventResponse;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
@@ -51,10 +53,13 @@ public class DashboardBean implements Serializable {
|
||||
|
||||
@Inject
|
||||
private UserSession userSession;
|
||||
|
||||
|
||||
@Inject
|
||||
private dev.lions.unionflow.client.bean.MenuBean menuBean;
|
||||
|
||||
@Inject
|
||||
ErrorHandlerService errorHandler;
|
||||
|
||||
|
||||
@Inject
|
||||
RetryService retryService;
|
||||
|
||||
@@ -134,8 +139,30 @@ public class DashboardBean implements Serializable {
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// Charger les données pour les rôles administratifs
|
||||
chargerDonneesBackend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode appelée par f:viewAction pour rediriger les MEMBRE_ACTIF.
|
||||
* S'exécute AVANT le rendu de la page (phase INVOKE_APPLICATION).
|
||||
*/
|
||||
public void checkAccessAndRedirect() {
|
||||
if (menuBean != null && menuBean.isMembreActif() &&
|
||||
!menuBean.isSecretaire() && !menuBean.isTresorier() &&
|
||||
!menuBean.isResponsableSocial() && !menuBean.isResponsableEvenements() &&
|
||||
!menuBean.isAdminOrganisation() && !menuBean.isSuperAdmin()) {
|
||||
try {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
String redirectUrl = ctx.getExternalContext().getRequestContextPath() +
|
||||
"/pages/secure/dashboard-membre.xhtml?faces-redirect=true";
|
||||
ctx.getExternalContext().redirect(redirectUrl);
|
||||
ctx.responseComplete();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Erreur lors de la redirection vers dashboard-membre", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge toutes les données depuis le service Dashboard (DRY/WOU - un seul appel)
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.dashboard.UpcomingEventResponse;
|
||||
import dev.lions.unionflow.server.api.dto.evenement.response.EvenementResponse;
|
||||
import dev.lions.unionflow.client.api.dto.MembreDashboardResponse;
|
||||
import dev.lions.unionflow.client.service.MembreDashboardRestClient;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
import dev.lions.unionflow.client.service.RetryService;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bean de gestion du dashboard personnel pour les membres actifs
|
||||
* (MEMBRE_ACTIF).
|
||||
* Affiche uniquement les données personnelles du membre connecté, pas les
|
||||
* statistiques globales.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-02
|
||||
*/
|
||||
@Named("dashboardMembreBean")
|
||||
@ViewScoped
|
||||
public class DashboardMembreBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOG = Logger.getLogger(DashboardMembreBean.class);
|
||||
|
||||
@Inject
|
||||
SecurityIdentity securityIdentity;
|
||||
|
||||
@Inject
|
||||
ErrorHandlerService errorHandler;
|
||||
|
||||
@Inject
|
||||
RetryService retryService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
MembreDashboardRestClient dashboardClient;
|
||||
|
||||
// Informations personnelles du membre
|
||||
private String prenomMembre;
|
||||
private String nomMembre;
|
||||
private LocalDate dateInscription;
|
||||
|
||||
// KPI personnels - TOUTES LES VALEURS DOIVENT ÊTRE CALCULÉES DEPUIS LES DONNÉES
|
||||
// RÉELLES
|
||||
// IMPORTANT: Ces valeurs par défaut (0, "", null) sont TEMPORAIRES en attendant
|
||||
// l'implémentation des endpoints REST
|
||||
// Une fois les endpoints implémentés, ces valeurs seront REMPLACÉES par les
|
||||
// données calculées depuis PostgreSQL
|
||||
|
||||
// Cotisations
|
||||
private String mesCotisationsPaiement = "0"; // TEMPORAIRE - Sera remplacé par le montant réel depuis API
|
||||
private String statutCotisations = "Non disponible"; // TEMPORAIRE - Sera remplacé par "À jour"/"En retard" depuis
|
||||
// API
|
||||
private Integer tauxCotisationsPerso = null; // null = pas de jauge affichée en attendant les données réelles
|
||||
|
||||
// Épargne
|
||||
private String monSoldeEpargne = "0"; // TEMPORAIRE - Sera remplacé par le solde réel depuis API
|
||||
private String evolutionEpargne = "+0%"; // TEMPORAIRE - Sera remplacé par l'évolution réelle depuis API
|
||||
private String evolutionEpargneNombre = "0"; // TEMPORAIRE - Sera remplacé par l'évolution en FCFA depuis API
|
||||
private Integer objectifEpargne = null; // null = pas de jauge affichée en attendant les données réelles
|
||||
|
||||
// Événements
|
||||
private Integer mesEvenementsInscrits = 0; // TEMPORAIRE - Sera remplacé par le nombre réel depuis API
|
||||
private Integer evenementsAVenir = 0; // TEMPORAIRE - Sera remplacé par le nombre réel depuis API
|
||||
private Integer tauxParticipationPerso = null; // null = pas de jauge affichée en attendant les données réelles
|
||||
|
||||
// Aides
|
||||
private Integer mesDemandesAide = 0; // TEMPORAIRE - Sera remplacé par le nombre réel depuis API
|
||||
private Integer aidesEnCours = 0; // TEMPORAIRE - Sera remplacé par le nombre réel depuis API
|
||||
private Integer tauxAidesApprouvees = null; // null = pas de jauge affichée en attendant les données réelles
|
||||
|
||||
// Collections
|
||||
private List<CotisationPerso> historiqueCotisations = new ArrayList<>();
|
||||
private List<NotificationPerso> mesNotifications = new ArrayList<>();
|
||||
private List<UpcomingEventResponse> evenementsPublics = new ArrayList<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
LOG.info("Initialisation du dashboard personnel membre");
|
||||
chargerDonneesPersonnelles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les données personnelles du membre connecté depuis les endpoints REST.
|
||||
* Les données de synthèse sont récupérées via l'API membre/me.
|
||||
*/
|
||||
private void chargerDonneesPersonnelles() {
|
||||
try {
|
||||
LOG.info("Chargement des données du dashboard depuis l'API...");
|
||||
MembreDashboardResponse data = dashboardClient.getMonDashboard();
|
||||
|
||||
if (data != null) {
|
||||
this.prenomMembre = data.prenom();
|
||||
this.nomMembre = data.nom();
|
||||
this.dateInscription = data.dateInscription();
|
||||
|
||||
this.mesCotisationsPaiement = formatMontant(data.mesCotisationsPaiement());
|
||||
this.statutCotisations = data.statutCotisations() != null ? data.statutCotisations() : "Non disponible";
|
||||
this.tauxCotisationsPerso = data.tauxCotisationsPerso();
|
||||
|
||||
this.monSoldeEpargne = formatMontant(data.monSoldeEpargne());
|
||||
this.evolutionEpargneNombre = formatMontant(data.evolutionEpargneNombre());
|
||||
this.evolutionEpargne = data.evolutionEpargne() != null ? data.evolutionEpargne() : "+0%";
|
||||
this.objectifEpargne = data.objectifEpargne();
|
||||
|
||||
this.mesEvenementsInscrits = data.mesEvenementsInscrits() != null ? data.mesEvenementsInscrits() : 0;
|
||||
this.evenementsAVenir = data.evenementsAVenir() != null ? data.evenementsAVenir() : 0;
|
||||
this.tauxParticipationPerso = data.tauxParticipationPerso();
|
||||
|
||||
this.mesDemandesAide = data.mesDemandesAide() != null ? data.mesDemandesAide() : 0;
|
||||
this.aidesEnCours = data.aidesEnCours() != null ? data.aidesEnCours() : 0;
|
||||
this.tauxAidesApprouvees = data.tauxAidesApprouvees();
|
||||
}
|
||||
|
||||
// Pour l'historique et événements, on mock en attendant les endpoints détaillés
|
||||
// si nécessaires
|
||||
// ou on laissera vide vu que le dashboard principal est fonctionnel avec les
|
||||
// KPI
|
||||
historiqueCotisations = new ArrayList<>();
|
||||
mesNotifications = new ArrayList<>();
|
||||
evenementsPublics = new ArrayList<>();
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors du chargement des données de synthèse du dashboard", e);
|
||||
errorHandler.handleException(e, "lors du chargement de votre dashboard", null);
|
||||
}
|
||||
}
|
||||
|
||||
private String formatMontant(BigDecimal montant) {
|
||||
if (montant == null)
|
||||
return "0";
|
||||
// Format simple, on pourrait rajouter des espaces pour les milliers
|
||||
return String.format("%,d", montant.longValue()).replace(',', ' ');
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Actions
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
public void payerCotisation() {
|
||||
try {
|
||||
// TODO: Rediriger vers la page de paiement des cotisations
|
||||
LOG.info("Redirection vers paiement cotisation");
|
||||
} catch (Exception e) {
|
||||
errorHandler.handleException(e, "lors de la redirection", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void inscrireEvenement() {
|
||||
try {
|
||||
// TODO: Rediriger vers /pages/secure/evenement/calendrier.xhtml
|
||||
// Liste des événements publics où le membre peut s'inscrire
|
||||
LOG.info("Redirection vers calendrier des événements disponibles");
|
||||
} catch (Exception e) {
|
||||
errorHandler.handleException(e, "lors de la redirection", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void demanderAide() {
|
||||
try {
|
||||
// TODO: Rediriger vers le formulaire de demande d'aide
|
||||
LOG.info("Redirection vers demande d'aide");
|
||||
} catch (Exception e) {
|
||||
errorHandler.handleException(e, "lors de la redirection", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void allerAMonProfil() {
|
||||
try {
|
||||
// TODO: Rediriger vers le profil personnel
|
||||
LOG.info("Redirection vers mon profil");
|
||||
} catch (Exception e) {
|
||||
errorHandler.handleException(e, "lors de la redirection", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void allerAuxEvenements() {
|
||||
try {
|
||||
// TODO: Rediriger vers la liste complète des événements
|
||||
LOG.info("Redirection vers liste événements");
|
||||
} catch (Exception e) {
|
||||
errorHandler.handleException(e, "lors de la redirection", null);
|
||||
}
|
||||
}
|
||||
|
||||
public void inscrireAEvenement(String evenementId) {
|
||||
try {
|
||||
// TODO: Appeler API pour inscrire le membre à l'événement
|
||||
LOG.infof("Inscription à l'événement %s", evenementId);
|
||||
errorHandler.showSuccess("Inscription confirmée", "Vous êtes inscrit à cet événement");
|
||||
} catch (Exception e) {
|
||||
errorHandler.handleException(e, "lors de l'inscription à l'événement", null);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Helpers
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
private String extractPrenomFromUsername(String username) {
|
||||
// Extraction basique depuis le username en attendant l'API
|
||||
if (username != null && username.contains("@")) {
|
||||
return username.split("@")[0];
|
||||
}
|
||||
return username != null ? username : "Membre";
|
||||
}
|
||||
|
||||
private String extractNomFromUsername(String username) {
|
||||
// TODO: Appeler GET /api/membres/mon-profil pour récupérer le nom complet
|
||||
return "";
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// DTOs internes
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
public static class CotisationPerso implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LocalDate datePaiement;
|
||||
private LocalDate periode;
|
||||
private String montant;
|
||||
private String modePaiement;
|
||||
private String statut;
|
||||
|
||||
public CotisationPerso(LocalDate datePaiement, LocalDate periode, String montant,
|
||||
String modePaiement, String statut) {
|
||||
this.datePaiement = datePaiement;
|
||||
this.periode = periode;
|
||||
this.montant = montant;
|
||||
this.modePaiement = modePaiement;
|
||||
this.statut = statut;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public LocalDate getDatePaiement() {
|
||||
return datePaiement;
|
||||
}
|
||||
|
||||
public LocalDate getPeriode() {
|
||||
return periode;
|
||||
}
|
||||
|
||||
public String getMontant() {
|
||||
return montant;
|
||||
}
|
||||
|
||||
public String getModePaiement() {
|
||||
return modePaiement;
|
||||
}
|
||||
|
||||
public String getStatut() {
|
||||
return statut;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NotificationPerso implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String icon;
|
||||
private String titre;
|
||||
private String message;
|
||||
private LocalDateTime date;
|
||||
|
||||
public NotificationPerso(String icon, String titre, String message, LocalDateTime date) {
|
||||
this.icon = icon;
|
||||
this.titre = titre;
|
||||
this.message = message;
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getTitre() {
|
||||
return titre;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public LocalDateTime getDate() {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Getters pour JSF
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
public String getPrenomMembre() {
|
||||
return prenomMembre;
|
||||
}
|
||||
|
||||
public String getNomMembre() {
|
||||
return nomMembre;
|
||||
}
|
||||
|
||||
public LocalDate getDateInscription() {
|
||||
return dateInscription;
|
||||
}
|
||||
|
||||
public String getMesCotisationsPaiement() {
|
||||
return mesCotisationsPaiement;
|
||||
}
|
||||
|
||||
public String getStatutCotisations() {
|
||||
return statutCotisations;
|
||||
}
|
||||
|
||||
public Integer getTauxCotisationsPerso() {
|
||||
return tauxCotisationsPerso;
|
||||
}
|
||||
|
||||
public String getMonSoldeEpargne() {
|
||||
return monSoldeEpargne;
|
||||
}
|
||||
|
||||
public String getEvolutionEpargne() {
|
||||
return evolutionEpargne;
|
||||
}
|
||||
|
||||
public String getEvolutionEpargneNombre() {
|
||||
return evolutionEpargneNombre;
|
||||
}
|
||||
|
||||
public Integer getObjectifEpargne() {
|
||||
return objectifEpargne;
|
||||
}
|
||||
|
||||
public Integer getMesEvenementsInscrits() {
|
||||
return mesEvenementsInscrits;
|
||||
}
|
||||
|
||||
public Integer getEvenementsAVenir() {
|
||||
return evenementsAVenir;
|
||||
}
|
||||
|
||||
public Integer getTauxParticipationPerso() {
|
||||
return tauxParticipationPerso;
|
||||
}
|
||||
|
||||
public Integer getMesDemandesAide() {
|
||||
return mesDemandesAide;
|
||||
}
|
||||
|
||||
public Integer getAidesEnCours() {
|
||||
return aidesEnCours;
|
||||
}
|
||||
|
||||
public Integer getTauxAidesApprouvees() {
|
||||
return tauxAidesApprouvees;
|
||||
}
|
||||
|
||||
public List<CotisationPerso> getHistoriqueCotisations() {
|
||||
return historiqueCotisations;
|
||||
}
|
||||
|
||||
public List<NotificationPerso> getMesNotifications() {
|
||||
return mesNotifications;
|
||||
}
|
||||
|
||||
public List<UpcomingEventResponse> getEvenementsPublics() {
|
||||
return evenementsPublics;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ public class DemandesAideBean implements Serializable {
|
||||
|
||||
try {
|
||||
// Charger toutes les demandes depuis le backend pour calculer les étapes
|
||||
List<DemandeAideResponse> demandesDTO = demandeAideService.listerToutes(0, 10000);
|
||||
List<DemandeAideResponse> demandesDTO = demandeAideService.listerToutes(0, 1000);
|
||||
|
||||
// Calculer le nombre de demandes par statut depuis les données réelles
|
||||
long enAttenteCount = demandesDTO.stream().filter(d -> StatutAide.EN_ATTENTE.equals(d.getStatut())).count();
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DemandesBean implements Serializable {
|
||||
private void initializeDemandes() {
|
||||
demandes = new ArrayList<>();
|
||||
try {
|
||||
List<DemandeAideResponse> dtos = demandeAideService.listerToutes(0, 10000);
|
||||
List<DemandeAideResponse> dtos = demandeAideService.listerToutes(0, 1000);
|
||||
if (dtos != null) {
|
||||
for (DemandeAideResponse dto : dtos) {
|
||||
demandes.add(mapToDemande(dto));
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.abonnement.response.AbonnementResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.CotisationService;
|
||||
@@ -105,7 +107,7 @@ public class EntitesGestionBean implements Serializable {
|
||||
private void initializeStatistiques() {
|
||||
statistiques = new Statistiques();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
List<OrganisationResponse> associations = new ArrayList<>();
|
||||
if (response != null && response.getData() != null) {
|
||||
associations = response.getData();
|
||||
@@ -138,7 +140,7 @@ public class EntitesGestionBean implements Serializable {
|
||||
private void initializeEntites() {
|
||||
toutesLesEntites = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
if (response != null && response.getData() != null) {
|
||||
for (OrganisationResponse dto : response.getData()) {
|
||||
Entite entite = convertToEntite(dto);
|
||||
|
||||
@@ -114,44 +114,16 @@ public class EvenementsBean implements Serializable {
|
||||
public void chargerEvenements() {
|
||||
try {
|
||||
LOG.info("Chargement des événements depuis le backend");
|
||||
Map<String, Object> response = retryService.executeWithRetrySupplier(
|
||||
var response = retryService.executeWithRetrySupplier(
|
||||
() -> evenementService.listerTous(0, 1000, "dateDebut", "asc"),
|
||||
"chargement de tous les événements"
|
||||
);
|
||||
|
||||
|
||||
tousLesEvenements = new ArrayList<>();
|
||||
|
||||
// Le backend peut retourner soit une liste de DTOs, soit une Map avec "data"
|
||||
if (response.containsKey("data")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> data = (List<Object>) response.get("data");
|
||||
|
||||
if (data != null) {
|
||||
for (Object item : data) {
|
||||
if (item instanceof EvenementResponse) {
|
||||
tousLesEvenements.add((EvenementResponse) item);
|
||||
} else if (item instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
EvenementResponse dto = convertMapToDTO((Map<String, Object>) item);
|
||||
tousLesEvenements.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Si la réponse est directement une liste
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> data = (List<Object>) response.get("evenements");
|
||||
if (data != null) {
|
||||
for (Object item : data) {
|
||||
if (item instanceof EvenementResponse) {
|
||||
tousLesEvenements.add((EvenementResponse) item);
|
||||
} else if (item instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
EvenementResponse dto = convertMapToDTO((Map<String, Object>) item);
|
||||
tousLesEvenements.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer les données depuis PagedResponse
|
||||
if (response != null && response.getData() != null) {
|
||||
tousLesEvenements.addAll(response.getData());
|
||||
}
|
||||
|
||||
appliquerFiltres();
|
||||
@@ -170,22 +142,17 @@ public class EvenementsBean implements Serializable {
|
||||
public void chargerEvenementsProchains() {
|
||||
try {
|
||||
LOG.info("Chargement des événements à venir");
|
||||
Map<String, Object> response = retryService.executeWithRetrySupplier(
|
||||
var response = retryService.executeWithRetrySupplier(
|
||||
() -> evenementService.listerAVenir(0, 6),
|
||||
"chargement des événements à venir"
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> data = (List<Map<String, Object>>) response.get("data");
|
||||
|
||||
if (data != null) {
|
||||
evenementsProchains = data.stream()
|
||||
.map(this::convertMapToDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (response != null && response.getData() != null) {
|
||||
evenementsProchains = new ArrayList<>(response.getData());
|
||||
} else {
|
||||
evenementsProchains = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors du chargement des événements à venir");
|
||||
evenementsProchains = new ArrayList<>();
|
||||
|
||||
@@ -45,20 +45,23 @@ public class MembreCotisationBean implements Serializable {
|
||||
@Inject
|
||||
@RestClient
|
||||
private MembreService membreService;
|
||||
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private CotisationService cotisationService;
|
||||
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private ExportClientService exportService;
|
||||
|
||||
|
||||
@Inject
|
||||
ErrorHandlerService errorHandler;
|
||||
|
||||
|
||||
@Inject
|
||||
RetryService retryService;
|
||||
|
||||
@Inject
|
||||
io.quarkus.security.identity.SecurityIdentity securityIdentity;
|
||||
|
||||
// ID du membre (depuis viewParam)
|
||||
private UUID membreId;
|
||||
@@ -135,14 +138,43 @@ public class MembreCotisationBean implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Si toujours null, auto-détecter le membre connecté (Pattern DRY depuis DashboardMembreBean)
|
||||
if (membreId == null) {
|
||||
try {
|
||||
String username = securityIdentity.getPrincipal().getName();
|
||||
LOG.infof("Auto-détection du membre connecté: %s", username);
|
||||
|
||||
// Récupérer directement le membre connecté via l'endpoint /me
|
||||
MembreResponse membreConnecte = retryService.executeWithRetrySupplier(
|
||||
() -> membreService.obtenirMembreConnecte(),
|
||||
"récupération du membre connecté"
|
||||
);
|
||||
|
||||
if (membreConnecte != null) {
|
||||
membreId = membreConnecte.getId();
|
||||
numeroMembre = membreConnecte.getNumeroMembre();
|
||||
LOG.infof("Membre connecté détecté: %s (%s)", numeroMembre, membreId);
|
||||
} else {
|
||||
LOG.warnf("Aucun membre trouvé pour l'utilisateur: %s", username);
|
||||
errorHandler.showWarning("Attention",
|
||||
"Impossible de charger vos cotisations. Veuillez contacter l'administrateur.");
|
||||
initialiserDonneesVides();
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de l'auto-détection du membre connecté");
|
||||
errorHandler.handleException(e, "lors du chargement de vos cotisations", null);
|
||||
initialiserDonneesVides();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (membreId != null) {
|
||||
chargerMembre();
|
||||
chargerCotisations();
|
||||
calculerStatistiques();
|
||||
} else {
|
||||
LOG.warn("Aucun membreId fourni, impossible de charger les cotisations");
|
||||
errorHandler.showWarning("Attention", "Aucun membre sélectionné");
|
||||
initialiserDonneesVides();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
import dev.lions.unionflow.client.service.RetryService;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.request.*;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.*;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
@@ -88,7 +91,7 @@ public class MembreExportBean implements Serializable {
|
||||
private void chargerOrganisations() {
|
||||
organisationsDisponibles = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
PagedResponse<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
() -> associationService.listerToutes(0, 1000),
|
||||
"chargement des organisations pour export");
|
||||
List<OrganisationResponse> associations = (response != null && response.getData() != null) ? response.getData()
|
||||
|
||||
@@ -6,8 +6,11 @@ import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
import dev.lions.unionflow.client.service.RetryService;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.request.*;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.*;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
@@ -71,7 +74,7 @@ public class MembreImportBean implements Serializable {
|
||||
private void chargerOrganisations() {
|
||||
organisationsDisponibles = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
PagedResponse<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
() -> associationService.listerToutes(0, 1000),
|
||||
"chargement des organisations pour import");
|
||||
List<OrganisationResponse> associations = (response != null && response.getData() != null) ? response.getData()
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
@@ -120,7 +122,7 @@ public class MembreInscriptionBean implements Serializable {
|
||||
|
||||
// Charger les organisations actives (DRY/WOU - utilise AssociationService)
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
PagedResponse<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
() -> associationService.listerToutes(0, 1000),
|
||||
"chargement des associations");
|
||||
organisationsDisponibles = (response != null && response.getData() != null) ? response.getData()
|
||||
|
||||
@@ -53,7 +53,7 @@ public class MembreLazyDataModel extends LazyDataModelBase<MembreSummaryResponse
|
||||
|
||||
// Sans critère, l'endpoint /search/advanced refuse la requête (HTTP 400)
|
||||
if (!searchCriteria.hasAnyCriteria()) {
|
||||
List<MembreResponse> all = membreService.listerTous();
|
||||
List<MembreResponse> all = membreService.listerTous().getData();
|
||||
if (all == null || all.isEmpty()) return List.of();
|
||||
int toIndex = Math.min(first + pageSize, all.size());
|
||||
// Conversion MembreResponse → MembreSummaryResponse
|
||||
@@ -71,7 +71,9 @@ public class MembreLazyDataModel extends LazyDataModelBase<MembreSummaryResponse
|
||||
m.getStatutCompteLibelle(),
|
||||
m.getStatutCompteSeverity(),
|
||||
"ACTIF".equals(m.getStatutCompte()), // actif
|
||||
m.getRoles()))
|
||||
m.getRoles(),
|
||||
m.getOrganisationId(),
|
||||
m.getAssociationNom()))
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -106,7 +108,7 @@ public class MembreLazyDataModel extends LazyDataModelBase<MembreSummaryResponse
|
||||
|
||||
// Sans critère, compter via listerTous()
|
||||
if (!searchCriteria.hasAnyCriteria()) {
|
||||
List<MembreResponse> all = membreService.listerTous();
|
||||
List<MembreResponse> all = membreService.listerTous().getData();
|
||||
return all != null ? all.size() : 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.NotificationService;
|
||||
@@ -8,7 +9,9 @@ import dev.lions.unionflow.client.service.CotisationService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
import dev.lions.unionflow.client.service.RetryService;
|
||||
import dev.lions.unionflow.server.api.dto.membre.MembreSearchCriteria;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -108,6 +111,8 @@ public class MembreListeBean implements Serializable {
|
||||
// === Contact membre ===
|
||||
|
||||
private MembreResponse membreAContacter;
|
||||
/** Membre en attente de confirmation de suspension (flux explicite). */
|
||||
private MembreResponse membrePourSuspension;
|
||||
private String messageContact;
|
||||
private String sujetContact;
|
||||
private boolean dialogContactVisible = false;
|
||||
@@ -198,7 +203,7 @@ public class MembreListeBean implements Serializable {
|
||||
private void chargerOrganisations() {
|
||||
organisationsDisponibles = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
PagedResponse<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
() -> associationService.listerToutes(0, 1000),
|
||||
"chargement des organisations");
|
||||
if (response != null && response.getData() != null) {
|
||||
@@ -396,6 +401,25 @@ public class MembreListeBean implements Serializable {
|
||||
// ACTIONS SUR UN MEMBRE
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Prépare la suspension (ouvre le dialogue de confirmation).
|
||||
*/
|
||||
public void preparerSuspendre(MembreResponse membre) {
|
||||
this.membrePourSuspension = membre;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirme et exécute la suspension après clic sur « Oui » dans le dialogue.
|
||||
*/
|
||||
public void confirmerSuspendre() {
|
||||
if (membrePourSuspension == null) {
|
||||
return;
|
||||
}
|
||||
MembreResponse m = membrePourSuspension;
|
||||
membrePourSuspension = null;
|
||||
suspendreMembre(m);
|
||||
}
|
||||
|
||||
public void suspendreMembre(MembreResponse membre) {
|
||||
try {
|
||||
retryService.executeWithRetrySupplier(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
@@ -67,7 +68,7 @@ public class MembreRechercheBean implements Serializable {
|
||||
private void initializeStatistiques() {
|
||||
statistiques = new Statistiques();
|
||||
try {
|
||||
List<MembreResponse> membres = membreService.listerTous();
|
||||
List<MembreResponse> membres = membreService.listerTous().getData();
|
||||
statistiques.setTotalMembres(membres.size());
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors du calcul des statistiques");
|
||||
@@ -83,7 +84,7 @@ public class MembreRechercheBean implements Serializable {
|
||||
selectedMembres = new ArrayList<>();
|
||||
|
||||
try {
|
||||
List<MembreResponse> membresDTO = membreService.listerTous();
|
||||
List<MembreResponse> membresDTO = membreService.listerTous().getData();
|
||||
for (MembreResponse dto : membresDTO) {
|
||||
Membre membre = convertToMembre(dto);
|
||||
tousLesMembres.add(membre);
|
||||
@@ -118,7 +119,7 @@ public class MembreRechercheBean implements Serializable {
|
||||
private void initializeEntites() {
|
||||
entitesDisponibles = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse> response = associationService
|
||||
PagedResponse<dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse> response = associationService
|
||||
.listerToutes(0, 1000);
|
||||
if (response != null && response.getData() != null) {
|
||||
for (dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse assoc : response.getData()) {
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.cotisation.response.CotisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
|
||||
import dev.lions.unionflow.server.api.dto.paiement.response.PaiementResponse;
|
||||
import dev.lions.unionflow.client.service.CotisationService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
import dev.lions.unionflow.client.service.ExportClientService;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
import dev.lions.unionflow.client.service.RetryService;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.context.ExternalContext;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Bean pour le paiement des cotisations du membre connecté (MEMBRE_ACTIF).
|
||||
* Affiche uniquement les cotisations personnelles, pas les données admin.
|
||||
*
|
||||
* Pattern DRY: Réutilise la logique de MembreCotisationBean et DashboardMembreBean
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2026-03-02
|
||||
*/
|
||||
@Named("mesCotisationsPaiementBean")
|
||||
@ViewScoped
|
||||
public class MesCotisationsPaiementBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOG = Logger.getLogger(MesCotisationsPaiementBean.class);
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
|
||||
|
||||
@Inject
|
||||
SecurityIdentity securityIdentity;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private MembreService membreService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private CotisationService cotisationService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private ExportClientService exportService;
|
||||
|
||||
@Inject
|
||||
ErrorHandlerService errorHandler;
|
||||
|
||||
@Inject
|
||||
RetryService retryService;
|
||||
|
||||
// Informations du membre connecté
|
||||
private UUID membreId;
|
||||
private String numeroMembre;
|
||||
private MembreResponse membre;
|
||||
|
||||
// KPI personnels - Cotisations à payer
|
||||
private Integer cotisationsEnAttente = 0;
|
||||
private String montantDu = "0 FCFA";
|
||||
private String prochaineEcheance = "-";
|
||||
private String totalPaye = "0 FCFA";
|
||||
private Integer anneeEnCours = LocalDate.now().getYear();
|
||||
|
||||
// Listes
|
||||
private List<CotisationPerso> mesCotisationsEnAttente = new ArrayList<>();
|
||||
private List<PaiementPerso> derniersPaiements = new ArrayList<>();
|
||||
|
||||
// Formulaires dialogs
|
||||
// Dialog Paiement en Ligne
|
||||
private UUID cotisationSelectionneeId;
|
||||
private String methodePaiementChoisie = "WAVE";
|
||||
private String numeroTelephone;
|
||||
|
||||
// Dialog Paiement Manuel
|
||||
private String methodePaiementManuel = "ESPECES";
|
||||
private String referencePaiementManuel;
|
||||
private String commentairePaiement;
|
||||
|
||||
// Configuration organisation (TODO: charger depuis API)
|
||||
private boolean paiementManuelActive = true;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
LOG.info("Initialisation du bean de paiement des cotisations personnelles");
|
||||
detecterMembreConnecte();
|
||||
if (membreId != null) {
|
||||
chargerDonnees();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-détection du membre connecté (Pattern DRY depuis DashboardMembreBean)
|
||||
*/
|
||||
private void detecterMembreConnecte() {
|
||||
try {
|
||||
String username = securityIdentity.getPrincipal().getName();
|
||||
LOG.infof("Auto-détection du membre connecté: %s", username);
|
||||
|
||||
// Récupérer directement le membre connecté via l'endpoint /me
|
||||
membre = retryService.executeWithRetrySupplier(
|
||||
() -> membreService.obtenirMembreConnecte(),
|
||||
"récupération du membre connecté"
|
||||
);
|
||||
|
||||
if (membre != null) {
|
||||
membreId = membre.getId();
|
||||
numeroMembre = membre.getNumeroMembre();
|
||||
LOG.infof("Membre connecté détecté: %s (%s)", numeroMembre, membreId);
|
||||
} else {
|
||||
LOG.warnf("Aucun membre trouvé pour l'utilisateur: %s", username);
|
||||
errorHandler.showWarning("Attention",
|
||||
"Impossible de charger vos cotisations. Veuillez contacter l'administrateur.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de l'auto-détection du membre connecté");
|
||||
errorHandler.handleException(e, "lors du chargement de vos cotisations", null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge toutes les données personnelles de cotisations et paiements
|
||||
*/
|
||||
private void chargerDonnees() {
|
||||
chargerCotisationsEnAttente();
|
||||
chargerDerniersPaiements();
|
||||
calculerKPI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les cotisations en attente du membre connecté
|
||||
* Pattern DRY: Réutilise la logique de MembreCotisationBean.chargerCotisations()
|
||||
*/
|
||||
private void chargerCotisationsEnAttente() {
|
||||
try {
|
||||
// TODO: Créer endpoint GET /api/cotisations/mes-cotisations/en-attente
|
||||
// Pour l'instant, utiliser l'endpoint existant avec filtre statut
|
||||
List<CotisationResponse> cotisationsDTO = retryService.executeWithRetrySupplier(
|
||||
() -> cotisationService.rechercher(
|
||||
membreId,
|
||||
"EN_ATTENTE", // Statut
|
||||
null, // Type
|
||||
anneeEnCours,
|
||||
null, // Mois
|
||||
0,
|
||||
100
|
||||
),
|
||||
"chargement des cotisations en attente"
|
||||
);
|
||||
|
||||
mesCotisationsEnAttente = new ArrayList<>();
|
||||
for (CotisationResponse dto : cotisationsDTO) {
|
||||
CotisationPerso cotisation = new CotisationPerso();
|
||||
cotisation.setId(dto.getId());
|
||||
cotisation.setReference(dto.getNumeroReference() != null ? dto.getNumeroReference() : "");
|
||||
cotisation.setType(dto.getTypeCotisation() != null ? dto.getTypeCotisation() : "MENSUELLE");
|
||||
cotisation.setPeriode(formaterPeriode(dto.getDateEcheance()));
|
||||
cotisation.setMontantDu(dto.getMontantDu() != null ? dto.getMontantDu() : BigDecimal.ZERO);
|
||||
cotisation.setDateEcheance(dto.getDateEcheance());
|
||||
mesCotisationsEnAttente.add(cotisation);
|
||||
}
|
||||
|
||||
LOG.infof("Cotisations en attente chargées: %d", mesCotisationsEnAttente.size());
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors du chargement des cotisations en attente");
|
||||
errorHandler.handleException(e, "lors du chargement de vos cotisations en attente", null);
|
||||
mesCotisationsEnAttente = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les 5 derniers paiements du membre connecté
|
||||
*/
|
||||
private void chargerDerniersPaiements() {
|
||||
try {
|
||||
// TODO: Créer endpoint GET /api/paiements/mes-paiements/historique?limit=5
|
||||
// Pour l'instant, charger toutes les cotisations payées et prendre les 5 dernières
|
||||
List<CotisationResponse> cotisationsPayees = retryService.executeWithRetrySupplier(
|
||||
() -> cotisationService.rechercher(
|
||||
membreId,
|
||||
"PAYEE", // Statut
|
||||
null, // Type
|
||||
null, // Année
|
||||
null, // Mois
|
||||
0,
|
||||
5
|
||||
),
|
||||
"chargement de l'historique des paiements"
|
||||
);
|
||||
|
||||
derniersPaiements = new ArrayList<>();
|
||||
for (CotisationResponse dto : cotisationsPayees) {
|
||||
PaiementPerso paiement = new PaiementPerso();
|
||||
paiement.setId(dto.getId());
|
||||
paiement.setReference(dto.getNumeroReference() != null ? dto.getNumeroReference() : "");
|
||||
paiement.setPeriode(formaterPeriode(dto.getDateEcheance()));
|
||||
paiement.setMontant(dto.getMontantDu() != null ? dto.getMontantDu() : BigDecimal.ZERO);
|
||||
if (dto.getDatePaiement() != null) {
|
||||
paiement.setDatePaiement(dto.getDatePaiement().toLocalDate());
|
||||
}
|
||||
// Note: methodePaiement non disponible dans CotisationResponse
|
||||
paiement.setMethodePaiement("Non renseignée");
|
||||
derniersPaiements.add(paiement);
|
||||
}
|
||||
|
||||
LOG.infof("Derniers paiements chargés: %d", derniersPaiements.size());
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors du chargement des derniers paiements");
|
||||
errorHandler.handleException(e, "lors du chargement de votre historique", null);
|
||||
derniersPaiements = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule les KPI personnels depuis les données chargées
|
||||
*/
|
||||
private void calculerKPI() {
|
||||
// Cotisations en attente
|
||||
cotisationsEnAttente = mesCotisationsEnAttente.size();
|
||||
|
||||
// Montant dû total
|
||||
BigDecimal montantTotal = mesCotisationsEnAttente.stream()
|
||||
.map(CotisationPerso::getMontantDu)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
montantDu = formaterMontant(montantTotal);
|
||||
|
||||
// Prochaine échéance
|
||||
if (!mesCotisationsEnAttente.isEmpty()) {
|
||||
LocalDate prochaine = mesCotisationsEnAttente.stream()
|
||||
.map(CotisationPerso::getDateEcheance)
|
||||
.filter(d -> d != null)
|
||||
.min(LocalDate::compareTo)
|
||||
.orElse(null);
|
||||
prochaineEcheance = prochaine != null ? prochaine.format(DATE_FORMATTER) : "-";
|
||||
} else {
|
||||
prochaineEcheance = "Aucune";
|
||||
}
|
||||
|
||||
// Total payé cette année
|
||||
BigDecimal totalPayeAnnee = derniersPaiements.stream()
|
||||
.filter(p -> p.getDatePaiement() != null && p.getDatePaiement().getYear() == anneeEnCours)
|
||||
.map(PaiementPerso::getMontant)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
totalPaye = formaterMontant(totalPayeAnnee);
|
||||
|
||||
LOG.infof("KPI calculés: %d cotisations en attente, %s à payer", cotisationsEnAttente, montantDu);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Actions
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* Initie un paiement en ligne (Wave, Orange, Free Money, Carte)
|
||||
*/
|
||||
public void initierPaiementEnLigne() {
|
||||
if (cotisationSelectionneeId == null) {
|
||||
errorHandler.showWarning("Attention", "Veuillez sélectionner une cotisation à payer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (numeroTelephone == null || numeroTelephone.trim().isEmpty()) {
|
||||
errorHandler.showWarning("Attention", "Veuillez saisir votre numéro de téléphone");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: Créer endpoint POST /api/paiements/initier-paiement-en-ligne
|
||||
// Body: { cotisationId, methodePaiement, numeroTelephone }
|
||||
// Retour: { redirectUrl, transactionId }
|
||||
LOG.infof("Paiement en ligne initié: cotisation=%s, méthode=%s, téléphone=%s",
|
||||
cotisationSelectionneeId, methodePaiementChoisie, numeroTelephone);
|
||||
|
||||
errorHandler.showInfo("Paiement en ligne",
|
||||
"Redirection vers le gateway de paiement " + methodePaiementChoisie + "...");
|
||||
|
||||
// TODO: Rediriger vers l'URL du gateway de paiement
|
||||
// ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
|
||||
// ec.redirect(paymentGatewayUrl);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de l'initiation du paiement en ligne");
|
||||
errorHandler.handleException(e, "lors de l'initiation du paiement", null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Déclare un paiement manuel (espèces, virement, chèque)
|
||||
* Statut: EN_ATTENTE_VALIDATION (le trésorier doit valider)
|
||||
*/
|
||||
public void declarerPaiementManuel() {
|
||||
if (cotisationSelectionneeId == null) {
|
||||
errorHandler.showWarning("Attention", "Veuillez sélectionner une cotisation");
|
||||
return;
|
||||
}
|
||||
|
||||
if (methodePaiementManuel == null || methodePaiementManuel.trim().isEmpty()) {
|
||||
errorHandler.showWarning("Attention", "Veuillez sélectionner une méthode de paiement");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: Créer endpoint POST /api/paiements/declarer-paiement-manuel
|
||||
// Body: { cotisationId, methodePaiement, reference, commentaire }
|
||||
// Retour: 201 Created
|
||||
LOG.infof("Paiement manuel déclaré: cotisation=%s, méthode=%s, ref=%s",
|
||||
cotisationSelectionneeId, methodePaiementManuel, referencePaiementManuel);
|
||||
|
||||
errorHandler.showSuccess("Paiement déclaré",
|
||||
"Votre paiement a été enregistré. Il sera validé par le trésorier.");
|
||||
|
||||
// Recharger les données
|
||||
chargerDonnees();
|
||||
|
||||
// Réinitialiser le formulaire
|
||||
cotisationSelectionneeId = null;
|
||||
methodePaiementManuel = "ESPECES";
|
||||
referencePaiementManuel = null;
|
||||
commentairePaiement = null;
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de la déclaration du paiement manuel");
|
||||
errorHandler.handleException(e, "lors de la déclaration du paiement", null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Télécharge le reçu PDF d'un paiement
|
||||
*/
|
||||
public void telechargerRecu(UUID paiementId) {
|
||||
if (paiementId == null) {
|
||||
errorHandler.showWarning("Attention", "Impossible de télécharger le reçu");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: Créer endpoint GET /api/paiements/telecharger-recu/{id}
|
||||
byte[] recu = retryService.executeWithRetrySupplier(
|
||||
() -> exportService.genererRecu(paiementId),
|
||||
"génération d'un reçu"
|
||||
);
|
||||
|
||||
String nomFichier = "recu-" + paiementId + ".pdf";
|
||||
telechargerFichier(recu, nomFichier, "application/pdf");
|
||||
|
||||
errorHandler.showSuccess("Reçu téléchargé", "Le reçu a été téléchargé avec succès");
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors du téléchargement du reçu");
|
||||
errorHandler.handleException(e, "lors du téléchargement du reçu", null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouvre le dialog de paiement en ligne pour une cotisation
|
||||
*/
|
||||
public void ouvrirDialogPaiementEnLigne(UUID cotisationId) {
|
||||
this.cotisationSelectionneeId = cotisationId;
|
||||
this.numeroTelephone = null;
|
||||
this.methodePaiementChoisie = "WAVE";
|
||||
LOG.infof("Dialog paiement en ligne ouvert pour cotisation: %s", cotisationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouvre le dialog de paiement manuel pour une cotisation
|
||||
*/
|
||||
public void ouvrirDialogPaiementManuel(UUID cotisationId) {
|
||||
this.cotisationSelectionneeId = cotisationId;
|
||||
this.methodePaiementManuel = "ESPECES";
|
||||
this.referencePaiementManuel = null;
|
||||
this.commentairePaiement = null;
|
||||
LOG.infof("Dialog paiement manuel ouvert pour cotisation: %s", cotisationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualise les données
|
||||
*/
|
||||
public void actualiser() {
|
||||
LOG.info("Actualisation des données de paiement");
|
||||
chargerDonnees();
|
||||
errorHandler.showSuccess("Actualisation", "Les données ont été actualisées");
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Helpers
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
private String formaterPeriode(LocalDate dateEcheance) {
|
||||
if (dateEcheance == null) {
|
||||
return "";
|
||||
}
|
||||
String[] moisNoms = {"Janvier", "Février", "Mars", "Avril", "Mai", "Juin",
|
||||
"Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"};
|
||||
int mois = dateEcheance.getMonthValue();
|
||||
int annee = dateEcheance.getYear();
|
||||
return moisNoms[mois - 1] + " " + annee;
|
||||
}
|
||||
|
||||
private String formaterMontant(BigDecimal montant) {
|
||||
if (montant == null) {
|
||||
return "0 FCFA";
|
||||
}
|
||||
return String.format("%,.0f FCFA", montant);
|
||||
}
|
||||
|
||||
private void telechargerFichier(byte[] data, String nomFichier, String contentType) {
|
||||
try {
|
||||
jakarta.faces.context.FacesContext fc = jakarta.faces.context.FacesContext.getCurrentInstance();
|
||||
ExternalContext ec = fc.getExternalContext();
|
||||
ec.responseReset();
|
||||
ec.setResponseContentType(contentType + "; charset=UTF-8");
|
||||
ec.setResponseContentLength(data.length);
|
||||
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + nomFichier + "\"");
|
||||
OutputStream output = ec.getResponseOutputStream();
|
||||
output.write(data);
|
||||
output.flush();
|
||||
fc.responseComplete();
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur téléchargement fichier");
|
||||
throw new RuntimeException("Erreur lors du téléchargement", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// Getters / Setters
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
public UUID getMembreId() { return membreId; }
|
||||
public String getNumeroMembre() { return numeroMembre; }
|
||||
public MembreResponse getMembre() { return membre; }
|
||||
|
||||
public Integer getCotisationsEnAttente() { return cotisationsEnAttente; }
|
||||
public String getMontantDu() { return montantDu; }
|
||||
public String getProchaineEcheance() { return prochaineEcheance; }
|
||||
public String getTotalPaye() { return totalPaye; }
|
||||
public Integer getAnneeEnCours() { return anneeEnCours; }
|
||||
|
||||
public List<CotisationPerso> getMesCotisationsEnAttente() { return mesCotisationsEnAttente; }
|
||||
public List<PaiementPerso> getDerniersPaiements() { return derniersPaiements; }
|
||||
|
||||
public UUID getCotisationSelectionneeId() { return cotisationSelectionneeId; }
|
||||
public void setCotisationSelectionneeId(UUID cotisationSelectionneeId) { this.cotisationSelectionneeId = cotisationSelectionneeId; }
|
||||
|
||||
public String getMethodePaiementChoisie() { return methodePaiementChoisie; }
|
||||
public void setMethodePaiementChoisie(String methodePaiementChoisie) { this.methodePaiementChoisie = methodePaiementChoisie; }
|
||||
|
||||
public String getNumeroTelephone() { return numeroTelephone; }
|
||||
public void setNumeroTelephone(String numeroTelephone) { this.numeroTelephone = numeroTelephone; }
|
||||
|
||||
public String getMethodePaiementManuel() { return methodePaiementManuel; }
|
||||
public void setMethodePaiementManuel(String methodePaiementManuel) { this.methodePaiementManuel = methodePaiementManuel; }
|
||||
|
||||
public String getReferencePaiementManuel() { return referencePaiementManuel; }
|
||||
public void setReferencePaiementManuel(String referencePaiementManuel) { this.referencePaiementManuel = referencePaiementManuel; }
|
||||
|
||||
public String getCommentairePaiement() { return commentairePaiement; }
|
||||
public void setCommentairePaiement(String commentairePaiement) { this.commentairePaiement = commentairePaiement; }
|
||||
|
||||
public boolean isPaiementManuelActive() { return paiementManuelActive; }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// DTOs internes
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
public static class CotisationPerso implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private UUID id;
|
||||
private String reference;
|
||||
private String type;
|
||||
private String periode;
|
||||
private BigDecimal montantDu;
|
||||
private LocalDate dateEcheance;
|
||||
|
||||
// Getters / Setters
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
public String getReference() { return reference; }
|
||||
public void setReference(String reference) { this.reference = reference; }
|
||||
|
||||
public String getType() { return type; }
|
||||
public void setType(String type) { this.type = type; }
|
||||
|
||||
public String getPeriode() { return periode; }
|
||||
public void setPeriode(String periode) { this.periode = periode; }
|
||||
|
||||
public BigDecimal getMontantDu() { return montantDu; }
|
||||
public void setMontantDu(BigDecimal montantDu) { this.montantDu = montantDu; }
|
||||
|
||||
public LocalDate getDateEcheance() { return dateEcheance; }
|
||||
public void setDateEcheance(LocalDate dateEcheance) { this.dateEcheance = dateEcheance; }
|
||||
|
||||
// Méthodes dérivées pour l'affichage
|
||||
public String getTypeSeverity() {
|
||||
return switch (type) {
|
||||
case "MENSUELLE" -> "info";
|
||||
case "SPECIALE" -> "warning";
|
||||
case "ADHESION" -> "success";
|
||||
default -> "secondary";
|
||||
};
|
||||
}
|
||||
|
||||
public String getTypeIcon() {
|
||||
return switch (type) {
|
||||
case "MENSUELLE" -> "pi-calendar";
|
||||
case "SPECIALE" -> "pi-star";
|
||||
case "ADHESION" -> "pi-user-plus";
|
||||
default -> "pi-circle";
|
||||
};
|
||||
}
|
||||
|
||||
public String getMontantDuFormatte() {
|
||||
return montantDu != null ? String.format("%,.0f FCFA", montantDu) : "0 FCFA";
|
||||
}
|
||||
|
||||
public String getDateEcheanceFormattee() {
|
||||
return dateEcheance != null ? dateEcheance.format(DATE_FORMATTER) : "-";
|
||||
}
|
||||
}
|
||||
|
||||
public static class PaiementPerso implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private UUID id;
|
||||
private String reference;
|
||||
private String periode;
|
||||
private BigDecimal montant;
|
||||
private LocalDate datePaiement;
|
||||
private String methodePaiement;
|
||||
|
||||
// Getters / Setters
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
public String getReference() { return reference; }
|
||||
public void setReference(String reference) { this.reference = reference; }
|
||||
|
||||
public String getPeriode() { return periode; }
|
||||
public void setPeriode(String periode) { this.periode = periode; }
|
||||
|
||||
public BigDecimal getMontant() { return montant; }
|
||||
public void setMontant(BigDecimal montant) { this.montant = montant; }
|
||||
|
||||
public LocalDate getDatePaiement() { return datePaiement; }
|
||||
public void setDatePaiement(LocalDate datePaiement) { this.datePaiement = datePaiement; }
|
||||
|
||||
public String getMethodePaiement() { return methodePaiement; }
|
||||
public void setMethodePaiement(String methodePaiement) { this.methodePaiement = methodePaiement; }
|
||||
|
||||
// Méthodes dérivées pour l'affichage
|
||||
public String getMontantFormatte() {
|
||||
return montant != null ? String.format("%,.0f FCFA", montant) : "0 FCFA";
|
||||
}
|
||||
|
||||
public String getDatePaiementFormattee() {
|
||||
return datePaiement != null ? datePaiement.format(DATE_FORMATTER) : "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
import dev.lions.unionflow.client.service.RestClientExceptionMapper;
|
||||
@@ -296,7 +297,7 @@ public class OrganisationDetailBean implements Serializable {
|
||||
public List<OrganisationResponse> rechercherOrganisations(String query) {
|
||||
if (query == null || query.trim().isEmpty()) return List.of();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response =
|
||||
PagedResponse<OrganisationResponse> response =
|
||||
associationService.rechercher(query, null, null, null, null, 0, 100);
|
||||
return (response != null && response.getData() != null) ? response.getData() : List.of();
|
||||
} catch (Exception e) {
|
||||
@@ -322,6 +323,17 @@ public class OrganisationDetailBean implements Serializable {
|
||||
return organisation.getTypeOrganisationLibelle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias pour la vue (detail.xhtml) : libellé du type d'organisation.
|
||||
* Délègue à typeLibelle du DTO si présent, sinon typeOrganisationLibelle.
|
||||
*/
|
||||
public String getTypeLibelle() {
|
||||
if (organisation == null) return "";
|
||||
String libelle = organisation.getTypeLibelle();
|
||||
if (libelle != null && !libelle.isBlank()) return libelle;
|
||||
return organisation.getTypeOrganisationLibelle() != null ? organisation.getTypeOrganisationLibelle() : "";
|
||||
}
|
||||
|
||||
public String getStatutLibelle() {
|
||||
if (organisation == null || organisation.getStatut() == null) return "Non renseigné";
|
||||
return switch (organisation.getStatut()) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.constants.StatutOrganisationConstants;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Named;
|
||||
@@ -74,7 +75,7 @@ public class OrganisationStatistiquesBean implements Serializable {
|
||||
private void calculerStatistiquesDepuisListe() {
|
||||
try {
|
||||
// Charger toutes les organisations
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
List<OrganisationResponse> organisations = (response != null && response.getData() != null) ? response.getData()
|
||||
: new ArrayList<>();
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.constants.StatutOrganisationConstants;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.reference.response.TypeReferenceResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.CacheService;
|
||||
import dev.lions.unionflow.client.service.ErrorHandlerService;
|
||||
@@ -71,6 +73,10 @@ public class OrganisationsBean implements Serializable {
|
||||
private OrganisationResponse organisationSelectionnee;
|
||||
private OrganisationResponse nouvelleOrganisation;
|
||||
private OrganisationResponse backupOrganisation; // Pour rollback
|
||||
/** Organisation en attente de confirmation de suppression (flux explicite). */
|
||||
private OrganisationResponse organisationPourSuppression;
|
||||
/** Organisation en attente de confirmation de bascule de statut (flux explicite). */
|
||||
private OrganisationResponse organisationPourStatut;
|
||||
|
||||
private long totalOrganisations;
|
||||
private long organisationsActives;
|
||||
@@ -110,7 +116,7 @@ public class OrganisationsBean implements Serializable {
|
||||
public void chargerOrganisations() {
|
||||
try {
|
||||
LOG.debug("Chargement des organisations");
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
PagedResponse<OrganisationResponse> response = retryService.executeWithRetrySupplier(
|
||||
() -> associationService.listerToutes(0, 1000),
|
||||
"chargement de toutes les organisations");
|
||||
organisations = (response != null && response.getData() != null) ? response.getData() : new ArrayList<>();
|
||||
@@ -136,7 +142,7 @@ public class OrganisationsBean implements Serializable {
|
||||
() -> {
|
||||
LOG.debug("Chargement de toutes les organisations pour les statistiques");
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = retryService
|
||||
PagedResponse<OrganisationResponse> response = retryService
|
||||
.executeWithRetrySupplier(
|
||||
() -> associationService.listerToutes(0, 10000),
|
||||
"chargement des statistiques");
|
||||
@@ -342,6 +348,45 @@ public class OrganisationsBean implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prépare la suppression (ouvre le dialogue de confirmation).
|
||||
*/
|
||||
public void preparerSuppression(OrganisationResponse organisation) {
|
||||
organisationPourSuppression = organisation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirme et exécute la suppression après clic sur « Oui » dans le dialogue.
|
||||
*/
|
||||
public void confirmerSuppression() {
|
||||
if (organisationPourSuppression == null) {
|
||||
errorHandler.showWarning("Erreur", "Aucune organisation à supprimer");
|
||||
return;
|
||||
}
|
||||
OrganisationResponse org = organisationPourSuppression;
|
||||
organisationPourSuppression = null;
|
||||
supprimerOrganisation(org);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prépare la bascule de statut (ouvre le dialogue de confirmation).
|
||||
*/
|
||||
public void preparerBasculerStatut(OrganisationResponse organisation) {
|
||||
organisationPourStatut = organisation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirme et exécute la bascule de statut après clic sur « Oui » dans le dialogue.
|
||||
*/
|
||||
public void confirmerBasculerStatut() {
|
||||
if (organisationPourStatut == null) {
|
||||
return;
|
||||
}
|
||||
OrganisationResponse org = organisationPourStatut;
|
||||
organisationPourStatut = null;
|
||||
basculerStatutOrganisation(org);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime une organisation.
|
||||
*/
|
||||
@@ -449,7 +494,7 @@ public class OrganisationsBean implements Serializable {
|
||||
return List.of();
|
||||
}
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.rechercher(
|
||||
PagedResponse<OrganisationResponse> response = associationService.rechercher(
|
||||
query, null, null, null, null, 0, 100);
|
||||
List<OrganisationResponse> resultats = (response != null && response.getData() != null) ? response.getData()
|
||||
: new ArrayList<>();
|
||||
|
||||
@@ -79,7 +79,7 @@ public class PersonnelBean implements Serializable {
|
||||
String email = userSession.getCurrentUser().getEmail();
|
||||
if (email != null) {
|
||||
// Rechercher le membre par email
|
||||
List<MembreResponse> membres = membreService.listerTous();
|
||||
List<MembreResponse> membres = membreService.listerTous().getData();
|
||||
membre = membres.stream()
|
||||
.filter(m -> email.equals(m.getEmail()))
|
||||
.findFirst()
|
||||
@@ -132,14 +132,10 @@ public class PersonnelBean implements Serializable {
|
||||
try {
|
||||
if (membre != null) {
|
||||
List<CotisationResponse> cotisations = cotisationService.obtenirParMembre(membre.getId(), 0, 100);
|
||||
Map<String, Object> evenementsMap = evenementService.listerTous(0, 100, "dateDebut", "desc");
|
||||
var evenementsResponse = evenementService.listerTous(0, 100, "dateDebut", "desc");
|
||||
int nbCotisations = cotisations != null ? cotisations.size() : 0;
|
||||
int nbEvenements = 0;
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
nbEvenements = content != null ? content.size() : 0;
|
||||
}
|
||||
int nbEvenements = evenementsResponse != null && evenementsResponse.getData() != null
|
||||
? evenementsResponse.getData().size() : 0;
|
||||
return nbCotisations + nbEvenements;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -152,14 +148,10 @@ public class PersonnelBean implements Serializable {
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Récupérer tous les événements et filtrer ceux où le membre a participé
|
||||
Map<String, Object> evenementsMap = evenementService.listerTous(0, 100, "dateDebut", "desc");
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
if (content != null) {
|
||||
// Pour l'instant, on estime que le membre a participé à 30% des événements
|
||||
return (int) (content.size() * 0.3);
|
||||
}
|
||||
var evenementsResponse = evenementService.listerTous(0, 100, "dateDebut", "desc");
|
||||
if (evenementsResponse != null && evenementsResponse.getData() != null) {
|
||||
// Pour l'instant, on estime que le membre a participé à 30% des événements
|
||||
return (int) (evenementsResponse.getData().size() * 0.3);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -243,24 +235,20 @@ public class PersonnelBean implements Serializable {
|
||||
}
|
||||
|
||||
// Charger les événements récents
|
||||
Map<String, Object> evenementsMap = evenementService.listerAVenir(0, 5);
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
if (content != null) {
|
||||
for (Map<String, Object> evtMap : content) {
|
||||
ActiviteRecente act = new ActiviteRecente();
|
||||
act.setTitre("Événement: " + (evtMap.get("titre") != null ? evtMap.get("titre").toString() : ""));
|
||||
act.setDescription("Événement à venir");
|
||||
if (evtMap.get("dateDebut") != null) {
|
||||
act.setDateHeure(formatDateRelative(evtMap.get("dateDebut").toString()));
|
||||
} else {
|
||||
act.setDateHeure("Bientôt");
|
||||
}
|
||||
act.setIcon("pi-calendar");
|
||||
act.setCouleur("blue-500");
|
||||
activitesRecentes.add(act);
|
||||
var evenementsResponse = evenementService.listerAVenir(0, 5);
|
||||
if (evenementsResponse != null && evenementsResponse.getData() != null) {
|
||||
for (EvenementResponse evt : evenementsResponse.getData()) {
|
||||
ActiviteRecente act = new ActiviteRecente();
|
||||
act.setTitre("Événement: " + (evt.getTitre() != null ? evt.getTitre() : ""));
|
||||
act.setDescription("Événement à venir");
|
||||
if (evt.getDateDebut() != null) {
|
||||
act.setDateHeure(formatDateRelative(evt.getDateDebut().toString()));
|
||||
} else {
|
||||
act.setDateHeure("Bientôt");
|
||||
}
|
||||
act.setIcon("pi-calendar");
|
||||
act.setCouleur("blue-500");
|
||||
activitesRecentes.add(act);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,29 +372,25 @@ public class PersonnelBean implements Serializable {
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Créer des notifications basées sur les événements à venir
|
||||
Map<String, Object> evenementsMap = evenementService.listerAVenir(0, 5);
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
if (content != null) {
|
||||
for (Map<String, Object> evtMap : content) {
|
||||
NotificationPersonnelle notif = new NotificationPersonnelle();
|
||||
notif.setId(UUID.randomUUID());
|
||||
notif.setTitre("Nouvel événement");
|
||||
notif.setMessage("Un nouvel événement a été programmé: " +
|
||||
(evtMap.get("titre") != null ? evtMap.get("titre").toString() : ""));
|
||||
if (evtMap.get("dateCreation") != null) {
|
||||
try {
|
||||
notif.setDateCreation(LocalDate.parse(evtMap.get("dateCreation").toString().substring(0, 10)));
|
||||
} catch (Exception e) {
|
||||
notif.setDateCreation(LocalDate.now().minusDays(1));
|
||||
}
|
||||
} else {
|
||||
var evenementsResponse = evenementService.listerAVenir(0, 5);
|
||||
if (evenementsResponse != null && evenementsResponse.getData() != null) {
|
||||
for (EvenementResponse evt : evenementsResponse.getData()) {
|
||||
NotificationPersonnelle notif = new NotificationPersonnelle();
|
||||
notif.setId(UUID.randomUUID());
|
||||
notif.setTitre("Nouvel événement");
|
||||
notif.setMessage("Un nouvel événement a été programmé: " +
|
||||
(evt.getTitre() != null ? evt.getTitre() : ""));
|
||||
if (evt.getDateCreation() != null) {
|
||||
try {
|
||||
notif.setDateCreation(evt.getDateCreation().toLocalDate());
|
||||
} catch (Exception e) {
|
||||
notif.setDateCreation(LocalDate.now().minusDays(1));
|
||||
}
|
||||
notif.setLue(false);
|
||||
notifications.add(notif);
|
||||
} else {
|
||||
notif.setDateCreation(LocalDate.now().minusDays(1));
|
||||
}
|
||||
notif.setLue(false);
|
||||
notifications.add(notif);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,8 +153,8 @@ public class RapportsBean implements Serializable {
|
||||
private void calculerIndicateurs() {
|
||||
indicateurs = new IndicateursGlobaux();
|
||||
try {
|
||||
int totalMembres = membreService.listerTous().size();
|
||||
int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").size();
|
||||
int totalMembres = membreService.listerTous().getData().size();
|
||||
int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").getData().size();
|
||||
|
||||
BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
|
||||
.filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
|
||||
@@ -197,7 +197,7 @@ public class RapportsBean implements Serializable {
|
||||
repartitionMembres = new ArrayList<>();
|
||||
try {
|
||||
// Corrigé: MembreResponse est dans server.api, pas client.dto; et getStatut() → getStatutCompte()
|
||||
List<dev.lions.unionflow.server.api.dto.membre.response.MembreResponse> membres = membreService.listerTous();
|
||||
List<dev.lions.unionflow.server.api.dto.membre.response.MembreResponse> membres = membreService.listerTous().getData();
|
||||
long actifs = membres.stream().filter(m -> "ACTIF".equals(m.getStatutCompte())).count();
|
||||
long inactifs = membres.stream().filter(m -> "INACTIF".equals(m.getStatutCompte())).count();
|
||||
long total = membres.size();
|
||||
@@ -248,8 +248,8 @@ public class RapportsBean implements Serializable {
|
||||
private void calculerObjectifs() {
|
||||
objectifs = new ArrayList<>();
|
||||
try {
|
||||
int totalMembres = membreService.listerTous().size();
|
||||
int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").size();
|
||||
int totalMembres = membreService.listerTous().getData().size();
|
||||
int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").getData().size();
|
||||
|
||||
BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
|
||||
.filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
|
||||
|
||||
@@ -31,6 +31,8 @@ public class RolesBean implements Serializable {
|
||||
private List<Role> roles;
|
||||
private Role roleSelectionne;
|
||||
private Role nouveauRole = new Role();
|
||||
/** Rôle en attente de confirmation de suppression (flux explicite). */
|
||||
private Role rolePourSuppression;
|
||||
|
||||
@jakarta.annotation.PostConstruct
|
||||
public void init() {
|
||||
@@ -120,6 +122,32 @@ public class RolesBean implements Serializable {
|
||||
public void gererUtilisateurs(Role role) {
|
||||
this.roleSelectionne = role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prépare la suppression (ouvre le dialogue de confirmation).
|
||||
*/
|
||||
public void preparerSuppression(Role role) {
|
||||
this.rolePourSuppression = role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirme et exécute la suppression après clic sur « Oui » dans le dialogue.
|
||||
*/
|
||||
public void confirmerSuppression() {
|
||||
if (rolePourSuppression == null) return;
|
||||
Role r = rolePourSuppression;
|
||||
rolePourSuppression = null;
|
||||
supprimerRole(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un rôle de la liste (côté client ; pas d'API delete dans AdminUserService).
|
||||
*/
|
||||
public void supprimerRole(Role role) {
|
||||
if (role != null && roles != null) {
|
||||
roles.remove(role);
|
||||
}
|
||||
}
|
||||
|
||||
public void creerRole() {
|
||||
// Validation
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.abonnement.response.AbonnementResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.client.service.AdminUserService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.AuditService;
|
||||
@@ -151,7 +153,7 @@ public class SuperAdminBean implements Serializable {
|
||||
|
||||
private void initializeAssociationKPIs() {
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
List<OrganisationResponse> associations = (response != null && response.getData() != null) ? response.getData()
|
||||
: new ArrayList<>();
|
||||
totalEntites = associations.size();
|
||||
@@ -291,7 +293,7 @@ public class SuperAdminBean implements Serializable {
|
||||
private void initializeEntites() {
|
||||
topEntites = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
List<OrganisationResponse> associations = (response != null && response.getData() != null) ? response.getData()
|
||||
: new ArrayList<>();
|
||||
topEntites = associations.stream()
|
||||
@@ -318,7 +320,7 @@ public class SuperAdminBean implements Serializable {
|
||||
private void initializeRepartitionTypes() {
|
||||
repartitionTypes = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
List<OrganisationResponse> associations = (response != null && response.getData() != null) ? response.getData()
|
||||
: new ArrayList<>();
|
||||
if (associations == null || associations.isEmpty())
|
||||
|
||||
@@ -56,6 +56,8 @@ public class TypeOrganisationsAdminBean implements Serializable {
|
||||
/** Type actuellement édité dans le dialogue (nouveau ou existant). */
|
||||
private TypeReferenceResponse typeCourant;
|
||||
private TypeReferenceResponse typeSelectionne;
|
||||
/** ID du type à supprimer (pour dialogue de confirmation explicite). */
|
||||
private UUID typeASupprimerId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
@@ -95,6 +97,11 @@ public class TypeOrganisationsAdminBean implements Serializable {
|
||||
.domaine("TYPE_ORGANISATION")
|
||||
.code(typeCourant.getCode())
|
||||
.libelle(typeCourant.getLibelle())
|
||||
.description(typeCourant.getDescription())
|
||||
.ordreAffichage(typeCourant.getOrdreAffichage() != null ? typeCourant.getOrdreAffichage() : 0)
|
||||
.estDefaut(false)
|
||||
.estSysteme(false)
|
||||
.organisationId(null)
|
||||
.build();
|
||||
|
||||
TypeReferenceResponse cree = retryService.executeWithRetrySupplier(
|
||||
@@ -152,11 +159,11 @@ public class TypeOrganisationsAdminBean implements Serializable {
|
||||
UpdateTypeReferenceRequest request = new UpdateTypeReferenceRequest(
|
||||
typeCourant.getCode(),
|
||||
typeCourant.getLibelle(),
|
||||
null, // description
|
||||
typeCourant.getDescription(),
|
||||
null, // icone
|
||||
null, // couleur
|
||||
null, // severity
|
||||
null, // ordreAffichage
|
||||
typeCourant.getOrdreAffichage(),
|
||||
null, // estDefaut
|
||||
typeCourant.getActif()
|
||||
);
|
||||
@@ -179,30 +186,49 @@ public class TypeOrganisationsAdminBean implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
public void desactiverType(UUID id) {
|
||||
/**
|
||||
* Ouvre le dialogue de confirmation de suppression (stocke l'id).
|
||||
*/
|
||||
public void preparerSuppression(UUID id) {
|
||||
typeASupprimerId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirme et exécute la suppression du type dont l'id a été stocké par preparerSuppression.
|
||||
*/
|
||||
public void confirmerSuppression() {
|
||||
if (typeASupprimerId == null) {
|
||||
errorHandler.showWarning("Erreur", "Aucun type à supprimer");
|
||||
return;
|
||||
}
|
||||
UUID id = typeASupprimerId;
|
||||
typeASupprimerId = null;
|
||||
supprimerType(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime définitivement un type d'organisation (appel DELETE côté API).
|
||||
*/
|
||||
public void supprimerType(UUID id) {
|
||||
if (id == null) {
|
||||
errorHandler.showWarning("Erreur", "Aucun type sélectionné");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
retryService.executeWithRetrySupplier(
|
||||
() -> {
|
||||
typeOrganisationClientService.disable(id);
|
||||
return null;
|
||||
},
|
||||
"désactivation d'un type d'organisation"
|
||||
"suppression d'un type d'organisation"
|
||||
);
|
||||
|
||||
LOG.infof("Type d'organisation désactivé avec succès: id=%s", id);
|
||||
LOG.infof("Type d'organisation supprimé avec succès: id=%s", id);
|
||||
typeCatalogueService.recharger();
|
||||
chargerTypes();
|
||||
|
||||
errorHandler.showSuccess("Succès", "Type d'organisation désactivé");
|
||||
|
||||
errorHandler.showSuccess("Succès", "Type d'organisation supprimé");
|
||||
} catch (Exception e) {
|
||||
LOG.errorf(e, "Erreur lors de la désactivation du type d'organisation");
|
||||
errorHandler.handleException(e, "lors de la désactivation d'un type d'organisation", null);
|
||||
LOG.errorf(e, "Erreur lors de la suppression du type d'organisation");
|
||||
errorHandler.handleException(e, "lors de la suppression d'un type d'organisation", null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.lions.unionflow.client.view;
|
||||
|
||||
import io.quarkus.oidc.IdToken;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
@@ -14,12 +15,12 @@ import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Gestion de la session utilisateur avec Keycloak OIDC
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Utilise {@code @IdToken JsonWebToken} pour accéder aux claims du token
|
||||
* et {@link SecurityIdentity} pour les vérifications d'authentification,
|
||||
* car l'application est en mode OIDC {@code web-app} (authorization code flow).
|
||||
*
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 2.1
|
||||
*/
|
||||
@@ -50,6 +51,20 @@ public class UserSession implements Serializable {
|
||||
clearSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise automatiquement la session après injection des dépendances
|
||||
* Appelé automatiquement par CDI si l'utilisateur est authentifié
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (securityIdentity != null && !securityIdentity.isAnonymous()) {
|
||||
LOGGER.info("Initialisation automatique de la session utilisateur (authentifié via OIDC)");
|
||||
initializeFromOidcToken();
|
||||
} else {
|
||||
LOGGER.info("Utilisateur non authentifié, session reste vide");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise la session depuis le token OIDC Keycloak
|
||||
* Appelé automatiquement après l'authentification
|
||||
|
||||
@@ -4,6 +4,7 @@ import dev.lions.unionflow.server.api.dto.user.request.CreateUserRequest;
|
||||
import dev.lions.unionflow.server.api.dto.user.request.UpdateUserRequest;
|
||||
import dev.lions.unionflow.server.api.dto.user.response.UserResponse;
|
||||
import dev.lions.unionflow.server.api.dto.base.PageResponse;
|
||||
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
|
||||
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
|
||||
import dev.lions.unionflow.client.service.AdminUserService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
@@ -84,7 +85,7 @@ public class UtilisateursBean implements Serializable {
|
||||
private void initializeOrganisations() {
|
||||
organisationsDisponibles = new ArrayList<>();
|
||||
try {
|
||||
AssociationService.PagedResponseDTO<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
PagedResponse<OrganisationResponse> response = associationService.listerToutes(0, 1000);
|
||||
List<OrganisationResponse> associations = (response != null && response.getData() != null) ? response.getData()
|
||||
: new ArrayList<>();
|
||||
for (OrganisationResponse assoc : associations) {
|
||||
|
||||
Reference in New Issue
Block a user