feat: Module Devis professionnel avec écrans complets
Création de 2 écrans professionnels pour le module Devis:
1. devis/nouveau.xhtml:
- 4 sections: Informations générales, Détail du devis, Montants, Conditions
- Numéro auto-généré avec icône
- Statut avec 5 valeurs (BROUILLON, ATTENTE, ACCEPTE, REFUSE, EXPIRE)
- Dates d'émission et validité avec calendriers
- Client et objet du devis requis
- Placeholder pour lignes de devis (future développement)
- Calcul automatique TVA 18% et TTC
- Récapitulatif visuel HT/TVA/TTC avec composant monétaire
- Conditions de paiement et remarques (section collapsible)
- 3 boutons: Annuler, Brouillon, Envoyer
2. devis/details.xhtml:
- En-tête: numéro, statut, client, objet, dates
- Actions: Retour, Convertir en chantier, PDF, Modifier
- 4 KPI cards: Montant HT, TVA, TTC, Statut
- 6 onglets professionnels:
* Vue d'ensemble: infos + récap financier + actions rapides
* Détail des lignes: table lignes (placeholder)
* Conditions: paiement, délais, garanties
* Documents: GED associée (placeholder)
* Suivi: timeline actions
* Historique: modifications (placeholder)
Corrections:
- Fix navigation /factures/nouvelle -> /factures/nouveau (factures.xhtml)
- Fix menu /factures/nouvelle -> /factures/nouveau (menu.xhtml)
Tous les composants réutilisables utilisés (status-badge, monetary-display).
Validation complète côté client et serveur.
UI/UX professionnel adapté au métier BTP.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
package dev.lions.btpxpress.filter;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Filtre de sécurité qui ajoute les headers HTTP de sécurité essentiels
|
||||
* pour protéger l'application contre diverses attaques.
|
||||
*/
|
||||
public class SecurityHeadersFilter implements Filter {
|
||||
|
||||
private static final String STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security";
|
||||
private static final String X_FRAME_OPTIONS = "X-Frame-Options";
|
||||
private static final String X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
|
||||
private static final String X_XSS_PROTECTION = "X-XSS-Protection";
|
||||
private static final String REFERRER_POLICY = "Referrer-Policy";
|
||||
private static final String CONTENT_SECURITY_POLICY = "Content-Security-Policy";
|
||||
private static final String PERMISSIONS_POLICY = "Permissions-Policy";
|
||||
|
||||
// HSTS - Force HTTPS pendant 1 an, inclut les sous-domaines
|
||||
private static final String HSTS_VALUE = "max-age=31536000; includeSubDomains; preload";
|
||||
|
||||
// X-Frame-Options - Empêche le clickjacking
|
||||
private static final String X_FRAME_OPTIONS_VALUE = "DENY";
|
||||
|
||||
// X-Content-Type-Options - Empêche le MIME sniffing
|
||||
private static final String X_CONTENT_TYPE_OPTIONS_VALUE = "nosniff";
|
||||
|
||||
// X-XSS-Protection - Active la protection XSS du navigateur (legacy mais utile)
|
||||
private static final String X_XSS_PROTECTION_VALUE = "1; mode=block";
|
||||
|
||||
// Referrer-Policy - Contrôle les informations de referrer envoyées
|
||||
private static final String REFERRER_POLICY_VALUE = "strict-origin-when-cross-origin";
|
||||
|
||||
// Content Security Policy - Politique de sécurité stricte
|
||||
// Autorise uniquement les ressources depuis le même domaine et security.lions.dev
|
||||
private static final String CSP_VALUE =
|
||||
"default-src 'self'; " +
|
||||
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://security.lions.dev; " +
|
||||
"style-src 'self' 'unsafe-inline' https://security.lions.dev; " +
|
||||
"img-src 'self' data: https: blob:; " +
|
||||
"font-src 'self' data: https://security.lions.dev; " +
|
||||
"connect-src 'self' https://security.lions.dev https://api.btpxpress.lions.dev https://api.lions.dev; " +
|
||||
"frame-src 'self' https://security.lions.dev; " +
|
||||
"object-src 'none'; " +
|
||||
"base-uri 'self'; " +
|
||||
"form-action 'self' https://security.lions.dev; " +
|
||||
"frame-ancestors 'none'; " +
|
||||
"upgrade-insecure-requests;";
|
||||
|
||||
// Permissions Policy - Désactive les fonctionnalités non nécessaires
|
||||
private static final String PERMISSIONS_POLICY_VALUE =
|
||||
"geolocation=(), " +
|
||||
"microphone=(), " +
|
||||
"camera=(), " +
|
||||
"payment=(), " +
|
||||
"usb=(), " +
|
||||
"magnetometer=(), " +
|
||||
"gyroscope=(), " +
|
||||
"speaker=()";
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
// Initialisation non nécessaire
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
// Ajouter les headers de sécurité uniquement pour les requêtes HTTPS
|
||||
if (httpRequest.isSecure() ||
|
||||
"https".equalsIgnoreCase(httpRequest.getHeader("X-Forwarded-Proto")) ||
|
||||
"https".equalsIgnoreCase(httpRequest.getHeader("X-Forwarded-Scheme"))) {
|
||||
|
||||
// Strict Transport Security (HSTS)
|
||||
httpResponse.setHeader(STRICT_TRANSPORT_SECURITY, HSTS_VALUE);
|
||||
|
||||
// Content Security Policy
|
||||
httpResponse.setHeader(CONTENT_SECURITY_POLICY, CSP_VALUE);
|
||||
}
|
||||
|
||||
// Headers de sécurité applicables même en HTTP (développement)
|
||||
// Ces headers seront toujours présents
|
||||
httpResponse.setHeader(X_FRAME_OPTIONS, X_FRAME_OPTIONS_VALUE);
|
||||
httpResponse.setHeader(X_CONTENT_TYPE_OPTIONS, X_CONTENT_TYPE_OPTIONS_VALUE);
|
||||
httpResponse.setHeader(X_XSS_PROTECTION, X_XSS_PROTECTION_VALUE);
|
||||
httpResponse.setHeader(REFERRER_POLICY, REFERRER_POLICY_VALUE);
|
||||
httpResponse.setHeader(PERMISSIONS_POLICY, PERMISSIONS_POLICY_VALUE);
|
||||
|
||||
// Headers supplémentaires pour renforcer la sécurité
|
||||
httpResponse.setHeader("X-Permitted-Cross-Domain-Policies", "none");
|
||||
httpResponse.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
|
||||
httpResponse.setHeader("Cross-Origin-Opener-Policy", "same-origin");
|
||||
httpResponse.setHeader("Cross-Origin-Resource-Policy", "same-origin");
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// Nettoyage non nécessaire
|
||||
}
|
||||
}
|
||||
|
||||
82
src/main/java/dev/lions/btpxpress/service/ClientService.java
Normal file
82
src/main/java/dev/lions/btpxpress/service/ClientService.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package dev.lions.btpxpress.service;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service de gestion des clients côté client.
|
||||
* <p>
|
||||
* Ce service encapsule la communication avec l'API backend pour les opérations
|
||||
* liées aux clients. Il utilise le REST Client pour effectuer les appels HTTP
|
||||
* vers le backend.
|
||||
* </p>
|
||||
*
|
||||
* @author BTP Xpress Development Team
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class ClientService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ClientService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
BtpXpressApiClient apiClient;
|
||||
|
||||
/**
|
||||
* Récupère tous les clients depuis l'API backend.
|
||||
*
|
||||
* @return Liste des clients, ou liste vide en cas d'erreur.
|
||||
*/
|
||||
public List<Map<String, Object>> getAllClients() {
|
||||
try {
|
||||
LOG.debug("Récupération de la liste des clients depuis l'API backend.");
|
||||
Response response = apiClient.getClients();
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> clients = response.readEntity(List.class);
|
||||
LOG.debug("Clients récupérés avec succès : {} élément(s)", clients != null ? clients.size() : 0);
|
||||
return clients != null ? clients : new ArrayList<>();
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération des clients. Code HTTP : {}", response.getStatus());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer les clients : {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère un client par son identifiant depuis l'API backend.
|
||||
*
|
||||
* @param id L'identifiant du client.
|
||||
* @return Le client sous forme de Map, ou null en cas d'erreur.
|
||||
*/
|
||||
public Map<String, Object> getClientById(Long id) {
|
||||
try {
|
||||
LOG.debug("Récupération du client avec ID : {}", id);
|
||||
Response response = apiClient.getClient(id);
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
Map<String, Object> client = response.readEntity(Map.class);
|
||||
LOG.debug("Client récupéré avec succès.");
|
||||
return client;
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération du client. Code HTTP : {}", response.getStatus());
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer le client : {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/main/java/dev/lions/btpxpress/service/DevisService.java
Normal file
58
src/main/java/dev/lions/btpxpress/service/DevisService.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package dev.lions.btpxpress.service;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service de gestion des devis côté client.
|
||||
* <p>
|
||||
* Ce service encapsule la communication avec l'API backend pour les opérations
|
||||
* liées aux devis. Il utilise le REST Client pour effectuer les appels HTTP
|
||||
* vers le backend.
|
||||
* </p>
|
||||
*
|
||||
* @author BTP Xpress Development Team
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class DevisService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DevisService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
BtpXpressApiClient apiClient;
|
||||
|
||||
/**
|
||||
* Récupère tous les devis depuis l'API backend.
|
||||
*
|
||||
* @return Liste des devis, ou liste vide en cas d'erreur.
|
||||
*/
|
||||
public List<Map<String, Object>> getAllDevis() {
|
||||
try {
|
||||
LOG.debug("Récupération de la liste des devis depuis l'API backend.");
|
||||
Response response = apiClient.getDevis();
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> devis = response.readEntity(List.class);
|
||||
LOG.debug("Devis récupérés avec succès : {} élément(s)", devis != null ? devis.size() : 0);
|
||||
return devis != null ? devis : new ArrayList<>();
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération des devis. Code HTTP : {}", response.getStatus());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer les devis : {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package dev.lions.btpxpress.service;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service de gestion des employés côté client.
|
||||
* <p>
|
||||
* Ce service encapsule la communication avec l'API backend pour les opérations
|
||||
* liées aux employés. Il utilise le REST Client pour effectuer les appels HTTP
|
||||
* vers le backend.
|
||||
* </p>
|
||||
*
|
||||
* @author BTP Xpress Development Team
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class EmployeService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EmployeService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
BtpXpressApiClient apiClient;
|
||||
|
||||
/**
|
||||
* Récupère tous les employés depuis l'API backend.
|
||||
*
|
||||
* @return Liste des employés, ou liste vide en cas d'erreur.
|
||||
*/
|
||||
public List<Map<String, Object>> getAllEmployes() {
|
||||
try {
|
||||
LOG.debug("Récupération de la liste des employés depuis l'API backend.");
|
||||
Response response = apiClient.getEmployes();
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> employes = response.readEntity(List.class);
|
||||
LOG.debug("Employés récupérés avec succès : {} élément(s)", employes != null ? employes.size() : 0);
|
||||
return employes != null ? employes : new ArrayList<>();
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération des employés. Code HTTP : {}", response.getStatus());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer les employés : {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/main/java/dev/lions/btpxpress/service/EquipeService.java
Normal file
58
src/main/java/dev/lions/btpxpress/service/EquipeService.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package dev.lions.btpxpress.service;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service de gestion des équipes côté client.
|
||||
* <p>
|
||||
* Ce service encapsule la communication avec l'API backend pour les opérations
|
||||
* liées aux équipes. Il utilise le REST Client pour effectuer les appels HTTP
|
||||
* vers le backend.
|
||||
* </p>
|
||||
*
|
||||
* @author BTP Xpress Development Team
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class EquipeService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EquipeService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
BtpXpressApiClient apiClient;
|
||||
|
||||
/**
|
||||
* Récupère toutes les équipes depuis l'API backend.
|
||||
*
|
||||
* @return Liste des équipes, ou liste vide en cas d'erreur.
|
||||
*/
|
||||
public List<Map<String, Object>> getAllEquipes() {
|
||||
try {
|
||||
LOG.debug("Récupération de la liste des équipes depuis l'API backend.");
|
||||
Response response = apiClient.getEquipes();
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> equipes = response.readEntity(List.class);
|
||||
LOG.debug("Équipes récupérées avec succès : {} élément(s)", equipes != null ? equipes.size() : 0);
|
||||
return equipes != null ? equipes : new ArrayList<>();
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération des équipes. Code HTTP : {}", response.getStatus());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer les équipes : {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package dev.lions.btpxpress.service;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service de gestion des factures côté client.
|
||||
* <p>
|
||||
* Ce service encapsule la communication avec l'API backend pour les opérations
|
||||
* liées aux factures. Il utilise le REST Client pour effectuer les appels HTTP
|
||||
* vers le backend.
|
||||
* </p>
|
||||
*
|
||||
* @author BTP Xpress Development Team
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class FactureService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FactureService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
BtpXpressApiClient apiClient;
|
||||
|
||||
/**
|
||||
* Récupère toutes les factures depuis l'API backend.
|
||||
*
|
||||
* @return Liste des factures, ou liste vide en cas d'erreur.
|
||||
*/
|
||||
public List<Map<String, Object>> getAllFactures() {
|
||||
try {
|
||||
LOG.debug("Récupération de la liste des factures depuis l'API backend.");
|
||||
Response response = apiClient.getFactures();
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> factures = response.readEntity(List.class);
|
||||
LOG.debug("Factures récupérées avec succès : {} élément(s)", factures != null ? factures.size() : 0);
|
||||
return factures != null ? factures : new ArrayList<>();
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération des factures. Code HTTP : {}", response.getStatus());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer les factures : {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package dev.lions.btpxpress.service;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service de gestion des matériels côté client.
|
||||
* <p>
|
||||
* Ce service encapsule la communication avec l'API backend pour les opérations
|
||||
* liées aux matériels. Il utilise le REST Client pour effectuer les appels HTTP
|
||||
* vers le backend.
|
||||
* </p>
|
||||
*
|
||||
* @author BTP Xpress Development Team
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class MaterielService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MaterielService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
BtpXpressApiClient apiClient;
|
||||
|
||||
/**
|
||||
* Récupère tous les matériels depuis l'API backend.
|
||||
*
|
||||
* @return Liste des matériels, ou liste vide en cas d'erreur.
|
||||
*/
|
||||
public List<Map<String, Object>> getAllMateriels() {
|
||||
try {
|
||||
LOG.debug("Récupération de la liste des matériels depuis l'API backend.");
|
||||
Response response = apiClient.getMateriels();
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> materiels = response.readEntity(List.class);
|
||||
LOG.debug("Matériels récupérés avec succès : {} élément(s)", materiels != null ? materiels.size() : 0);
|
||||
return materiels != null ? materiels : new ArrayList<>();
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération des matériels. Code HTTP : {}", response.getStatus());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer les matériels : {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
61
src/main/java/dev/lions/btpxpress/service/StockService.java
Normal file
61
src/main/java/dev/lions/btpxpress/service/StockService.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package dev.lions.btpxpress.service;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service de gestion des stocks côté client.
|
||||
* <p>
|
||||
* Ce service encapsule la communication avec l'API backend pour les opérations
|
||||
* liées aux stocks. Il utilise le REST Client pour effectuer les appels HTTP
|
||||
* vers le backend.
|
||||
* </p>
|
||||
*
|
||||
* @author BTP Xpress Development Team
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class StockService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StockService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
BtpXpressApiClient apiClient;
|
||||
|
||||
/**
|
||||
* Récupère tous les stocks depuis l'API backend.
|
||||
*
|
||||
* @return Liste des stocks, ou liste vide en cas d'erreur.
|
||||
*/
|
||||
public List<Map<String, Object>> getAllStocks() {
|
||||
try {
|
||||
LOG.debug("Récupération de la liste des stocks depuis l'API backend.");
|
||||
Response response = apiClient.getStocks();
|
||||
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
|
||||
// Le backend retourne un objet avec une propriété "stocks"
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> data = response.readEntity(Map.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> stocks = (List<Map<String, Object>>) data.get("stocks");
|
||||
LOG.debug("Stocks récupérés avec succès : {} élément(s)", stocks != null ? stocks.size() : 0);
|
||||
return stocks != null ? stocks : new ArrayList<>();
|
||||
} else {
|
||||
LOG.warn("Erreur lors de la récupération des stocks. Code HTTP : {}", response.getStatus());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la communication avec l'API backend pour récupérer les stocks : {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,383 @@
|
||||
package dev.lions.btpxpress.view;
|
||||
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Classe de base pour les vues de type liste/CRUD.
|
||||
*
|
||||
* Fonctionnalités:
|
||||
* - Chargement et affichage de listes
|
||||
* - Filtrage multi-critères
|
||||
* - Tri (ascendant/descendant)
|
||||
* - Pagination
|
||||
* - CRUD complet (Create, Read, Update, Delete)
|
||||
* - Sélection simple/multiple
|
||||
* - Messages utilisateur (succès, erreur, warning)
|
||||
* - Lazy loading pour grandes listes
|
||||
*
|
||||
* Principe DRY: Toute la logique commune des écrans de liste est centralisée ici.
|
||||
*
|
||||
* @param <T> Type d'entité
|
||||
* @param <ID> Type de l'identifiant
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class BaseListView<T, ID> implements Serializable {
|
||||
|
||||
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(BaseListView.class);
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected List<T> items = new java.util.ArrayList<>();
|
||||
// ========== Données ==========
|
||||
protected List<T> items = new ArrayList<>();
|
||||
protected List<T> filteredItems = new ArrayList<>();
|
||||
protected T selectedItem;
|
||||
protected boolean loading = false;
|
||||
protected List<T> selectedItems = new ArrayList<>();
|
||||
protected T entity; // Pour les formulaires create/edit
|
||||
|
||||
public abstract void loadItems();
|
||||
|
||||
protected void applyFilters(List<T> items, List<Predicate<T>> filters) {
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
filters.stream()
|
||||
.filter(p -> p != null)
|
||||
.forEach(filter -> items.removeIf(filter.negate()));
|
||||
// ========== États ==========
|
||||
protected boolean loading = false;
|
||||
protected boolean editing = false; // Mode édition vs création
|
||||
protected String globalFilter; // Recherche globale
|
||||
|
||||
// ========== Pagination ==========
|
||||
protected int first = 0; // Index de départ
|
||||
protected int pageSize = 10; // Taille de page
|
||||
protected int totalRecords = 0; // Nombre total d'enregistrements
|
||||
|
||||
// ========== Tri ==========
|
||||
protected String sortField; // Champ de tri
|
||||
protected boolean sortAscending = true; // Ordre de tri
|
||||
|
||||
// ========== Sélection ==========
|
||||
protected String selectionMode = "single"; // single, multiple, checkbox
|
||||
|
||||
/**
|
||||
* Initialisation du bean au chargement de la page.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
LOG.debug("Initialisation de {}", getClass().getSimpleName());
|
||||
try {
|
||||
initializeFields();
|
||||
loadItems();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de l'initialisation", e);
|
||||
addErrorMessage("Erreur lors du chargement des données");
|
||||
}
|
||||
}
|
||||
|
||||
public void search() {
|
||||
LOG.debug("Recherche lancée pour {}", getClass().getSimpleName());
|
||||
/**
|
||||
* Initialiser les champs spécifiques de la vue.
|
||||
* Override si nécessaire.
|
||||
*/
|
||||
protected void initializeFields() {
|
||||
// À surcharger dans les classes filles si besoin
|
||||
}
|
||||
|
||||
/**
|
||||
* Charger les items depuis la source de données.
|
||||
* DOIT être implémenté par les classes filles.
|
||||
*/
|
||||
public abstract void loadItems();
|
||||
|
||||
/**
|
||||
* Recharger les données (alias pour loadItems).
|
||||
*/
|
||||
public void refresh() {
|
||||
LOG.debug("Rafraîchissement des données");
|
||||
loadItems();
|
||||
}
|
||||
|
||||
// ========== Filtrage ==========
|
||||
|
||||
/**
|
||||
* Appliquer les filtres à la liste d'items.
|
||||
*/
|
||||
protected void applyFilters(List<T> sourceItems, List<Predicate<T>> filters) {
|
||||
if (filters == null || filters.isEmpty()) {
|
||||
filteredItems = new ArrayList<>(sourceItems);
|
||||
return;
|
||||
}
|
||||
|
||||
filteredItems = sourceItems.stream()
|
||||
.filter(filters.stream().reduce(Predicate::and).orElse(x -> true))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche avec les critères de filtrage actuels.
|
||||
*/
|
||||
public void search() {
|
||||
LOG.debug("Recherche lancée pour {}", getClass().getSimpleName());
|
||||
first = 0; // Retour à la première page
|
||||
loadItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialiser tous les filtres.
|
||||
*/
|
||||
public void resetFilters() {
|
||||
LOG.debug("Réinitialisation des filtres pour {}", getClass().getSimpleName());
|
||||
globalFilter = null;
|
||||
sortField = null;
|
||||
sortAscending = true;
|
||||
first = 0;
|
||||
resetFilterFields();
|
||||
loadItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialiser les champs de filtre spécifiques.
|
||||
* DOIT être implémenté par les classes filles.
|
||||
*/
|
||||
protected abstract void resetFilterFields();
|
||||
|
||||
public String viewDetails(ID id) {
|
||||
LOG.debug("Redirection vers détails : {}", id);
|
||||
return getDetailsPath() + id + "?faces-redirect=true";
|
||||
// ========== Tri ==========
|
||||
|
||||
/**
|
||||
* Trier la liste par un champ donné.
|
||||
*/
|
||||
public void sort(String field) {
|
||||
if (field.equals(sortField)) {
|
||||
sortAscending = !sortAscending;
|
||||
} else {
|
||||
sortField = field;
|
||||
sortAscending = true;
|
||||
}
|
||||
LOG.debug("Tri par {} ({})", field, sortAscending ? "ASC" : "DESC");
|
||||
loadItems();
|
||||
}
|
||||
|
||||
// ========== Navigation ==========
|
||||
|
||||
/**
|
||||
* Naviguer vers la page de détails d'un item.
|
||||
*/
|
||||
public String viewDetails(ID id) {
|
||||
LOG.debug("Redirection vers détails : {}", id);
|
||||
return getDetailsPath() + "?id=" + id + "&faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Naviguer vers la page de détails de l'item sélectionné.
|
||||
*/
|
||||
public String viewSelectedDetails() {
|
||||
if (selectedItem == null) {
|
||||
addWarningMessage("Aucun élément sélectionné");
|
||||
return null;
|
||||
}
|
||||
return viewDetails(getEntityId(selectedItem));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtenir le chemin de la page de détails.
|
||||
*/
|
||||
protected abstract String getDetailsPath();
|
||||
|
||||
/**
|
||||
* Naviguer vers la page de création.
|
||||
*/
|
||||
public String createNew() {
|
||||
LOG.debug("Redirection vers création");
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtenir le chemin de la page de création.
|
||||
*/
|
||||
protected abstract String getCreatePath();
|
||||
|
||||
// ========== CRUD ==========
|
||||
|
||||
/**
|
||||
* Préparer un nouvel item pour création.
|
||||
*/
|
||||
public void prepareNew() {
|
||||
LOG.debug("Préparation nouvelle entité");
|
||||
entity = createNewEntity();
|
||||
editing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Créer une nouvelle instance de l'entité.
|
||||
* DOIT être implémenté par les classes filles.
|
||||
*/
|
||||
protected abstract T createNewEntity();
|
||||
|
||||
/**
|
||||
* Préparer un item pour édition.
|
||||
*/
|
||||
public void prepareEdit(T item) {
|
||||
LOG.debug("Préparation édition : {}", item);
|
||||
entity = item;
|
||||
editing = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarder l'entité (création ou modification).
|
||||
*/
|
||||
public void save() {
|
||||
try {
|
||||
loading = true;
|
||||
|
||||
if (editing) {
|
||||
performUpdate();
|
||||
addSuccessMessage("Modification réussie");
|
||||
} else {
|
||||
performCreate();
|
||||
addSuccessMessage("Création réussie");
|
||||
}
|
||||
|
||||
loadItems();
|
||||
entity = null;
|
||||
editing = false;
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la sauvegarde", e);
|
||||
addErrorMessage("Erreur lors de la sauvegarde : " + e.getMessage());
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Créer une nouvelle entité.
|
||||
* DOIT être implémenté par les classes filles.
|
||||
*/
|
||||
protected abstract void performCreate();
|
||||
|
||||
/**
|
||||
* Mettre à jour une entité existante.
|
||||
* DOIT être implémenté par les classes filles.
|
||||
*/
|
||||
protected abstract void performUpdate();
|
||||
|
||||
/**
|
||||
* Supprimer l'item sélectionné.
|
||||
*/
|
||||
public void delete() {
|
||||
if (selectedItem != null) {
|
||||
if (selectedItem == null) {
|
||||
addWarningMessage("Aucun élément sélectionné");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading = true;
|
||||
LOG.info("Suppression : {}", selectedItem);
|
||||
performDelete();
|
||||
items.remove(selectedItem);
|
||||
selectedItem = null;
|
||||
addSuccessMessage("Suppression réussie");
|
||||
loadItems();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la suppression", e);
|
||||
addErrorMessage("Erreur lors de la suppression : " + e.getMessage());
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprimer les items sélectionnés (sélection multiple).
|
||||
*/
|
||||
public void deleteSelected() {
|
||||
if (selectedItems == null || selectedItems.isEmpty()) {
|
||||
addWarningMessage("Aucun élément sélectionné");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading = true;
|
||||
int count = selectedItems.size();
|
||||
for (T item : selectedItems) {
|
||||
selectedItem = item;
|
||||
performDelete();
|
||||
}
|
||||
loadItems();
|
||||
selectedItems.clear();
|
||||
selectedItem = null;
|
||||
addSuccessMessage(count + " élément(s) supprimé(s)");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur lors de la suppression multiple", e);
|
||||
addErrorMessage("Erreur lors de la suppression");
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectuer la suppression réelle.
|
||||
* DOIT être implémenté par les classes filles.
|
||||
*/
|
||||
protected abstract void performDelete();
|
||||
|
||||
/**
|
||||
* Obtenir l'ID d'une entité.
|
||||
* DOIT être implémenté par les classes filles.
|
||||
*/
|
||||
protected abstract ID getEntityId(T entity);
|
||||
|
||||
// ========== Messages utilisateur ==========
|
||||
|
||||
protected void addSuccessMessage(String message) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message));
|
||||
}
|
||||
|
||||
protected void addErrorMessage(String message) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message));
|
||||
}
|
||||
|
||||
protected void addWarningMessage(String message) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", message));
|
||||
}
|
||||
|
||||
protected void addInfoMessage(String message) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Information", message));
|
||||
}
|
||||
|
||||
// ========== Utilitaires ==========
|
||||
|
||||
/**
|
||||
* Vérifier si la liste est vide.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return items == null || items.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtenir le nombre d'items.
|
||||
*/
|
||||
public int getItemCount() {
|
||||
return items == null ? 0 : items.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifier si un item est sélectionné.
|
||||
*/
|
||||
public boolean hasSelection() {
|
||||
return selectedItem != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifier si plusieurs items sont sélectionnés.
|
||||
*/
|
||||
public boolean hasMultipleSelection() {
|
||||
return selectedItems != null && !selectedItems.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,39 @@ public class ChantiersView extends BaseListView<ChantiersView.Chantier, Long> im
|
||||
@Override
|
||||
protected void performDelete() {
|
||||
LOG.info("Suppression chantier : {}", selectedItem.getId());
|
||||
// TODO: Appeler chantierService.delete(selectedItem.getId())
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chantier createNewEntity() {
|
||||
Chantier c = new Chantier();
|
||||
c.setStatut("PLANIFIE");
|
||||
c.setAvancement(0);
|
||||
c.setDateDebut(LocalDate.now());
|
||||
c.setDateCreation(LocalDateTime.now());
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
entity.setId(System.currentTimeMillis()); // Simulation ID
|
||||
entity.setDateCreation(LocalDateTime.now());
|
||||
entity.setDateModification(LocalDateTime.now());
|
||||
items.add(entity);
|
||||
LOG.info("Nouveau chantier créé : {}", entity.getNom());
|
||||
// TODO: Appeler chantierService.create(entity)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
entity.setDateModification(LocalDateTime.now());
|
||||
LOG.info("Chantier modifié : {}", entity.getNom());
|
||||
// TODO: Appeler chantierService.update(entity)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Chantier chantier) {
|
||||
return chantier.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,10 +205,7 @@ public class ChantiersView extends BaseListView<ChantiersView.Chantier, Long> im
|
||||
*/
|
||||
@Override
|
||||
public String createNew() {
|
||||
selectedItem = new Chantier();
|
||||
selectedItem.setStatut("PLANIFIE");
|
||||
selectedItem.setAvancement(0);
|
||||
selectedItem.setDateDebut(LocalDate.now());
|
||||
prepareNew();
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,38 @@ public class ClientsView extends BaseListView<ClientsView.Client, Long> implemen
|
||||
LOG.info("Suppression client : {}", selectedItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Client createNewEntity() {
|
||||
Client client = new Client();
|
||||
client.setDateCreation(LocalDateTime.now());
|
||||
client.setDateModification(LocalDateTime.now());
|
||||
client.setNombreChantiers(0);
|
||||
client.setChiffreAffairesTotal(0.0);
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
if (selectedItem.getId() == null) {
|
||||
selectedItem.setId(System.currentTimeMillis());
|
||||
}
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
selectedItem.setDateModification(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Created: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
selectedItem.setDateModification(LocalDateTime.now());
|
||||
LOG.info("Updated: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Client entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise un nouveau client pour la création.
|
||||
*/
|
||||
|
||||
270
src/main/java/dev/lions/btpxpress/view/DevisView.java
Normal file
270
src/main/java/dev/lions/btpxpress/view/DevisView.java
Normal file
@@ -0,0 +1,270 @@
|
||||
package dev.lions.btpxpress.view;
|
||||
|
||||
import dev.lions.btpxpress.service.DevisService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Named("devisView")
|
||||
@ViewScoped
|
||||
@Getter
|
||||
@Setter
|
||||
public class DevisView extends BaseListView<DevisView.Devis, Long> implements Serializable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DevisView.class);
|
||||
|
||||
@Inject
|
||||
DevisService devisService;
|
||||
|
||||
private String filtreNumero;
|
||||
private String filtreClient;
|
||||
private String filtreStatut;
|
||||
private Long devisId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (filtreStatut == null) {
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
loadItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Définit le filtre de statut (utilisé depuis les pages filtrées).
|
||||
*/
|
||||
public void setFiltreStatut(String statut) {
|
||||
this.filtreStatut = statut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadItems() {
|
||||
loading = true;
|
||||
try {
|
||||
items = new ArrayList<>();
|
||||
|
||||
// Récupération depuis l'API backend
|
||||
List<Map<String, Object>> devisData = devisService.getAllDevis();
|
||||
|
||||
for (Map<String, Object> data : devisData) {
|
||||
Devis d = new Devis();
|
||||
|
||||
// Mapping des données de l'API vers l'objet Devis
|
||||
d.setId(data.get("id") != null ? Long.valueOf(data.get("id").toString().hashCode()) : null);
|
||||
d.setNumero((String) data.get("numero"));
|
||||
d.setObjet((String) data.get("objet"));
|
||||
|
||||
// Le client peut être un objet ou une chaîne
|
||||
Object clientObj = data.get("client");
|
||||
if (clientObj instanceof Map) {
|
||||
Map<String, Object> clientData = (Map<String, Object>) clientObj;
|
||||
String entreprise = (String) clientData.get("entreprise");
|
||||
String nom = (String) clientData.get("nom");
|
||||
String prenom = (String) clientData.get("prenom");
|
||||
d.setClient(entreprise != null && !entreprise.trim().isEmpty() ?
|
||||
entreprise : (prenom != null ? prenom + " " : "") + (nom != null ? nom : ""));
|
||||
} else if (clientObj instanceof String) {
|
||||
d.setClient((String) clientObj);
|
||||
} else {
|
||||
d.setClient("N/A");
|
||||
}
|
||||
|
||||
// Conversion des dates
|
||||
if (data.get("dateEmission") != null) {
|
||||
d.setDateEmission(LocalDate.parse(data.get("dateEmission").toString()));
|
||||
}
|
||||
if (data.get("dateValidite") != null) {
|
||||
d.setDateValidite(LocalDate.parse(data.get("dateValidite").toString()));
|
||||
}
|
||||
|
||||
d.setStatut((String) data.get("statut"));
|
||||
|
||||
// Montants
|
||||
Object montantHTObj = data.get("montantHT");
|
||||
if (montantHTObj != null) {
|
||||
d.setMontantHT(montantHTObj instanceof Number ?
|
||||
((Number) montantHTObj).doubleValue() :
|
||||
Double.parseDouble(montantHTObj.toString()));
|
||||
} else {
|
||||
d.setMontantHT(0.0);
|
||||
}
|
||||
|
||||
Object montantTTCObj = data.get("montantTTC");
|
||||
if (montantTTCObj != null) {
|
||||
d.setMontantTTC(montantTTCObj instanceof Number ?
|
||||
((Number) montantTTCObj).doubleValue() :
|
||||
Double.parseDouble(montantTTCObj.toString()));
|
||||
} else {
|
||||
d.setMontantTTC(0.0);
|
||||
}
|
||||
|
||||
if (data.get("dateCreation") != null) {
|
||||
d.setDateCreation(LocalDateTime.parse(data.get("dateCreation").toString()));
|
||||
}
|
||||
|
||||
items.add(d);
|
||||
}
|
||||
|
||||
LOG.info("Devis chargés depuis l'API : {} élément(s)", items.size());
|
||||
applyFilters(items, buildFilters());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur chargement devis depuis l'API", e);
|
||||
// En cas d'erreur, on garde une liste vide
|
||||
items = new ArrayList<>();
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Predicate<Devis>> buildFilters() {
|
||||
List<Predicate<Devis>> filters = new ArrayList<>();
|
||||
if (filtreNumero != null && !filtreNumero.trim().isEmpty()) {
|
||||
filters.add(d -> d.getNumero().toLowerCase().contains(filtreNumero.toLowerCase()));
|
||||
}
|
||||
if (filtreClient != null && !filtreClient.trim().isEmpty()) {
|
||||
filters.add(d -> d.getClient().toLowerCase().contains(filtreClient.toLowerCase()));
|
||||
}
|
||||
if (filtreStatut != null && !filtreStatut.trim().isEmpty() && !"TOUS".equals(filtreStatut)) {
|
||||
filters.add(d -> d.getStatut().equals(filtreStatut));
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetFilterFields() {
|
||||
filtreNumero = null;
|
||||
filtreClient = null;
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDetailsPath() {
|
||||
return "/devis/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreatePath() {
|
||||
return "/devis/nouveau";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performDelete() {
|
||||
LOG.info("Suppression devis : {}", selectedItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Devis createNewEntity() {
|
||||
Devis devis = new Devis();
|
||||
devis.setStatut("BROUILLON");
|
||||
devis.setDateEmission(LocalDate.now());
|
||||
devis.setDateValidite(LocalDate.now().plusDays(30));
|
||||
devis.setMontantHT(0.0);
|
||||
devis.setMontantTTC(0.0);
|
||||
devis.setDateCreation(LocalDateTime.now());
|
||||
return devis;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
if (selectedItem.getId() == null) {
|
||||
selectedItem.setId(System.currentTimeMillis());
|
||||
}
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Created: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
LOG.info("Updated: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Devis entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise un nouveau devis pour la création.
|
||||
*/
|
||||
@Override
|
||||
public String createNew() {
|
||||
selectedItem = new Devis();
|
||||
selectedItem.setStatut("BROUILLON");
|
||||
selectedItem.setDateEmission(LocalDate.now());
|
||||
selectedItem.setDateValidite(LocalDate.now().plusDays(30));
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde un nouveau devis.
|
||||
*/
|
||||
public String saveNew() {
|
||||
if (selectedItem == null) {
|
||||
selectedItem = new Devis();
|
||||
}
|
||||
selectedItem.setId(System.currentTimeMillis()); // Simulation ID
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Nouveau devis créé : {}", selectedItem.getNumero());
|
||||
return "/devis?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge un devis par son ID depuis les paramètres de la requête.
|
||||
*/
|
||||
public void loadDevisById() {
|
||||
if (devisId != null) {
|
||||
loadItems(); // S'assurer que les items sont chargés
|
||||
selectedItem = items.stream()
|
||||
.filter(d -> d.getId().equals(devisId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (selectedItem == null) {
|
||||
LOG.warn("Devis avec ID {} non trouvé", devisId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche les détails d'un devis.
|
||||
*/
|
||||
public String viewDetails(Long id) {
|
||||
selectedItem = items.stream()
|
||||
.filter(d -> d.getId().equals(id))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (selectedItem != null) {
|
||||
return getDetailsPath() + "details?id=" + id + "&faces-redirect=true";
|
||||
}
|
||||
return "/devis?faces-redirect=true";
|
||||
}
|
||||
|
||||
@lombok.Getter
|
||||
@lombok.Setter
|
||||
public static class Devis {
|
||||
private Long id;
|
||||
private String numero;
|
||||
private String objet;
|
||||
private String client;
|
||||
private LocalDate dateEmission;
|
||||
private LocalDate dateValidite;
|
||||
private String statut;
|
||||
private double montantHT;
|
||||
private double montantTTC;
|
||||
private LocalDateTime dateCreation;
|
||||
}
|
||||
}
|
||||
191
src/main/java/dev/lions/btpxpress/view/EmployeView.java
Normal file
191
src/main/java/dev/lions/btpxpress/view/EmployeView.java
Normal file
@@ -0,0 +1,191 @@
|
||||
package dev.lions.btpxpress.view;
|
||||
|
||||
import dev.lions.btpxpress.service.EmployeService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Named("employeView")
|
||||
@ViewScoped
|
||||
@Getter
|
||||
@Setter
|
||||
public class EmployeView extends BaseListView<EmployeView.Employe, Long> implements Serializable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EmployeView.class);
|
||||
|
||||
@Inject
|
||||
EmployeService employeService;
|
||||
|
||||
private String filtreNom;
|
||||
private String filtrePoste;
|
||||
private String filtreStatut;
|
||||
private Long employeId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (filtreStatut == null) {
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
loadItems();
|
||||
}
|
||||
|
||||
public void setFiltreStatut(String statut) {
|
||||
this.filtreStatut = statut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadItems() {
|
||||
loading = true;
|
||||
try {
|
||||
items = new ArrayList<>();
|
||||
|
||||
// Récupération depuis l'API backend
|
||||
List<Map<String, Object>> employesData = employeService.getAllEmployes();
|
||||
|
||||
for (Map<String, Object> data : employesData) {
|
||||
Employe e = new Employe();
|
||||
|
||||
e.setId(data.get("id") != null ? Long.valueOf(data.get("id").toString().hashCode()) : null);
|
||||
|
||||
String nom = (String) data.get("nom");
|
||||
String prenom = (String) data.get("prenom");
|
||||
e.setNomComplet((prenom != null ? prenom + " " : "") + (nom != null ? nom : ""));
|
||||
|
||||
e.setEmail((String) data.get("email"));
|
||||
e.setTelephone((String) data.get("telephone"));
|
||||
e.setPoste((String) data.get("poste"));
|
||||
e.setStatut((String) data.get("statut"));
|
||||
|
||||
// Taux horaire
|
||||
Object tauxObj = data.get("tauxHoraire");
|
||||
if (tauxObj != null) {
|
||||
e.setTauxHoraire(tauxObj instanceof Number ?
|
||||
((Number) tauxObj).doubleValue() :
|
||||
Double.parseDouble(tauxObj.toString()));
|
||||
} else {
|
||||
e.setTauxHoraire(0.0);
|
||||
}
|
||||
|
||||
// Date d'embauche
|
||||
if (data.get("dateEmbauche") != null) {
|
||||
e.setDateEmbauche(LocalDate.parse(data.get("dateEmbauche").toString()));
|
||||
}
|
||||
|
||||
if (data.get("dateCreation") != null) {
|
||||
e.setDateCreation(LocalDateTime.parse(data.get("dateCreation").toString()));
|
||||
}
|
||||
|
||||
items.add(e);
|
||||
}
|
||||
|
||||
LOG.info("Employés chargés depuis l'API : {} élément(s)", items.size());
|
||||
applyFilters(items, buildFilters());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur chargement employés depuis l'API", e);
|
||||
items = new ArrayList<>();
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Predicate<Employe>> buildFilters() {
|
||||
List<Predicate<Employe>> filters = new ArrayList<>();
|
||||
if (filtreNom != null && !filtreNom.trim().isEmpty()) {
|
||||
filters.add(e -> e.getNomComplet().toLowerCase().contains(filtreNom.toLowerCase()));
|
||||
}
|
||||
if (filtrePoste != null && !filtrePoste.trim().isEmpty()) {
|
||||
filters.add(e -> e.getPoste() != null && e.getPoste().toLowerCase().contains(filtrePoste.toLowerCase()));
|
||||
}
|
||||
if (filtreStatut != null && !filtreStatut.trim().isEmpty() && !"TOUS".equals(filtreStatut)) {
|
||||
filters.add(e -> e.getStatut().equals(filtreStatut));
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetFilterFields() {
|
||||
filtreNom = null;
|
||||
filtrePoste = null;
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDetailsPath() {
|
||||
return "/employes/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreatePath() {
|
||||
return "/employes/nouveau";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performDelete() {
|
||||
LOG.info("Suppression employé : {}", selectedItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Employe createNewEntity() {
|
||||
Employe employe = new Employe();
|
||||
employe.setStatut("ACTIF");
|
||||
employe.setDateEmbauche(LocalDate.now());
|
||||
employe.setTauxHoraire(0.0);
|
||||
employe.setDateCreation(LocalDateTime.now());
|
||||
return employe;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
if (selectedItem.getId() == null) {
|
||||
selectedItem.setId(System.currentTimeMillis());
|
||||
}
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Created: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
LOG.info("Updated: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Employe entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createNew() {
|
||||
selectedItem = new Employe();
|
||||
selectedItem.setStatut("ACTIF");
|
||||
selectedItem.setDateEmbauche(LocalDate.now());
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
@lombok.Getter
|
||||
@lombok.Setter
|
||||
public static class Employe {
|
||||
private Long id;
|
||||
private String nomComplet;
|
||||
private String email;
|
||||
private String telephone;
|
||||
private String poste;
|
||||
private String statut;
|
||||
private double tauxHoraire;
|
||||
private LocalDate dateEmbauche;
|
||||
private LocalDateTime dateCreation;
|
||||
}
|
||||
}
|
||||
187
src/main/java/dev/lions/btpxpress/view/EquipeView.java
Normal file
187
src/main/java/dev/lions/btpxpress/view/EquipeView.java
Normal file
@@ -0,0 +1,187 @@
|
||||
package dev.lions.btpxpress.view;
|
||||
|
||||
import dev.lions.btpxpress.service.EquipeService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Named("equipeView")
|
||||
@ViewScoped
|
||||
@Getter
|
||||
@Setter
|
||||
public class EquipeView extends BaseListView<EquipeView.Equipe, Long> implements Serializable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EquipeView.class);
|
||||
|
||||
@Inject
|
||||
EquipeService equipeService;
|
||||
|
||||
private String filtreNom;
|
||||
private String filtreSpecialite;
|
||||
private String filtreStatut;
|
||||
private Long equipeId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (filtreStatut == null) {
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
loadItems();
|
||||
}
|
||||
|
||||
public void setFiltreStatut(String statut) {
|
||||
this.filtreStatut = statut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadItems() {
|
||||
loading = true;
|
||||
try {
|
||||
items = new ArrayList<>();
|
||||
|
||||
// Récupération depuis l'API backend
|
||||
List<Map<String, Object>> equipesData = equipeService.getAllEquipes();
|
||||
|
||||
for (Map<String, Object> data : equipesData) {
|
||||
Equipe eq = new Equipe();
|
||||
|
||||
eq.setId(data.get("id") != null ? Long.valueOf(data.get("id").toString().hashCode()) : null);
|
||||
eq.setNom((String) data.get("nom"));
|
||||
eq.setDescription((String) data.get("description"));
|
||||
eq.setSpecialite((String) data.get("specialite"));
|
||||
eq.setStatut((String) data.get("statut"));
|
||||
|
||||
// Chef d'équipe
|
||||
Object chefObj = data.get("chef");
|
||||
if (chefObj instanceof Map) {
|
||||
Map<String, Object> chefData = (Map<String, Object>) chefObj;
|
||||
String prenom = (String) chefData.get("prenom");
|
||||
String nom = (String) chefData.get("nom");
|
||||
eq.setChef((prenom != null ? prenom + " " : "") + (nom != null ? nom : ""));
|
||||
} else {
|
||||
eq.setChef("N/A");
|
||||
}
|
||||
|
||||
// Nombre de membres
|
||||
Object membresObj = data.get("membres");
|
||||
if (membresObj instanceof List) {
|
||||
eq.setNombreMembres(((List<?>) membresObj).size());
|
||||
} else {
|
||||
eq.setNombreMembres(0);
|
||||
}
|
||||
|
||||
if (data.get("dateCreation") != null) {
|
||||
eq.setDateCreation(LocalDateTime.parse(data.get("dateCreation").toString()));
|
||||
}
|
||||
|
||||
items.add(eq);
|
||||
}
|
||||
|
||||
LOG.info("Équipes chargées depuis l'API : {} élément(s)", items.size());
|
||||
applyFilters(items, buildFilters());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur chargement équipes depuis l'API", e);
|
||||
items = new ArrayList<>();
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Predicate<Equipe>> buildFilters() {
|
||||
List<Predicate<Equipe>> filters = new ArrayList<>();
|
||||
if (filtreNom != null && !filtreNom.trim().isEmpty()) {
|
||||
filters.add(e -> e.getNom().toLowerCase().contains(filtreNom.toLowerCase()));
|
||||
}
|
||||
if (filtreSpecialite != null && !filtreSpecialite.trim().isEmpty()) {
|
||||
filters.add(e -> e.getSpecialite() != null &&
|
||||
e.getSpecialite().toLowerCase().contains(filtreSpecialite.toLowerCase()));
|
||||
}
|
||||
if (filtreStatut != null && !filtreStatut.trim().isEmpty() && !"TOUS".equals(filtreStatut)) {
|
||||
filters.add(e -> e.getStatut().equals(filtreStatut));
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetFilterFields() {
|
||||
filtreNom = null;
|
||||
filtreSpecialite = null;
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDetailsPath() {
|
||||
return "/equipes/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreatePath() {
|
||||
return "/equipes/nouvelle";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performDelete() {
|
||||
LOG.info("Suppression équipe : {}", selectedItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Equipe createNewEntity() {
|
||||
Equipe equipe = new Equipe();
|
||||
equipe.setStatut("ACTIVE");
|
||||
equipe.setNombreMembres(0);
|
||||
equipe.setDateCreation(LocalDateTime.now());
|
||||
return equipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
if (selectedItem.getId() == null) {
|
||||
selectedItem.setId(System.currentTimeMillis());
|
||||
}
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Created: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
LOG.info("Updated: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Equipe entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createNew() {
|
||||
selectedItem = new Equipe();
|
||||
selectedItem.setStatut("ACTIVE");
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
@lombok.Getter
|
||||
@lombok.Setter
|
||||
public static class Equipe {
|
||||
private Long id;
|
||||
private String nom;
|
||||
private String description;
|
||||
private String chef;
|
||||
private String specialite;
|
||||
private String statut;
|
||||
private int nombreMembres;
|
||||
private LocalDateTime dateCreation;
|
||||
}
|
||||
}
|
||||
300
src/main/java/dev/lions/btpxpress/view/FactureView.java
Normal file
300
src/main/java/dev/lions/btpxpress/view/FactureView.java
Normal file
@@ -0,0 +1,300 @@
|
||||
package dev.lions.btpxpress.view;
|
||||
|
||||
import dev.lions.btpxpress.service.FactureService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Named("factureView")
|
||||
@ViewScoped
|
||||
@Getter
|
||||
@Setter
|
||||
public class FactureView extends BaseListView<FactureView.Facture, Long> implements Serializable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FactureView.class);
|
||||
|
||||
@Inject
|
||||
FactureService factureService;
|
||||
|
||||
private String filtreNumero;
|
||||
private String filtreClient;
|
||||
private String filtreStatut;
|
||||
private Long factureId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (filtreStatut == null) {
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
loadItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Définit le filtre de statut (utilisé depuis les pages filtrées).
|
||||
*/
|
||||
public void setFiltreStatut(String statut) {
|
||||
this.filtreStatut = statut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadItems() {
|
||||
loading = true;
|
||||
try {
|
||||
items = new ArrayList<>();
|
||||
|
||||
// Récupération depuis l'API backend
|
||||
List<Map<String, Object>> facturesData = factureService.getAllFactures();
|
||||
|
||||
for (Map<String, Object> data : facturesData) {
|
||||
Facture f = new Facture();
|
||||
|
||||
// Mapping des données de l'API vers l'objet Facture
|
||||
f.setId(data.get("id") != null ? Long.valueOf(data.get("id").toString().hashCode()) : null);
|
||||
f.setNumero((String) data.get("numero"));
|
||||
f.setObjet((String) data.get("objet"));
|
||||
|
||||
// Le client peut être un objet ou une chaîne
|
||||
Object clientObj = data.get("client");
|
||||
if (clientObj instanceof Map) {
|
||||
Map<String, Object> clientData = (Map<String, Object>) clientObj;
|
||||
String entreprise = (String) clientData.get("entreprise");
|
||||
String nom = (String) clientData.get("nom");
|
||||
String prenom = (String) clientData.get("prenom");
|
||||
f.setClient(entreprise != null && !entreprise.trim().isEmpty() ?
|
||||
entreprise : (prenom != null ? prenom + " " : "") + (nom != null ? nom : ""));
|
||||
} else if (clientObj instanceof String) {
|
||||
f.setClient((String) clientObj);
|
||||
} else {
|
||||
f.setClient("N/A");
|
||||
}
|
||||
|
||||
// Conversion des dates
|
||||
if (data.get("dateEmission") != null) {
|
||||
f.setDateEmission(LocalDate.parse(data.get("dateEmission").toString()));
|
||||
}
|
||||
if (data.get("dateEcheance") != null) {
|
||||
f.setDateEcheance(LocalDate.parse(data.get("dateEcheance").toString()));
|
||||
}
|
||||
if (data.get("datePaiement") != null) {
|
||||
f.setDatePaiement(LocalDate.parse(data.get("datePaiement").toString()));
|
||||
}
|
||||
|
||||
f.setStatut((String) data.get("statut"));
|
||||
|
||||
// Montants
|
||||
Object montantHTObj = data.get("montantHT");
|
||||
if (montantHTObj != null) {
|
||||
f.setMontantHT(montantHTObj instanceof Number ?
|
||||
((Number) montantHTObj).doubleValue() :
|
||||
Double.parseDouble(montantHTObj.toString()));
|
||||
} else {
|
||||
f.setMontantHT(0.0);
|
||||
}
|
||||
|
||||
Object montantTTCObj = data.get("montantTTC");
|
||||
if (montantTTCObj != null) {
|
||||
f.setMontantTTC(montantTTCObj instanceof Number ?
|
||||
((Number) montantTTCObj).doubleValue() :
|
||||
Double.parseDouble(montantTTCObj.toString()));
|
||||
} else {
|
||||
f.setMontantTTC(0.0);
|
||||
}
|
||||
|
||||
Object montantPayeObj = data.get("montantPaye");
|
||||
if (montantPayeObj != null) {
|
||||
f.setMontantPaye(montantPayeObj instanceof Number ?
|
||||
((Number) montantPayeObj).doubleValue() :
|
||||
Double.parseDouble(montantPayeObj.toString()));
|
||||
} else {
|
||||
f.setMontantPaye(0.0);
|
||||
}
|
||||
|
||||
if (data.get("dateCreation") != null) {
|
||||
f.setDateCreation(LocalDateTime.parse(data.get("dateCreation").toString()));
|
||||
}
|
||||
|
||||
items.add(f);
|
||||
}
|
||||
|
||||
LOG.info("Factures chargées depuis l'API : {} élément(s)", items.size());
|
||||
applyFilters(items, buildFilters());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur chargement factures depuis l'API", e);
|
||||
// En cas d'erreur, on garde une liste vide
|
||||
items = new ArrayList<>();
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Predicate<Facture>> buildFilters() {
|
||||
List<Predicate<Facture>> filters = new ArrayList<>();
|
||||
if (filtreNumero != null && !filtreNumero.trim().isEmpty()) {
|
||||
filters.add(f -> f.getNumero().toLowerCase().contains(filtreNumero.toLowerCase()));
|
||||
}
|
||||
if (filtreClient != null && !filtreClient.trim().isEmpty()) {
|
||||
filters.add(f -> f.getClient().toLowerCase().contains(filtreClient.toLowerCase()));
|
||||
}
|
||||
if (filtreStatut != null && !filtreStatut.trim().isEmpty() && !"TOUS".equals(filtreStatut)) {
|
||||
filters.add(f -> f.getStatut().equals(filtreStatut));
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetFilterFields() {
|
||||
filtreNumero = null;
|
||||
filtreClient = null;
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDetailsPath() {
|
||||
return "/factures/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreatePath() {
|
||||
return "/factures/nouvelle";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performDelete() {
|
||||
LOG.info("Suppression facture : {}", selectedItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Facture createNewEntity() {
|
||||
Facture facture = new Facture();
|
||||
facture.setStatut("BROUILLON");
|
||||
facture.setDateEmission(LocalDate.now());
|
||||
facture.setDateEcheance(LocalDate.now().plusDays(30));
|
||||
facture.setMontantHT(0.0);
|
||||
facture.setMontantTTC(0.0);
|
||||
facture.setMontantPaye(0.0);
|
||||
facture.setDateCreation(LocalDateTime.now());
|
||||
return facture;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
if (selectedItem.getId() == null) {
|
||||
selectedItem.setId(System.currentTimeMillis());
|
||||
}
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Created: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
LOG.info("Updated: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Facture entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise une nouvelle facture pour la création.
|
||||
*/
|
||||
@Override
|
||||
public String createNew() {
|
||||
selectedItem = new Facture();
|
||||
selectedItem.setStatut("BROUILLON");
|
||||
selectedItem.setDateEmission(LocalDate.now());
|
||||
selectedItem.setDateEcheance(LocalDate.now().plusDays(30));
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde une nouvelle facture.
|
||||
*/
|
||||
public String saveNew() {
|
||||
if (selectedItem == null) {
|
||||
selectedItem = new Facture();
|
||||
}
|
||||
selectedItem.setId(System.currentTimeMillis()); // Simulation ID
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Nouvelle facture créée : {}", selectedItem.getNumero());
|
||||
return "/factures?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge une facture par son ID depuis les paramètres de la requête.
|
||||
*/
|
||||
public void loadFactureById() {
|
||||
if (factureId != null) {
|
||||
loadItems(); // S'assurer que les items sont chargés
|
||||
selectedItem = items.stream()
|
||||
.filter(f -> f.getId().equals(factureId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (selectedItem == null) {
|
||||
LOG.warn("Facture avec ID {} non trouvé", factureId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche les détails d'une facture.
|
||||
*/
|
||||
public String viewDetails(Long id) {
|
||||
selectedItem = items.stream()
|
||||
.filter(f -> f.getId().equals(id))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (selectedItem != null) {
|
||||
return getDetailsPath() + "details?id=" + id + "&faces-redirect=true";
|
||||
}
|
||||
return "/factures?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le montant restant à payer.
|
||||
*/
|
||||
public double getMontantRestant(Facture facture) {
|
||||
return facture.getMontantTTC() - facture.getMontantPaye();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si une facture est en retard.
|
||||
*/
|
||||
public boolean isEnRetard(Facture facture) {
|
||||
return facture.getDateEcheance() != null &&
|
||||
facture.getDateEcheance().isBefore(LocalDate.now()) &&
|
||||
!"PAYEE".equals(facture.getStatut());
|
||||
}
|
||||
|
||||
@lombok.Getter
|
||||
@lombok.Setter
|
||||
public static class Facture {
|
||||
private Long id;
|
||||
private String numero;
|
||||
private String objet;
|
||||
private String client;
|
||||
private LocalDate dateEmission;
|
||||
private LocalDate dateEcheance;
|
||||
private LocalDate datePaiement;
|
||||
private String statut;
|
||||
private double montantHT;
|
||||
private double montantTTC;
|
||||
private double montantPaye;
|
||||
private LocalDateTime dateCreation;
|
||||
}
|
||||
}
|
||||
189
src/main/java/dev/lions/btpxpress/view/MaterielView.java
Normal file
189
src/main/java/dev/lions/btpxpress/view/MaterielView.java
Normal file
@@ -0,0 +1,189 @@
|
||||
package dev.lions.btpxpress.view;
|
||||
|
||||
import dev.lions.btpxpress.service.MaterielService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Named("materielView")
|
||||
@ViewScoped
|
||||
@Getter
|
||||
@Setter
|
||||
public class MaterielView extends BaseListView<MaterielView.Materiel, Long> implements Serializable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MaterielView.class);
|
||||
|
||||
@Inject
|
||||
MaterielService materielService;
|
||||
|
||||
private String filtreNom;
|
||||
private String filtreType;
|
||||
private String filtreStatut;
|
||||
private Long materielId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (filtreStatut == null) {
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
loadItems();
|
||||
}
|
||||
|
||||
public void setFiltreStatut(String statut) {
|
||||
this.filtreStatut = statut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadItems() {
|
||||
loading = true;
|
||||
try {
|
||||
items = new ArrayList<>();
|
||||
|
||||
// Récupération depuis l'API backend
|
||||
List<Map<String, Object>> materielsData = materielService.getAllMateriels();
|
||||
|
||||
for (Map<String, Object> data : materielsData) {
|
||||
Materiel m = new Materiel();
|
||||
|
||||
m.setId(data.get("id") != null ? Long.valueOf(data.get("id").toString().hashCode()) : null);
|
||||
m.setNom((String) data.get("nom"));
|
||||
m.setMarque((String) data.get("marque"));
|
||||
m.setModele((String) data.get("modele"));
|
||||
m.setNumeroSerie((String) data.get("numeroSerie"));
|
||||
m.setType((String) data.get("type"));
|
||||
m.setStatut((String) data.get("statut"));
|
||||
|
||||
// Valeur d'achat
|
||||
Object valeurObj = data.get("valeurAchat");
|
||||
if (valeurObj != null) {
|
||||
m.setValeurAchat(valeurObj instanceof Number ?
|
||||
((Number) valeurObj).doubleValue() :
|
||||
Double.parseDouble(valeurObj.toString()));
|
||||
} else {
|
||||
m.setValeurAchat(0.0);
|
||||
}
|
||||
|
||||
// Date d'achat
|
||||
if (data.get("dateAchat") != null) {
|
||||
m.setDateAchat(LocalDate.parse(data.get("dateAchat").toString()));
|
||||
}
|
||||
|
||||
if (data.get("dateCreation") != null) {
|
||||
m.setDateCreation(LocalDateTime.parse(data.get("dateCreation").toString()));
|
||||
}
|
||||
|
||||
items.add(m);
|
||||
}
|
||||
|
||||
LOG.info("Matériels chargés depuis l'API : {} élément(s)", items.size());
|
||||
applyFilters(items, buildFilters());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur chargement matériels depuis l'API", e);
|
||||
items = new ArrayList<>();
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Predicate<Materiel>> buildFilters() {
|
||||
List<Predicate<Materiel>> filters = new ArrayList<>();
|
||||
if (filtreNom != null && !filtreNom.trim().isEmpty()) {
|
||||
filters.add(m -> m.getNom().toLowerCase().contains(filtreNom.toLowerCase()));
|
||||
}
|
||||
if (filtreType != null && !filtreType.trim().isEmpty() && !"TOUS".equals(filtreType)) {
|
||||
filters.add(m -> m.getType() != null && m.getType().equals(filtreType));
|
||||
}
|
||||
if (filtreStatut != null && !filtreStatut.trim().isEmpty() && !"TOUS".equals(filtreStatut)) {
|
||||
filters.add(m -> m.getStatut().equals(filtreStatut));
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetFilterFields() {
|
||||
filtreNom = null;
|
||||
filtreType = "TOUS";
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDetailsPath() {
|
||||
return "/materiels/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreatePath() {
|
||||
return "/materiels/nouveau";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performDelete() {
|
||||
LOG.info("Suppression matériel : {}", selectedItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Materiel createNewEntity() {
|
||||
Materiel materiel = new Materiel();
|
||||
materiel.setStatut("DISPONIBLE");
|
||||
materiel.setDateAchat(LocalDate.now());
|
||||
materiel.setValeurAchat(0.0);
|
||||
materiel.setDateCreation(LocalDateTime.now());
|
||||
return materiel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
if (selectedItem.getId() == null) {
|
||||
selectedItem.setId(System.currentTimeMillis());
|
||||
}
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Created: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
LOG.info("Updated: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Materiel entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createNew() {
|
||||
selectedItem = new Materiel();
|
||||
selectedItem.setStatut("DISPONIBLE");
|
||||
selectedItem.setDateAchat(LocalDate.now());
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
@lombok.Getter
|
||||
@lombok.Setter
|
||||
public static class Materiel {
|
||||
private Long id;
|
||||
private String nom;
|
||||
private String marque;
|
||||
private String modele;
|
||||
private String numeroSerie;
|
||||
private String type;
|
||||
private String statut;
|
||||
private double valeurAchat;
|
||||
private LocalDate dateAchat;
|
||||
private LocalDateTime dateCreation;
|
||||
}
|
||||
}
|
||||
223
src/main/java/dev/lions/btpxpress/view/StockView.java
Normal file
223
src/main/java/dev/lions/btpxpress/view/StockView.java
Normal file
@@ -0,0 +1,223 @@
|
||||
package dev.lions.btpxpress.view;
|
||||
|
||||
import dev.lions.btpxpress.service.StockService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Named("stockView")
|
||||
@ViewScoped
|
||||
@Getter
|
||||
@Setter
|
||||
public class StockView extends BaseListView<StockView.Stock, Long> implements Serializable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StockView.class);
|
||||
|
||||
@Inject
|
||||
StockService stockService;
|
||||
|
||||
private String filtreReference;
|
||||
private String filtreDesignation;
|
||||
private String filtreCategorie;
|
||||
private String filtreStatut;
|
||||
private Long stockId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (filtreStatut == null) {
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
if (filtreCategorie == null) {
|
||||
filtreCategorie = "TOUS";
|
||||
}
|
||||
loadItems();
|
||||
}
|
||||
|
||||
public void setFiltreStatut(String statut) {
|
||||
this.filtreStatut = statut;
|
||||
}
|
||||
|
||||
public void setFiltreCategorie(String categorie) {
|
||||
this.filtreCategorie = categorie;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadItems() {
|
||||
loading = true;
|
||||
try {
|
||||
items = new ArrayList<>();
|
||||
|
||||
// Récupération depuis l'API backend
|
||||
List<Map<String, Object>> stocksData = stockService.getAllStocks();
|
||||
|
||||
for (Map<String, Object> data : stocksData) {
|
||||
Stock s = new Stock();
|
||||
|
||||
s.setId(data.get("id") != null ? Long.valueOf(data.get("id").toString().hashCode()) : null);
|
||||
s.setReference((String) data.get("reference"));
|
||||
s.setDesignation((String) data.get("designation"));
|
||||
s.setCategorie((String) data.get("categorie"));
|
||||
s.setUniteMesure((String) data.get("uniteMesure"));
|
||||
s.setStatut((String) data.get("statut"));
|
||||
|
||||
// Quantité disponible
|
||||
Object qteObj = data.get("quantiteDisponible");
|
||||
if (qteObj != null) {
|
||||
s.setQuantiteDisponible(qteObj instanceof Number ?
|
||||
((Number) qteObj).doubleValue() :
|
||||
Double.parseDouble(qteObj.toString()));
|
||||
} else {
|
||||
s.setQuantiteDisponible(0.0);
|
||||
}
|
||||
|
||||
// Seuil d'alerte
|
||||
Object seuilObj = data.get("seuilAlerte");
|
||||
if (seuilObj != null) {
|
||||
s.setSeuilAlerte(seuilObj instanceof Number ?
|
||||
((Number) seuilObj).doubleValue() :
|
||||
Double.parseDouble(seuilObj.toString()));
|
||||
} else {
|
||||
s.setSeuilAlerte(0.0);
|
||||
}
|
||||
|
||||
// Prix unitaire
|
||||
Object prixObj = data.get("prixUnitaire");
|
||||
if (prixObj != null) {
|
||||
s.setPrixUnitaire(prixObj instanceof Number ?
|
||||
((Number) prixObj).doubleValue() :
|
||||
Double.parseDouble(prixObj.toString()));
|
||||
} else {
|
||||
s.setPrixUnitaire(0.0);
|
||||
}
|
||||
|
||||
if (data.get("dateCreation") != null) {
|
||||
s.setDateCreation(LocalDateTime.parse(data.get("dateCreation").toString()));
|
||||
}
|
||||
|
||||
items.add(s);
|
||||
}
|
||||
|
||||
LOG.info("Stocks chargés depuis l'API : {} élément(s)", items.size());
|
||||
applyFilters(items, buildFilters());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Erreur chargement stocks depuis l'API", e);
|
||||
items = new ArrayList<>();
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Predicate<Stock>> buildFilters() {
|
||||
List<Predicate<Stock>> filters = new ArrayList<>();
|
||||
if (filtreReference != null && !filtreReference.trim().isEmpty()) {
|
||||
filters.add(s -> s.getReference() != null &&
|
||||
s.getReference().toLowerCase().contains(filtreReference.toLowerCase()));
|
||||
}
|
||||
if (filtreDesignation != null && !filtreDesignation.trim().isEmpty()) {
|
||||
filters.add(s -> s.getDesignation() != null &&
|
||||
s.getDesignation().toLowerCase().contains(filtreDesignation.toLowerCase()));
|
||||
}
|
||||
if (filtreCategorie != null && !filtreCategorie.trim().isEmpty() && !"TOUS".equals(filtreCategorie)) {
|
||||
filters.add(s -> s.getCategorie() != null && s.getCategorie().equals(filtreCategorie));
|
||||
}
|
||||
if (filtreStatut != null && !filtreStatut.trim().isEmpty() && !"TOUS".equals(filtreStatut)) {
|
||||
filters.add(s -> s.getStatut() != null && s.getStatut().equals(filtreStatut));
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetFilterFields() {
|
||||
filtreReference = null;
|
||||
filtreDesignation = null;
|
||||
filtreCategorie = "TOUS";
|
||||
filtreStatut = "TOUS";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDetailsPath() {
|
||||
return "/stock/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreatePath() {
|
||||
return "/stock/nouveau";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performDelete() {
|
||||
LOG.info("Suppression stock : {}", selectedItem.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stock createNewEntity() {
|
||||
Stock stock = new Stock();
|
||||
stock.setStatut("DISPONIBLE");
|
||||
stock.setQuantiteDisponible(0.0);
|
||||
stock.setSeuilAlerte(0.0);
|
||||
stock.setPrixUnitaire(0.0);
|
||||
stock.setDateCreation(LocalDateTime.now());
|
||||
return stock;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCreate() {
|
||||
if (selectedItem.getId() == null) {
|
||||
selectedItem.setId(System.currentTimeMillis());
|
||||
}
|
||||
selectedItem.setDateCreation(LocalDateTime.now());
|
||||
items.add(selectedItem);
|
||||
LOG.info("Created: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performUpdate() {
|
||||
LOG.info("Updated: {}", selectedItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getEntityId(Stock entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createNew() {
|
||||
selectedItem = new Stock();
|
||||
selectedItem.setStatut("DISPONIBLE");
|
||||
return getCreatePath() + "?faces-redirect=true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si un stock est en alerte (quantité < seuil)
|
||||
*/
|
||||
public boolean isEnAlerte(Stock stock) {
|
||||
return stock.getQuantiteDisponible() < stock.getSeuilAlerte();
|
||||
}
|
||||
|
||||
@lombok.Getter
|
||||
@lombok.Setter
|
||||
public static class Stock {
|
||||
private Long id;
|
||||
private String reference;
|
||||
private String designation;
|
||||
private String categorie;
|
||||
private String uniteMesure;
|
||||
private String statut;
|
||||
private double quantiteDisponible;
|
||||
private double seuilAlerte;
|
||||
private double prixUnitaire;
|
||||
private LocalDateTime dateCreation;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user