640 lines
22 KiB
Java
640 lines
22 KiB
Java
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)
|
|
}
|