Initial commit
This commit is contained in:
@@ -0,0 +1,639 @@
|
||||
package dev.lions.btpxpress.application.service;
|
||||
|
||||
import dev.lions.btpxpress.domain.core.entity.*;
|
||||
import dev.lions.btpxpress.domain.infrastructure.repository.*;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service de gestion du planning - Architecture 2025 MÉTIER: Logique complète planning BTP avec
|
||||
* détection conflits
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class PlanningService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PlanningService.class);
|
||||
|
||||
@Inject PlanningEventRepository planningEventRepository;
|
||||
|
||||
@Inject ChantierRepository chantierRepository;
|
||||
|
||||
@Inject EquipeRepository equipeRepository;
|
||||
|
||||
@Inject EmployeRepository employeRepository;
|
||||
|
||||
@Inject MaterielRepository materielRepository;
|
||||
|
||||
// === MÉTHODES VUE PLANNING GÉNÉRAL ===
|
||||
|
||||
public Object getPlanningGeneral(
|
||||
LocalDate dateDebut,
|
||||
LocalDate dateFin,
|
||||
UUID chantierId,
|
||||
UUID equipeId,
|
||||
TypePlanningEvent type) {
|
||||
logger.debug("Génération du planning général du {} au {}", dateDebut, dateFin);
|
||||
|
||||
final LocalDate dateDebutFinal = dateDebut;
|
||||
final LocalDate dateFinFinal = dateFin;
|
||||
|
||||
List<PlanningEvent> events = planningEventRepository.findByDateRange(dateDebut, dateFin);
|
||||
|
||||
// Filtrage selon les critères
|
||||
if (chantierId != null) {
|
||||
events =
|
||||
events.stream()
|
||||
.filter(
|
||||
event ->
|
||||
event.getChantier() != null && event.getChantier().getId().equals(chantierId))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (equipeId != null) {
|
||||
events =
|
||||
events.stream()
|
||||
.filter(
|
||||
event -> event.getEquipe() != null && event.getEquipe().getId().equals(equipeId))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
events =
|
||||
events.stream().filter(event -> event.getType() == type).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// Organiser par jour
|
||||
Map<LocalDate, List<PlanningEvent>> eventsByDay =
|
||||
events.stream().collect(Collectors.groupingBy(event -> event.getDateDebut().toLocalDate()));
|
||||
|
||||
// Statistiques
|
||||
long totalEvents = events.size();
|
||||
Map<TypePlanningEvent, Long> eventsByType =
|
||||
events.stream()
|
||||
.collect(Collectors.groupingBy(PlanningEvent::getType, Collectors.counting()));
|
||||
|
||||
// Conflits détectés
|
||||
List<Object> conflicts = detectConflicts(dateDebut, dateFin, null);
|
||||
|
||||
return new Object() {
|
||||
public final LocalDate dateDebut = dateDebutFinal;
|
||||
public final LocalDate dateFin = dateFinFinal;
|
||||
public final long totalEvenements = totalEvents;
|
||||
public final Map<LocalDate, List<PlanningEvent>> evenementsParJour = eventsByDay;
|
||||
public final Map<TypePlanningEvent, Long> repartitionParType = eventsByType;
|
||||
public final List<Object> conflits = conflicts;
|
||||
public final int nombreConflits = conflicts.size();
|
||||
};
|
||||
}
|
||||
|
||||
public Object getPlanningWeek(LocalDate dateRef) {
|
||||
logger.debug("Génération du planning hebdomadaire pour la semaine du {}", dateRef);
|
||||
|
||||
LocalDate debutSemaine =
|
||||
dateRef.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));
|
||||
LocalDate finSemaine = debutSemaine.plusDays(6);
|
||||
|
||||
List<PlanningEvent> events = planningEventRepository.findByDateRange(debutSemaine, finSemaine);
|
||||
|
||||
// Organiser par jour de la semaine
|
||||
Map<java.time.DayOfWeek, List<PlanningEvent>> eventsByDayOfWeek = new LinkedHashMap<>();
|
||||
for (java.time.DayOfWeek day : java.time.DayOfWeek.values()) {
|
||||
eventsByDayOfWeek.put(day, new ArrayList<>());
|
||||
}
|
||||
|
||||
events.forEach(
|
||||
event -> {
|
||||
java.time.DayOfWeek dayOfWeek = event.getDateDebut().getDayOfWeek();
|
||||
eventsByDayOfWeek.get(dayOfWeek).add(event);
|
||||
});
|
||||
|
||||
final LocalDate debutSemaineFinal = debutSemaine;
|
||||
final LocalDate finSemaineFinal = finSemaine;
|
||||
|
||||
return new Object() {
|
||||
public final LocalDate debutSemaine = debutSemaineFinal;
|
||||
public final LocalDate finSemaine = finSemaineFinal;
|
||||
public final Map<java.time.DayOfWeek, List<PlanningEvent>> evenementsParJour =
|
||||
eventsByDayOfWeek;
|
||||
public final long totalEvenements = events.size();
|
||||
};
|
||||
}
|
||||
|
||||
public Object getPlanningMonth(LocalDate dateRef) {
|
||||
logger.debug("Génération du planning mensuel pour {}", dateRef.getMonth());
|
||||
|
||||
LocalDate debutMois = dateRef.with(TemporalAdjusters.firstDayOfMonth());
|
||||
LocalDate finMois = dateRef.with(TemporalAdjusters.lastDayOfMonth());
|
||||
|
||||
List<PlanningEvent> events = planningEventRepository.findByDateRange(debutMois, finMois);
|
||||
|
||||
// Organiser par semaine
|
||||
Map<Integer, List<PlanningEvent>> eventsByWeek =
|
||||
events.stream()
|
||||
.collect(
|
||||
Collectors.groupingBy(
|
||||
event ->
|
||||
event
|
||||
.getDateDebut()
|
||||
.toLocalDate()
|
||||
.get(java.time.temporal.WeekFields.ISO.weekOfYear())));
|
||||
|
||||
final LocalDate debutMoisFinal = debutMois;
|
||||
final LocalDate finMoisFinal = finMois;
|
||||
|
||||
return new Object() {
|
||||
public final int annee = dateRef.getYear();
|
||||
public final String mois = dateRef.getMonth().name();
|
||||
public final LocalDate debutMois = debutMoisFinal;
|
||||
public final LocalDate finMois = finMoisFinal;
|
||||
public final Map<Integer, List<PlanningEvent>> evenementsParSemaine = eventsByWeek;
|
||||
public final long totalEvenements = events.size();
|
||||
};
|
||||
}
|
||||
|
||||
// === MÉTHODES GESTION ÉVÉNEMENTS ===
|
||||
|
||||
public List<PlanningEvent> findAllEvents() {
|
||||
logger.debug("Recherche de tous les événements de planning");
|
||||
return planningEventRepository.findActifs();
|
||||
}
|
||||
|
||||
public Optional<PlanningEvent> findEventById(UUID id) {
|
||||
logger.debug("Recherche de l'événement par ID: {}", id);
|
||||
return planningEventRepository.findByIdOptional(id);
|
||||
}
|
||||
|
||||
public List<PlanningEvent> findEventsByDateRange(LocalDate dateDebut, LocalDate dateFin) {
|
||||
logger.debug("Recherche des événements entre {} et {}", dateDebut, dateFin);
|
||||
return planningEventRepository.findByDateRange(dateDebut, dateFin);
|
||||
}
|
||||
|
||||
public List<PlanningEvent> findEventsByType(TypePlanningEvent type) {
|
||||
logger.debug("Recherche des événements par type: {}", type);
|
||||
return planningEventRepository.findByType(type);
|
||||
}
|
||||
|
||||
public List<PlanningEvent> findEventsByChantier(UUID chantierId) {
|
||||
logger.debug("Recherche des événements pour le chantier: {}", chantierId);
|
||||
return planningEventRepository.findByChantierId(chantierId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public PlanningEvent createEvent(
|
||||
String titre,
|
||||
String description,
|
||||
String typeStr,
|
||||
LocalDateTime dateDebut,
|
||||
LocalDateTime dateFin,
|
||||
UUID chantierId,
|
||||
UUID equipeId,
|
||||
List<UUID> employeIds,
|
||||
List<UUID> materielIds) {
|
||||
logger.debug("Création d'un nouvel événement: {}", titre);
|
||||
|
||||
// Validation des données
|
||||
validateEventData(titre, dateDebut, dateFin);
|
||||
TypePlanningEvent type = TypePlanningEvent.valueOf(typeStr.toUpperCase());
|
||||
|
||||
// Récupération des entités
|
||||
Chantier chantier =
|
||||
chantierId != null
|
||||
? chantierRepository
|
||||
.findByIdOptional(chantierId)
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException("Chantier non trouvé: " + chantierId))
|
||||
: null;
|
||||
|
||||
Equipe equipe =
|
||||
equipeId != null
|
||||
? equipeRepository
|
||||
.findByIdOptional(equipeId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Équipe non trouvée: " + equipeId))
|
||||
: null;
|
||||
|
||||
List<Employe> employes =
|
||||
employeIds != null ? employeRepository.findByIds(employeIds) : new ArrayList<>();
|
||||
|
||||
List<Materiel> materiels =
|
||||
materielIds != null ? materielRepository.findByIds(materielIds) : new ArrayList<>();
|
||||
|
||||
// Vérification des conflits de ressources
|
||||
if (!checkResourcesAvailability(dateDebut, dateFin, employeIds, materielIds, equipeId)) {
|
||||
throw new IllegalStateException("Conflit de ressources détecté pour cette période");
|
||||
}
|
||||
|
||||
// Création de l'événement
|
||||
PlanningEvent event = new PlanningEvent();
|
||||
event.setTitre(titre);
|
||||
event.setDescription(description);
|
||||
event.setType(type);
|
||||
event.setDateDebut(dateDebut);
|
||||
event.setDateFin(dateFin);
|
||||
event.setChantier(chantier);
|
||||
event.setEquipe(equipe);
|
||||
event.setEmployes(employes);
|
||||
event.setMateriels(materiels);
|
||||
event.setActif(true);
|
||||
|
||||
planningEventRepository.persist(event);
|
||||
|
||||
logger.info("Événement créé avec succès: {} du {} au {}", titre, dateDebut, dateFin);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public PlanningEvent updateEvent(
|
||||
UUID id,
|
||||
String titre,
|
||||
String description,
|
||||
LocalDateTime dateDebut,
|
||||
LocalDateTime dateFin,
|
||||
UUID equipeId,
|
||||
List<UUID> employeIds,
|
||||
List<UUID> materielIds) {
|
||||
logger.debug("Mise à jour de l'événement: {}", id);
|
||||
|
||||
PlanningEvent event =
|
||||
planningEventRepository
|
||||
.findByIdOptional(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Événement non trouvé: " + id));
|
||||
|
||||
// Validation des nouvelles données
|
||||
if (dateDebut != null && dateFin != null) {
|
||||
validateEventData(titre, dateDebut, dateFin);
|
||||
|
||||
// Vérifier les conflits (en excluant l'événement actuel)
|
||||
if (!checkResourcesAvailabilityExcluding(
|
||||
dateDebut, dateFin, employeIds, materielIds, equipeId, id)) {
|
||||
throw new IllegalStateException("Conflit de ressources détecté pour cette période");
|
||||
}
|
||||
}
|
||||
|
||||
// Mise à jour des champs
|
||||
if (titre != null) event.setTitre(titre);
|
||||
if (description != null) event.setDescription(description);
|
||||
if (dateDebut != null) event.setDateDebut(dateDebut);
|
||||
if (dateFin != null) event.setDateFin(dateFin);
|
||||
|
||||
if (equipeId != null) {
|
||||
Equipe equipe =
|
||||
equipeRepository
|
||||
.findByIdOptional(equipeId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Équipe non trouvée: " + equipeId));
|
||||
event.setEquipe(equipe);
|
||||
}
|
||||
|
||||
if (employeIds != null) {
|
||||
List<Employe> employes = employeRepository.findByIds(employeIds);
|
||||
event.setEmployes(employes);
|
||||
}
|
||||
|
||||
if (materielIds != null) {
|
||||
List<Materiel> materiels = materielRepository.findByIds(materielIds);
|
||||
event.setMateriels(materiels);
|
||||
}
|
||||
|
||||
planningEventRepository.persist(event);
|
||||
|
||||
logger.info("Événement mis à jour avec succès: {}", event.getTitre());
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteEvent(UUID id) {
|
||||
logger.debug("Suppression de l'événement: {}", id);
|
||||
|
||||
PlanningEvent event =
|
||||
planningEventRepository
|
||||
.findByIdOptional(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Événement non trouvé: " + id));
|
||||
|
||||
planningEventRepository.softDelete(id);
|
||||
|
||||
logger.info("Événement supprimé avec succès: {}", event.getTitre());
|
||||
}
|
||||
|
||||
// === MÉTHODES DÉTECTION CONFLITS ===
|
||||
|
||||
public List<Object> detectConflicts(LocalDate dateDebut, LocalDate dateFin, String resourceType) {
|
||||
logger.debug("Détection des conflits du {} au {}", dateDebut, dateFin);
|
||||
|
||||
List<PlanningEvent> events = planningEventRepository.findByDateRange(dateDebut, dateFin);
|
||||
List<Object> conflicts = new ArrayList<>();
|
||||
|
||||
// Détecter les conflits d'employés
|
||||
if (resourceType == null || "EMPLOYE".equals(resourceType)) {
|
||||
conflicts.addAll(detectEmployeConflicts(events));
|
||||
}
|
||||
|
||||
// Détecter les conflits de matériel
|
||||
if (resourceType == null || "MATERIEL".equals(resourceType)) {
|
||||
conflicts.addAll(detectMaterielConflicts(events));
|
||||
}
|
||||
|
||||
// Détecter les conflits d'équipes
|
||||
if (resourceType == null || "EQUIPE".equals(resourceType)) {
|
||||
conflicts.addAll(detectEquipeConflicts(events));
|
||||
}
|
||||
|
||||
logger.info("Détection terminée: {} conflits trouvés", conflicts.size());
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
public boolean checkResourcesAvailability(
|
||||
LocalDateTime dateDebut,
|
||||
LocalDateTime dateFin,
|
||||
List<UUID> employeIds,
|
||||
List<UUID> materielIds,
|
||||
UUID equipeId) {
|
||||
return checkResourcesAvailabilityExcluding(
|
||||
dateDebut, dateFin, employeIds, materielIds, equipeId, null);
|
||||
}
|
||||
|
||||
public boolean checkResourcesAvailabilityExcluding(
|
||||
LocalDateTime dateDebut,
|
||||
LocalDateTime dateFin,
|
||||
List<UUID> employeIds,
|
||||
List<UUID> materielIds,
|
||||
UUID equipeId,
|
||||
UUID excludeEventId) {
|
||||
logger.debug("Vérification de disponibilité des ressources du {} au {}", dateDebut, dateFin);
|
||||
|
||||
List<PlanningEvent> conflictingEvents =
|
||||
planningEventRepository.findConflictingEvents(dateDebut, dateFin, excludeEventId);
|
||||
|
||||
// Vérifier les employés
|
||||
if (employeIds != null && !employeIds.isEmpty()) {
|
||||
for (UUID employeId : employeIds) {
|
||||
if (isEmployeOccupied(employeId, conflictingEvents)) {
|
||||
logger.warn("Employé {} occupé pendant cette période", employeId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifier le matériel
|
||||
if (materielIds != null && !materielIds.isEmpty()) {
|
||||
for (UUID materielId : materielIds) {
|
||||
if (isMaterielOccupied(materielId, conflictingEvents)) {
|
||||
logger.warn("Matériel {} occupé pendant cette période", materielId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifier l'équipe
|
||||
if (equipeId != null) {
|
||||
if (isEquipeOccupied(equipeId, conflictingEvents)) {
|
||||
logger.warn("Équipe {} occupée pendant cette période", equipeId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object getAvailabilityDetails(
|
||||
LocalDateTime dateDebut,
|
||||
LocalDateTime dateFin,
|
||||
List<UUID> employeIds,
|
||||
List<UUID> materielIds,
|
||||
UUID equipeId) {
|
||||
logger.debug("Génération des détails de disponibilité");
|
||||
|
||||
List<PlanningEvent> conflictingEvents =
|
||||
planningEventRepository.findConflictingEvents(dateDebut, dateFin, null);
|
||||
|
||||
// Analyser chaque ressource
|
||||
Map<String, Object> employeDetails = new HashMap<>();
|
||||
if (employeIds != null) {
|
||||
for (UUID employeId : employeIds) {
|
||||
employeDetails.put(
|
||||
employeId.toString(),
|
||||
isEmployeOccupied(employeId, conflictingEvents) ? "OCCUPÉ" : "DISPONIBLE");
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> materielDetails = new HashMap<>();
|
||||
if (materielIds != null) {
|
||||
for (UUID materielId : materielIds) {
|
||||
materielDetails.put(
|
||||
materielId.toString(),
|
||||
isMaterielOccupied(materielId, conflictingEvents) ? "OCCUPÉ" : "DISPONIBLE");
|
||||
}
|
||||
}
|
||||
|
||||
final String equipeStatus;
|
||||
if (equipeId != null) {
|
||||
equipeStatus = isEquipeOccupied(equipeId, conflictingEvents) ? "OCCUPÉE" : "DISPONIBLE";
|
||||
} else {
|
||||
equipeStatus = null;
|
||||
}
|
||||
|
||||
return new Object() {
|
||||
public final Map<String, Object> employes = employeDetails;
|
||||
public final Map<String, Object> materiels = materielDetails;
|
||||
public final String equipe = equipeStatus;
|
||||
public final List<PlanningEvent> evenementsConflictuels = conflictingEvents;
|
||||
};
|
||||
}
|
||||
|
||||
// === MÉTHODES STATISTIQUES ===
|
||||
|
||||
public Object getStatistics(LocalDate dateDebut, LocalDate dateFin) {
|
||||
logger.debug("Génération des statistiques du planning");
|
||||
|
||||
List<PlanningEvent> events = planningEventRepository.findByDateRange(dateDebut, dateFin);
|
||||
|
||||
Map<TypePlanningEvent, Long> eventsByType =
|
||||
events.stream()
|
||||
.collect(Collectors.groupingBy(PlanningEvent::getType, Collectors.counting()));
|
||||
|
||||
long totalHeures =
|
||||
events.stream()
|
||||
.mapToLong(
|
||||
event ->
|
||||
java.time.Duration.between(event.getDateDebut(), event.getDateFin()).toHours())
|
||||
.sum();
|
||||
|
||||
int conflitsDetectes = detectConflicts(dateDebut, dateFin, null).size();
|
||||
|
||||
return new Object() {
|
||||
public final long totalEvenements = events.size();
|
||||
public final Map<TypePlanningEvent, Long> repartitionParType = eventsByType;
|
||||
public final long totalHeuresPlannifiees = totalHeures;
|
||||
public final int nombreConflits = conflitsDetectes;
|
||||
public final LocalDate periodeDebut = dateDebut;
|
||||
public final LocalDate periodeFin = dateFin;
|
||||
};
|
||||
}
|
||||
|
||||
// === MÉTHODES PRIVÉES DE VALIDATION ===
|
||||
|
||||
private void validateEventData(String titre, LocalDateTime dateDebut, LocalDateTime dateFin) {
|
||||
if (titre == null || titre.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Le titre de l'événement est obligatoire");
|
||||
}
|
||||
|
||||
if (dateDebut == null || dateFin == null) {
|
||||
throw new IllegalArgumentException("Les dates de début et fin sont obligatoires");
|
||||
}
|
||||
|
||||
if (dateDebut.isAfter(dateFin)) {
|
||||
throw new IllegalArgumentException("La date de début ne peut pas être après la date de fin");
|
||||
}
|
||||
|
||||
if (dateDebut.isBefore(LocalDateTime.now().minusHours(1))) {
|
||||
throw new IllegalArgumentException("L'événement ne peut pas être planifié dans le passé");
|
||||
}
|
||||
}
|
||||
|
||||
// === MÉTHODES PRIVÉES DÉTECTION CONFLITS ===
|
||||
|
||||
private List<Object> detectEmployeConflicts(List<PlanningEvent> events) {
|
||||
List<Object> conflicts = new ArrayList<>();
|
||||
Map<UUID, List<PlanningEvent>> eventsByEmploye = new HashMap<>();
|
||||
|
||||
// Grouper les événements par employé
|
||||
for (PlanningEvent event : events) {
|
||||
if (event.getEmployes() != null) {
|
||||
for (Employe employe : event.getEmployes()) {
|
||||
eventsByEmploye.computeIfAbsent(employe.getId(), k -> new ArrayList<>()).add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Détecter les chevauchements
|
||||
for (Map.Entry<UUID, List<PlanningEvent>> entry : eventsByEmploye.entrySet()) {
|
||||
List<PlanningEvent> employeEvents = entry.getValue();
|
||||
for (int i = 0; i < employeEvents.size(); i++) {
|
||||
for (int j = i + 1; j < employeEvents.size(); j++) {
|
||||
PlanningEvent event1 = employeEvents.get(i);
|
||||
PlanningEvent event2 = employeEvents.get(j);
|
||||
|
||||
if (eventsOverlap(event1, event2)) {
|
||||
conflicts.add(createConflictReport("EMPLOYE", entry.getKey(), event1, event2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
private List<Object> detectMaterielConflicts(List<PlanningEvent> events) {
|
||||
List<Object> conflicts = new ArrayList<>();
|
||||
Map<UUID, List<PlanningEvent>> eventsByMateriel = new HashMap<>();
|
||||
|
||||
// Grouper les événements par matériel
|
||||
for (PlanningEvent event : events) {
|
||||
if (event.getMateriels() != null) {
|
||||
for (Materiel materiel : event.getMateriels()) {
|
||||
eventsByMateriel.computeIfAbsent(materiel.getId(), k -> new ArrayList<>()).add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Détecter les chevauchements
|
||||
for (Map.Entry<UUID, List<PlanningEvent>> entry : eventsByMateriel.entrySet()) {
|
||||
List<PlanningEvent> materielEvents = entry.getValue();
|
||||
for (int i = 0; i < materielEvents.size(); i++) {
|
||||
for (int j = i + 1; j < materielEvents.size(); j++) {
|
||||
PlanningEvent event1 = materielEvents.get(i);
|
||||
PlanningEvent event2 = materielEvents.get(j);
|
||||
|
||||
if (eventsOverlap(event1, event2)) {
|
||||
conflicts.add(createConflictReport("MATERIEL", entry.getKey(), event1, event2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
private List<Object> detectEquipeConflicts(List<PlanningEvent> events) {
|
||||
List<Object> conflicts = new ArrayList<>();
|
||||
Map<UUID, List<PlanningEvent>> eventsByEquipe = new HashMap<>();
|
||||
|
||||
// Grouper les événements par équipe
|
||||
for (PlanningEvent event : events) {
|
||||
if (event.getEquipe() != null) {
|
||||
eventsByEquipe
|
||||
.computeIfAbsent(event.getEquipe().getId(), k -> new ArrayList<>())
|
||||
.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Détecter les chevauchements
|
||||
for (Map.Entry<UUID, List<PlanningEvent>> entry : eventsByEquipe.entrySet()) {
|
||||
List<PlanningEvent> equipeEvents = entry.getValue();
|
||||
for (int i = 0; i < equipeEvents.size(); i++) {
|
||||
for (int j = i + 1; j < equipeEvents.size(); j++) {
|
||||
PlanningEvent event1 = equipeEvents.get(i);
|
||||
PlanningEvent event2 = equipeEvents.get(j);
|
||||
|
||||
if (eventsOverlap(event1, event2)) {
|
||||
conflicts.add(createConflictReport("EQUIPE", entry.getKey(), event1, event2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
private boolean eventsOverlap(PlanningEvent event1, PlanningEvent event2) {
|
||||
return event1.getDateDebut().isBefore(event2.getDateFin())
|
||||
&& event2.getDateDebut().isBefore(event1.getDateFin());
|
||||
}
|
||||
|
||||
private Object createConflictReport(
|
||||
String resourceType, UUID resourceId, PlanningEvent event1, PlanningEvent event2) {
|
||||
return new Object() {
|
||||
public final String typeRessource = resourceType;
|
||||
public final UUID idRessource = resourceId;
|
||||
public final PlanningEvent evenement1 = event1;
|
||||
public final PlanningEvent evenement2 = event2;
|
||||
public final String description =
|
||||
String.format(
|
||||
"Conflit de %s: %s et %s se chevauchent",
|
||||
resourceType.toLowerCase(), event1.getTitre(), event2.getTitre());
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isEmployeOccupied(UUID employeId, List<PlanningEvent> events) {
|
||||
return events.stream()
|
||||
.anyMatch(
|
||||
event ->
|
||||
event.getEmployes() != null
|
||||
&& event.getEmployes().stream().anyMatch(e -> e.getId().equals(employeId)));
|
||||
}
|
||||
|
||||
private boolean isMaterielOccupied(UUID materielId, List<PlanningEvent> events) {
|
||||
return events.stream()
|
||||
.anyMatch(
|
||||
event ->
|
||||
event.getMateriels() != null
|
||||
&& event.getMateriels().stream().anyMatch(m -> m.getId().equals(materielId)));
|
||||
}
|
||||
|
||||
private boolean isEquipeOccupied(UUID equipeId, List<PlanningEvent> events) {
|
||||
return events.stream()
|
||||
.anyMatch(event -> event.getEquipe() != null && event.getEquipe().getId().equals(equipeId));
|
||||
}
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
// (Méthodes supprimées car redondantes)
|
||||
}
|
||||
Reference in New Issue
Block a user