Configure Maven repository for unionflow-server-api dependency
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
package dev.lions.unionflow.server.service;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.solidarite.DemandeAideDTO;
|
||||
import dev.lions.unionflow.server.api.dto.solidarite.HistoriqueStatutDTO;
|
||||
import dev.lions.unionflow.server.api.enums.solidarite.PrioriteAide;
|
||||
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Service spécialisé pour la gestion des demandes d'aide
|
||||
*
|
||||
* <p>Ce service gère le cycle de vie complet des demandes d'aide : création, validation,
|
||||
* changements de statut, recherche et suivi.
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-16
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class DemandeAideService {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(DemandeAideService.class);
|
||||
|
||||
// Cache en mémoire pour les demandes fréquemment consultées
|
||||
private final Map<UUID, DemandeAideDTO> cacheDemandesRecentes = new HashMap<>();
|
||||
private final Map<UUID, LocalDateTime> cacheTimestamps = new HashMap<>();
|
||||
private static final long CACHE_DURATION_MINUTES = 15;
|
||||
|
||||
// === OPÉRATIONS CRUD ===
|
||||
|
||||
/**
|
||||
* Crée une nouvelle demande d'aide
|
||||
*
|
||||
* @param demandeDTO La demande à créer
|
||||
* @return La demande créée avec ID généré
|
||||
*/
|
||||
@Transactional
|
||||
public DemandeAideDTO creerDemande(@Valid DemandeAideDTO demandeDTO) {
|
||||
LOG.infof("Création d'une nouvelle demande d'aide: %s", demandeDTO.getTitre());
|
||||
|
||||
// Génération des identifiants
|
||||
demandeDTO.setId(UUID.randomUUID());
|
||||
demandeDTO.setNumeroReference(genererNumeroReference());
|
||||
|
||||
// Initialisation des dates
|
||||
LocalDateTime maintenant = LocalDateTime.now();
|
||||
demandeDTO.setDateCreation(maintenant);
|
||||
demandeDTO.setDateModification(maintenant);
|
||||
|
||||
// Statut initial
|
||||
if (demandeDTO.getStatut() == null) {
|
||||
demandeDTO.setStatut(StatutAide.BROUILLON);
|
||||
}
|
||||
|
||||
// Priorité par défaut si non définie
|
||||
if (demandeDTO.getPriorite() == null) {
|
||||
demandeDTO.setPriorite(PrioriteAide.NORMALE);
|
||||
}
|
||||
|
||||
// Initialisation de l'historique
|
||||
HistoriqueStatutDTO historiqueInitial =
|
||||
HistoriqueStatutDTO.builder()
|
||||
.id(UUID.randomUUID().toString())
|
||||
.ancienStatut(null)
|
||||
.nouveauStatut(demandeDTO.getStatut())
|
||||
.dateChangement(maintenant)
|
||||
.auteurId(demandeDTO.getMembreDemandeurId() != null ? demandeDTO.getMembreDemandeurId().toString() : null)
|
||||
.motif("Création de la demande")
|
||||
.estAutomatique(true)
|
||||
.build();
|
||||
|
||||
demandeDTO.setHistoriqueStatuts(List.of(historiqueInitial));
|
||||
|
||||
// Calcul du score de priorité
|
||||
demandeDTO.setScorePriorite(calculerScorePriorite(demandeDTO));
|
||||
|
||||
// Sauvegarde en cache
|
||||
ajouterAuCache(demandeDTO);
|
||||
|
||||
LOG.infof("Demande d'aide créée avec succès: %s", demandeDTO.getId());
|
||||
return demandeDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour une demande d'aide existante
|
||||
*
|
||||
* @param demandeDTO La demande à mettre à jour
|
||||
* @return La demande mise à jour
|
||||
*/
|
||||
@Transactional
|
||||
public DemandeAideDTO mettreAJour(@Valid DemandeAideDTO demandeDTO) {
|
||||
LOG.infof("Mise à jour de la demande d'aide: %s", demandeDTO.getId());
|
||||
|
||||
// Vérification que la demande peut être modifiée
|
||||
if (!demandeDTO.estModifiable()) {
|
||||
throw new IllegalStateException("Cette demande ne peut plus être modifiée");
|
||||
}
|
||||
|
||||
// Mise à jour de la date de modification
|
||||
demandeDTO.setDateModification(LocalDateTime.now());
|
||||
demandeDTO.setVersion(demandeDTO.getVersion() + 1);
|
||||
|
||||
// Recalcul du score de priorité
|
||||
demandeDTO.setScorePriorite(calculerScorePriorite(demandeDTO));
|
||||
|
||||
// Mise à jour du cache
|
||||
ajouterAuCache(demandeDTO);
|
||||
|
||||
LOG.infof("Demande d'aide mise à jour avec succès: %s", demandeDTO.getId());
|
||||
return demandeDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient une demande d'aide par son ID
|
||||
*
|
||||
* @param id UUID de la demande
|
||||
* @return La demande trouvée
|
||||
*/
|
||||
public DemandeAideDTO obtenirParId(@NotNull UUID id) {
|
||||
LOG.debugf("Récupération de la demande d'aide: %s", id);
|
||||
|
||||
// Vérification du cache
|
||||
DemandeAideDTO demandeCachee = obtenirDuCache(id);
|
||||
if (demandeCachee != null) {
|
||||
LOG.debugf("Demande trouvée dans le cache: %s", id);
|
||||
return demandeCachee;
|
||||
}
|
||||
|
||||
// Simulation de récupération depuis la base de données
|
||||
// Dans une vraie implémentation, ceci ferait appel au repository
|
||||
DemandeAideDTO demande = simulerRecuperationBDD(id);
|
||||
|
||||
if (demande != null) {
|
||||
ajouterAuCache(demande);
|
||||
}
|
||||
|
||||
return demande;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change le statut d'une demande d'aide
|
||||
*
|
||||
* @param demandeId UUID de la demande
|
||||
* @param nouveauStatut Nouveau statut
|
||||
* @param motif Motif du changement
|
||||
* @return La demande avec le nouveau statut
|
||||
*/
|
||||
@Transactional
|
||||
public DemandeAideDTO changerStatut(
|
||||
@NotNull UUID demandeId, @NotNull StatutAide nouveauStatut, String motif) {
|
||||
LOG.infof("Changement de statut pour la demande %s: %s", demandeId, nouveauStatut);
|
||||
|
||||
DemandeAideDTO demande = obtenirParId(demandeId);
|
||||
if (demande == null) {
|
||||
throw new IllegalArgumentException("Demande non trouvée: " + demandeId);
|
||||
}
|
||||
|
||||
StatutAide ancienStatut = demande.getStatut();
|
||||
|
||||
// Validation de la transition
|
||||
if (!ancienStatut.peutTransitionnerVers(nouveauStatut)) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Transition invalide de %s vers %s", ancienStatut, nouveauStatut));
|
||||
}
|
||||
|
||||
// Mise à jour du statut
|
||||
demande.setStatut(nouveauStatut);
|
||||
demande.setDateModification(LocalDateTime.now());
|
||||
|
||||
// Ajout à l'historique
|
||||
HistoriqueStatutDTO nouvelHistorique =
|
||||
HistoriqueStatutDTO.builder()
|
||||
.id(UUID.randomUUID().toString())
|
||||
.ancienStatut(ancienStatut)
|
||||
.nouveauStatut(nouveauStatut)
|
||||
.dateChangement(LocalDateTime.now())
|
||||
.motif(motif)
|
||||
.estAutomatique(false)
|
||||
.build();
|
||||
|
||||
List<HistoriqueStatutDTO> historique = new ArrayList<>(demande.getHistoriqueStatuts());
|
||||
historique.add(nouvelHistorique);
|
||||
demande.setHistoriqueStatuts(historique);
|
||||
|
||||
// Actions spécifiques selon le nouveau statut
|
||||
switch (nouveauStatut) {
|
||||
case SOUMISE -> demande.setDateSoumission(LocalDateTime.now());
|
||||
case APPROUVEE, APPROUVEE_PARTIELLEMENT -> demande.setDateApprobation(LocalDateTime.now());
|
||||
case VERSEE -> demande.setDateVersement(LocalDateTime.now());
|
||||
case CLOTUREE -> demande.setDateCloture(LocalDateTime.now());
|
||||
}
|
||||
|
||||
// Mise à jour du cache
|
||||
ajouterAuCache(demande);
|
||||
|
||||
LOG.infof(
|
||||
"Statut changé avec succès pour la demande %s: %s -> %s",
|
||||
demandeId, ancienStatut, nouveauStatut);
|
||||
return demande;
|
||||
}
|
||||
|
||||
// === RECHERCHE ET FILTRAGE ===
|
||||
|
||||
/**
|
||||
* Recherche des demandes avec filtres
|
||||
*
|
||||
* @param filtres Map des critères de recherche
|
||||
* @return Liste des demandes correspondantes
|
||||
*/
|
||||
public List<DemandeAideDTO> rechercherAvecFiltres(Map<String, Object> filtres) {
|
||||
LOG.debugf("Recherche de demandes avec filtres: %s", filtres);
|
||||
|
||||
// Simulation de recherche - dans une vraie implémentation,
|
||||
// ceci utiliserait des requêtes de base de données optimisées
|
||||
List<DemandeAideDTO> toutesLesDemandes = simulerRecuperationToutesLesDemandes();
|
||||
|
||||
return toutesLesDemandes.stream()
|
||||
.filter(demande -> correspondAuxFiltres(demande, filtres))
|
||||
.sorted(this::comparerParPriorite)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient les demandes urgentes pour une organisation
|
||||
*
|
||||
* @param organisationId UUID de l'organisation
|
||||
* @return Liste des demandes urgentes
|
||||
*/
|
||||
public List<DemandeAideDTO> obtenirDemandesUrgentes(UUID organisationId) {
|
||||
LOG.debugf("Récupération des demandes urgentes pour: %s", organisationId);
|
||||
|
||||
Map<String, Object> filtres =
|
||||
Map.of(
|
||||
"organisationId", organisationId,
|
||||
"priorite", List.of(PrioriteAide.CRITIQUE, PrioriteAide.URGENTE),
|
||||
"statut",
|
||||
List.of(
|
||||
StatutAide.SOUMISE,
|
||||
StatutAide.EN_ATTENTE,
|
||||
StatutAide.EN_COURS_EVALUATION,
|
||||
StatutAide.APPROUVEE));
|
||||
|
||||
return rechercherAvecFiltres(filtres);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient les demandes en retard (délai dépassé)
|
||||
*
|
||||
* @param organisationId ID de l'organisation
|
||||
* @return Liste des demandes en retard
|
||||
*/
|
||||
public List<DemandeAideDTO> obtenirDemandesEnRetard(UUID organisationId) {
|
||||
LOG.debugf("Récupération des demandes en retard pour: %s", organisationId);
|
||||
|
||||
return simulerRecuperationToutesLesDemandes().stream()
|
||||
.filter(demande -> demande.getAssociationId().equals(organisationId))
|
||||
.filter(DemandeAideDTO::estDelaiDepasse)
|
||||
.filter(demande -> !demande.estTerminee())
|
||||
.sorted(this::comparerParPriorite)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// === MÉTHODES UTILITAIRES PRIVÉES ===
|
||||
|
||||
/** Génère un numéro de référence unique */
|
||||
private String genererNumeroReference() {
|
||||
int annee = LocalDateTime.now().getYear();
|
||||
int numero = (int) (Math.random() * 999999) + 1;
|
||||
return String.format("DA-%04d-%06d", annee, numero);
|
||||
}
|
||||
|
||||
/** Calcule le score de priorité d'une demande */
|
||||
private double calculerScorePriorite(DemandeAideDTO demande) {
|
||||
double score = demande.getPriorite().getScorePriorite();
|
||||
|
||||
// Bonus pour type d'aide urgent
|
||||
if (demande.getTypeAide().isUrgent()) {
|
||||
score -= 1.0;
|
||||
}
|
||||
|
||||
// Bonus pour montant élevé (aide financière)
|
||||
if (demande.getTypeAide().isFinancier() && demande.getMontantDemande() != null) {
|
||||
if (demande.getMontantDemande().compareTo(new BigDecimal("50000")) > 0) {
|
||||
score -= 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
// Malus pour ancienneté
|
||||
long joursDepuisCreation =
|
||||
java.time.Duration.between(demande.getDateCreation(), LocalDateTime.now()).toDays();
|
||||
if (joursDepuisCreation > 7) {
|
||||
score += 0.3;
|
||||
}
|
||||
|
||||
return Math.max(0.1, score);
|
||||
}
|
||||
|
||||
/** Vérifie si une demande correspond aux filtres */
|
||||
private boolean correspondAuxFiltres(DemandeAideDTO demande, Map<String, Object> filtres) {
|
||||
for (Map.Entry<String, Object> filtre : filtres.entrySet()) {
|
||||
String cle = filtre.getKey();
|
||||
Object valeur = filtre.getValue();
|
||||
|
||||
switch (cle) {
|
||||
case "organisationId" -> {
|
||||
if (!demande.getAssociationId().equals(valeur)) return false;
|
||||
}
|
||||
case "typeAide" -> {
|
||||
if (valeur instanceof List<?> liste) {
|
||||
if (!liste.contains(demande.getTypeAide())) return false;
|
||||
} else if (!demande.getTypeAide().equals(valeur)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case "statut" -> {
|
||||
if (valeur instanceof List<?> liste) {
|
||||
if (!liste.contains(demande.getStatut())) return false;
|
||||
} else if (!demande.getStatut().equals(valeur)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case "priorite" -> {
|
||||
if (valeur instanceof List<?> liste) {
|
||||
if (!liste.contains(demande.getPriorite())) return false;
|
||||
} else if (!demande.getPriorite().equals(valeur)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case "demandeurId" -> {
|
||||
if (!demande.getMembreDemandeurId().equals(valeur)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Compare deux demandes par priorité */
|
||||
private int comparerParPriorite(DemandeAideDTO d1, DemandeAideDTO d2) {
|
||||
// D'abord par score de priorité (plus bas = plus prioritaire)
|
||||
int comparaisonScore = Double.compare(d1.getScorePriorite(), d2.getScorePriorite());
|
||||
if (comparaisonScore != 0) return comparaisonScore;
|
||||
|
||||
// Puis par date de création (plus ancien = plus prioritaire)
|
||||
return d1.getDateCreation().compareTo(d2.getDateCreation());
|
||||
}
|
||||
|
||||
// === GESTION DU CACHE ===
|
||||
|
||||
private void ajouterAuCache(DemandeAideDTO demande) {
|
||||
cacheDemandesRecentes.put(demande.getId(), demande);
|
||||
cacheTimestamps.put(demande.getId(), LocalDateTime.now());
|
||||
|
||||
// Nettoyage du cache si trop volumineux
|
||||
if (cacheDemandesRecentes.size() > 100) {
|
||||
nettoyerCache();
|
||||
}
|
||||
}
|
||||
|
||||
private DemandeAideDTO obtenirDuCache(UUID id) {
|
||||
LocalDateTime timestamp = cacheTimestamps.get(id);
|
||||
if (timestamp == null) return null;
|
||||
|
||||
// Vérification de l'expiration
|
||||
if (LocalDateTime.now().minusMinutes(CACHE_DURATION_MINUTES).isAfter(timestamp)) {
|
||||
cacheDemandesRecentes.remove(id);
|
||||
cacheTimestamps.remove(id);
|
||||
return null;
|
||||
}
|
||||
|
||||
return cacheDemandesRecentes.get(id);
|
||||
}
|
||||
|
||||
private void nettoyerCache() {
|
||||
LocalDateTime limite = LocalDateTime.now().minusMinutes(CACHE_DURATION_MINUTES);
|
||||
|
||||
cacheTimestamps.entrySet().removeIf(entry -> entry.getValue().isBefore(limite));
|
||||
cacheDemandesRecentes.keySet().retainAll(cacheTimestamps.keySet());
|
||||
}
|
||||
|
||||
// === MÉTHODES DE SIMULATION (À REMPLACER PAR DE VRAIS REPOSITORIES) ===
|
||||
|
||||
private DemandeAideDTO simulerRecuperationBDD(UUID id) {
|
||||
// Simulation - dans une vraie implémentation, ceci ferait appel au repository
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<DemandeAideDTO> simulerRecuperationToutesLesDemandes() {
|
||||
// Simulation - dans une vraie implémentation, ceci ferait appel au repository
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user