304 lines
11 KiB
Java
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());
|
|
}
|
|
}
|