Files
btpxpress-backend/src/main/java/dev/lions/btpxpress/application/service/ClientService.java
2025-10-01 01:37:34 +00:00

304 lines
11 KiB
Java

package dev.lions.btpxpress.application.service;
import dev.lions.btpxpress.domain.core.entity.Chantier;
import dev.lions.btpxpress.domain.core.entity.Client;
import dev.lions.btpxpress.domain.core.entity.TypeClient;
import dev.lions.btpxpress.domain.infrastructure.repository.ClientRepository;
import dev.lions.btpxpress.domain.shared.dto.ClientCreateDTO;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.validation.Valid;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotFoundException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Service de gestion des clients - Architecture 2025 MIGRATION: Préservation exacte de toutes les
* logiques de validation et recherche
*/
@ApplicationScoped
public class ClientService {
private static final Logger logger = LoggerFactory.getLogger(ClientService.class);
@Inject ClientRepository clientRepository;
// === MÉTHODES DE RECHERCHE - PRÉSERVÉES EXACTEMENT ===
public List<Client> findAll() {
logger.debug("Recherche de tous les clients actifs");
return clientRepository.findActifs();
}
public List<Client> findAll(int page, int size) {
logger.debug("Recherche des clients actifs - page: {}, taille: {}", page, size);
return clientRepository.findActifs(page, size);
}
public Optional<Client> findById(UUID id) {
logger.debug("Recherche du client avec l'ID: {}", id);
return clientRepository.findByIdOptional(id);
}
public Client findByIdRequired(UUID id) {
return findById(id)
.orElseThrow(() -> new NotFoundException("Client non trouvé avec l'ID: " + id));
}
public Optional<Client> findByEmail(String email) {
logger.debug("Recherche du client avec l'email: {}", email);
return clientRepository.findByEmail(email);
}
public List<Client> searchByNom(String nom) {
logger.debug("Recherche des clients par nom: {}", nom);
return clientRepository.findByNomContaining(nom);
}
public List<Client> findByEntreprise(String entreprise) {
logger.debug("Recherche des clients par entreprise: {}", entreprise);
return clientRepository.findByEntreprise(entreprise);
}
public List<Client> searchByEntreprise(String entreprise) {
logger.debug("Recherche des clients par entreprise: {}", entreprise);
return clientRepository.findByEntreprise(entreprise);
}
public List<Client> findByVille(String ville) {
logger.debug("Recherche des clients par ville: {}", ville);
return clientRepository.findByVille(ville);
}
public List<Client> findByCodePostal(String codePostal) {
logger.debug("Recherche des clients par code postal: {}", codePostal);
return clientRepository.findByCodePostal(codePostal);
}
public List<Client> findProfessionnels() {
logger.debug("Recherche des clients professionnels");
return clientRepository.findByType(TypeClient.PROFESSIONNEL);
}
public List<Client> findParticuliers() {
logger.debug("Recherche des clients particuliers");
return clientRepository.findByType(TypeClient.PARTICULIER);
}
public List<Client> findCreesRecemment(int jours) {
logger.debug("Recherche des clients créés récemment: {} jours", jours);
return clientRepository.findCreesRecemment(jours);
}
public List<Client> searchClients(String query) {
logger.debug("Recherche de clients: {}", query);
return clientRepository.findByNomContaining(query);
}
public Map<String, Object> getStatistiques() {
logger.debug("Calcul des statistiques clients");
Map<String, Object> stats = new HashMap<>();
stats.put("total", count());
stats.put("professionnels", findProfessionnels().size());
stats.put("particuliers", findParticuliers().size());
stats.put("nouveaux", findCreesRecemment(30).size());
return stats;
}
public List<Map<String, Object>> getHistoriqueChantiers(UUID clientId) {
logger.debug("Historique des chantiers pour le client: {}", clientId);
// Conversion des chantiers en Map pour l'API
List<Chantier> chantiers = clientRepository.getHistoriqueChantiers(clientId);
List<Map<String, Object>> historique = new ArrayList<>();
for (Chantier chantier : chantiers) {
Map<String, Object> chantierMap = new HashMap<>();
chantierMap.put("id", chantier.getId());
chantierMap.put("nom", chantier.getNom());
chantierMap.put("statut", chantier.getStatut());
chantierMap.put("dateDebut", chantier.getDateDebut());
chantierMap.put("dateFin", chantier.getDateFinPrevue());
chantierMap.put("montant", chantier.getMontantPrevu());
historique.add(chantierMap);
}
return historique;
}
public Map<String, Object> getDashboardClient(UUID id) {
logger.debug("Dashboard du client: {}", id);
Client client = findByIdRequired(id);
// Récupération des statistiques via le repository
Map<String, Object> stats = clientRepository.getClientStatistics(id);
Map<String, Object> dashboard = new HashMap<>();
dashboard.put("client", client);
dashboard.put("chantiersTotal", stats.getOrDefault("chantiersTotal", 0));
dashboard.put("chantiersEnCours", stats.getOrDefault("chantiersEnCours", 0));
dashboard.put(
"chiffreAffairesTotal", stats.getOrDefault("chiffreAffairesTotal", BigDecimal.ZERO));
dashboard.put("devisEnAttente", stats.getOrDefault("devisEnAttente", 0));
dashboard.put("facturesImpayees", stats.getOrDefault("facturesImpayees", 0));
dashboard.put("derniereActivite", stats.getOrDefault("derniereActivite", null));
return dashboard;
}
public List<Client> searchByVille(String ville) {
logger.debug("Recherche des clients par ville: {}", ville);
return clientRepository.findByVille(ville);
}
// === MÉTHODES CRUD - LOGIQUES CRITIQUES PRÉSERVÉES ===
@Transactional
public Client create(@Valid Client client) {
logger.info("Création d'un nouveau client: {} {}", client.getPrenom(), client.getNom());
// Vérifications métier - LOGIQUE CRITIQUE PRÉSERVÉE
validateClient(client);
// Vérifier l'unicité de l'email - LOGIQUE CRITIQUE PRÉSERVÉE
if (client.getEmail() != null && clientRepository.existsByEmail(client.getEmail())) {
throw new BadRequestException("Un client avec cet email existe déjà");
}
// Vérifier l'unicité du SIRET - LOGIQUE CRITIQUE PRÉSERVÉE
if (client.getSiret() != null && clientRepository.existsBySiret(client.getSiret())) {
throw new BadRequestException("Un client avec ce SIRET existe déjà");
}
clientRepository.persist(client);
logger.info("Client créé avec succès avec l'ID: {}", client.getId());
return client;
}
@Transactional
public Client createFromDTO(@Valid ClientCreateDTO dto) {
logger.info("Création d'un nouveau client depuis DTO: {} {}", dto.getPrenom(), dto.getNom());
try {
// Créer l'entité Client - LOGIQUE EXACTE PRÉSERVÉE
Client client = new Client();
client.setNom(dto.getNom());
client.setPrenom(dto.getPrenom());
client.setEntreprise(dto.getEntreprise());
client.setEmail(dto.getEmail());
client.setTelephone(dto.getTelephone());
client.setAdresse(dto.getAdresse());
client.setCodePostal(dto.getCodePostal());
client.setVille(dto.getVille());
client.setSiret(dto.getSiret());
client.setNumeroTVA(dto.getNumeroTVA());
client.setActif(dto.getActif() != null ? dto.getActif() : true);
// Utiliser la méthode create existante
return create(client);
} catch (Exception e) {
logger.error("Erreur lors de la création du client: {}", e.getMessage(), e);
throw e;
}
}
@Transactional
public Client update(UUID id, @Valid Client clientData) {
logger.info("Mise à jour du client avec l'ID: {}", id);
Client existingClient = findByIdRequired(id);
// Vérifications métier - LOGIQUE CRITIQUE PRÉSERVÉE
validateClient(clientData);
// Vérifier l'unicité de l'email (si changé) - LOGIQUE CRITIQUE PRÉSERVÉE
if (clientData.getEmail() != null && !clientData.getEmail().equals(existingClient.getEmail())) {
if (clientRepository.existsByEmail(clientData.getEmail())) {
throw new BadRequestException("Un client avec cet email existe déjà");
}
}
// Vérifier l'unicité du SIRET (si changé) - LOGIQUE CRITIQUE PRÉSERVÉE
if (clientData.getSiret() != null && !clientData.getSiret().equals(existingClient.getSiret())) {
if (clientRepository.existsBySiret(clientData.getSiret())) {
throw new BadRequestException("Un client avec ce SIRET existe déjà");
}
}
// Mise à jour des champs
updateClientFields(existingClient, clientData);
existingClient.setDateModification(LocalDateTime.now());
clientRepository.persist(existingClient);
logger.info("Client mis à jour avec succès");
return existingClient;
}
@Transactional
public void delete(UUID id) {
logger.info("Suppression logique du client avec l'ID: {}", id);
Client client = findByIdRequired(id);
clientRepository.softDelete(id);
logger.info("Client supprimé avec succès");
}
@Transactional
public void deleteByEmail(String email) {
logger.info("Suppression logique du client avec l'email: {}", email);
Client client =
findByEmail(email)
.orElseThrow(() -> new NotFoundException("Client non trouvé avec l'email: " + email));
clientRepository.softDeleteByEmail(email);
logger.info("Client supprimé avec succès");
}
// === MÉTHODES DE COMPTAGE - PRÉSERVÉES EXACTEMENT ===
public long count() {
return clientRepository.countActifs();
}
// === MÉTHODES PRIVÉES DE VALIDATION - LOGIQUES CRITIQUES PRÉSERVÉES EXACTEMENT ===
/** Validation complète du client - RÈGLES MÉTIER PRÉSERVÉES */
private void validateClient(Client client) {
if (client.getNom() == null || client.getNom().trim().isEmpty()) {
throw new BadRequestException("Le nom du client est obligatoire");
}
if (client.getPrenom() == null || client.getPrenom().trim().isEmpty()) {
throw new BadRequestException("Le prénom du client est obligatoire");
}
}
/** Mise à jour des champs client - LOGIQUE EXACTE PRÉSERVÉE */
private void updateClientFields(Client existing, Client updated) {
existing.setNom(updated.getNom());
existing.setPrenom(updated.getPrenom());
existing.setEntreprise(updated.getEntreprise());
existing.setEmail(updated.getEmail());
existing.setTelephone(updated.getTelephone());
existing.setAdresse(updated.getAdresse());
existing.setCodePostal(updated.getCodePostal());
existing.setVille(updated.getVille());
existing.setNumeroTVA(updated.getNumeroTVA());
existing.setSiret(updated.getSiret());
existing.setActif(updated.getActif());
}
}