Files
btpxpress-frontend/src/main/java/dev/lions/btpxpress/service/DashboardService.java
dahoud b749f2df37 feat: Migration complète vers Quarkus PrimeFaces Freya
Migration du frontend React/Next.js vers Quarkus + PrimeFaces Freya 5.0.0

Dashboard:
- Extension de BtpXpressApiClient avec tous les endpoints dashboard
- Création de DashboardService pour récupérer les données API
- Refactorisation DashboardView : uniquement données réelles de l'API
- Restructuration dashboard.xhtml avec tous les aspects métiers BTP
- Suppression complète de toutes les données fictives

Topbar:
- Amélioration du menu profil utilisateur avec header professionnel
- Ajout UserSessionBean pour gérer les informations utilisateur
- Styles CSS personnalisés pour une disposition raffinée
- Badges de notifications conditionnels

Configuration:
- Intégration du thème Freya 5.0.0-jakarta
- Configuration OIDC pour Keycloak (security.lions.dev)
- Gestion des erreurs HTTP 431 (headers size)
- Support du format Fcfa avec séparateurs d'espaces

Converters:
- Création de FcfaConverter pour formater les montants en Fcfa avec espaces (x xxx xxx format)

Code Quality:
- Code entièrement documenté en français avec Javadoc exemplaire
- Respect du principe Java 'Write once, use many times'
- Logging complet pour le débogage
- Gestion d'erreurs robuste
2025-11-01 19:55:30 +00:00

312 lines
12 KiB
Java

package dev.lions.btpxpress.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
/**
* Service pour récupérer et transformer les données du dashboard depuis l'API backend.
*
* <p>Ce service encapsule tous les appels à l'API dashboard et transforme
* les réponses JSON en objets Java utilisables par les vues JSF.</p>
*
* @author BTP Xpress Team
* @version 1.0
*/
@ApplicationScoped
public class DashboardService {
private static final Logger logger = LoggerFactory.getLogger(DashboardService.class);
@Inject
@RestClient
BtpXpressApiClient apiClient;
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* Récupère les métriques du dashboard principal.
*
* @return JsonNode contenant les métriques ou null en cas d'erreur
*/
public JsonNode getDashboardPrincipal() {
try {
Response response = apiClient.getDashboardPrincipal();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
if (entity == null) {
logger.warn("Réponse vide du dashboard principal");
return null;
}
// REST Client avec Jackson désérialise déjà en Map/Object
return convertToJsonNode(entity);
} else {
logger.error("Erreur API dashboard principal: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération du dashboard principal", e);
return null;
}
}
/**
* Convertit un objet en JsonNode, quel que soit son type (String, Map, Object, etc.).
*/
private JsonNode convertToJsonNode(Object entity) {
try {
if (entity instanceof String) {
return objectMapper.readTree((String) entity);
} else if (entity instanceof Map || entity instanceof List) {
// Map ou List sont déjà désérialisés par REST Client
return objectMapper.valueToTree(entity);
} else {
// Pour les autres objets, conversion via ObjectMapper
return objectMapper.valueToTree(entity);
}
} catch (Exception e) {
logger.error("Erreur lors de la conversion en JsonNode", e);
return null;
}
}
/**
* Récupère les métriques des chantiers.
*
* @return JsonNode contenant les métriques des chantiers ou null en cas d'erreur
*/
public JsonNode getDashboardChantiers() {
try {
Response response = apiClient.getDashboardChantiers();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return convertToJsonNode(entity);
} else {
logger.error("Erreur API dashboard chantiers: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération du dashboard chantiers", e);
return null;
}
}
/**
* Récupère les métriques financières.
*
* @param periode Période en jours (défaut: 30)
* @return JsonNode contenant les métriques financières ou null en cas d'erreur
*/
public JsonNode getDashboardFinances(int periode) {
try {
Response response = apiClient.getDashboardFinances(periode);
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
} else {
logger.error("Erreur API dashboard finances: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération du dashboard finances", e);
return null;
}
}
/**
* Récupère les métriques de maintenance.
*
* @return JsonNode contenant les métriques de maintenance ou null en cas d'erreur
*/
public JsonNode getDashboardMaintenance() {
try {
Response response = apiClient.getDashboardMaintenance();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
} else {
logger.error("Erreur API dashboard maintenance: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération du dashboard maintenance", e);
return null;
}
}
/**
* Récupère les métriques des ressources.
*
* @return JsonNode contenant les métriques des ressources ou null en cas d'erreur
*/
public JsonNode getDashboardRessources() {
try {
Response response = apiClient.getDashboardRessources();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
} else {
logger.error("Erreur API dashboard ressources: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération du dashboard ressources", e);
return null;
}
}
/**
* Récupère les alertes.
*
* @return JsonNode contenant les alertes ou null en cas d'erreur
*/
public JsonNode getAlertes() {
try {
Response response = apiClient.getAlertes();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
} else {
logger.error("Erreur API alertes: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération des alertes", e);
return null;
}
}
/**
* Récupère les KPIs.
*
* @param periode Période en jours (défaut: 30)
* @return JsonNode contenant les KPIs ou null en cas d'erreur
*/
public JsonNode getKPI(int periode) {
try {
Response response = apiClient.getKPI(periode);
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
} else {
logger.error("Erreur API KPI: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération des KPIs", e);
return null;
}
}
/**
* Récupère les activités récentes.
*
* @param limit Nombre d'activités à récupérer
* @return JsonNode contenant les activités récentes ou null en cas d'erreur
*/
public JsonNode getActivitesRecentes(int limit) {
try {
Response response = apiClient.getActivitesRecentes(limit);
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
} else {
logger.error("Erreur API activités récentes: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération des activités récentes", e);
return null;
}
}
/**
* Récupère le résumé quotidien.
*
* @return JsonNode contenant le résumé quotidien ou null en cas d'erreur
*/
public JsonNode getResumeQuotidien() {
try {
Response response = apiClient.getResumeQuotidien();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
Object entity = response.getEntity();
return entity instanceof String ? objectMapper.readTree((String) entity) : objectMapper.valueToTree(entity);
} else {
logger.error("Erreur API résumé quotidien: status {}", response.getStatus());
return null;
}
} catch (Exception e) {
logger.error("Erreur lors de la récupération du résumé quotidien", e);
return null;
}
}
/**
* Récupère le nombre de clients.
*
* @return Nombre de clients ou 0 en cas d'erreur
*/
public int getNombreClients() {
try {
Response response = apiClient.getClients();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
List<?> clients = (List<?>) response.getEntity();
return clients != null ? clients.size() : 0;
}
return 0;
} catch (Exception e) {
logger.error("Erreur lors de la récupération du nombre de clients", e);
return 0;
}
}
/**
* Récupère le nombre de devis en attente.
*
* @return Nombre de devis en attente ou 0 en cas d'erreur
*/
public int getNombreDevisEnAttente() {
try {
Response response = apiClient.getDevis();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
List<?> devis = (List<?>) response.getEntity();
// TODO: Filtrer par statut EN_ATTENTE si l'API le permet
return devis != null ? devis.size() : 0;
}
return 0;
} catch (Exception e) {
logger.error("Erreur lors de la récupération du nombre de devis", e);
return 0;
}
}
/**
* Récupère le nombre de factures impayées.
*
* @return Nombre de factures impayées ou 0 en cas d'erreur
*/
public int getNombreFacturesImpayees() {
try {
Response response = apiClient.getFactures();
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
List<?> factures = (List<?>) response.getEntity();
// TODO: Filtrer par statut IMPAYEE si l'API le permet
return factures != null ? factures.size() : 0;
}
return 0;
} catch (Exception e) {
logger.error("Erreur lors de la récupération du nombre de factures", e);
return 0;
}
}
}