Clean project: remove test files, debug logs, and add documentation

This commit is contained in:
dahoud
2025-10-05 13:41:33 +00:00
parent 96a17eadbd
commit 291847924c
438 changed files with 65754 additions and 32713 deletions

View File

@@ -2,31 +2,30 @@ package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.DecimalMin;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* DTO pour les données analytics UnionFlow
*
* Représente une donnée analytique avec sa valeur, sa métrique associée,
* sa période d'analyse et ses métadonnées.
*
*
* <p>Représente une donnée analytique avec sa valeur, sa métrique associée, sa période d'analyse et
* ses métadonnées.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -37,225 +36,224 @@ import java.util.UUID;
@NoArgsConstructor
@AllArgsConstructor
public class AnalyticsDataDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Type de métrique analysée */
@NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique;
/** Période d'analyse */
@NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse;
/** Valeur numérique de la métrique */
@NotNull(message = "La valeur est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur invalide")
private BigDecimal valeur;
/** Valeur précédente pour comparaison */
@DecimalMin(value = "0.0", message = "La valeur précédente doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur précédente invalide")
private BigDecimal valeurPrecedente;
/** Pourcentage d'évolution par rapport à la période précédente */
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
private BigDecimal pourcentageEvolution;
/** Date de début de la période analysée */
@NotNull(message = "La date de début est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebut;
/** Date de fin de la période analysée */
@NotNull(message = "La date de fin est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFin;
/** Date de calcul de la métrique */
@NotNull(message = "La date de calcul est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateCalcul;
/** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Identifiant de l'utilisateur qui a demandé le calcul */
private UUID utilisateurId;
/** Nom de l'utilisateur qui a demandé le calcul */
@Size(max = 200, message = "Le nom de l'utilisateur ne peut pas dépasser 200 caractères")
private String nomUtilisateur;
/** Libellé personnalisé de la métrique */
@Size(max = 300, message = "Le libellé personnalisé ne peut pas dépasser 300 caractères")
private String libellePersonnalise;
/** Description ou commentaire sur la métrique */
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
private String description;
/** Données détaillées pour les graphiques (format JSON) */
@Size(max = 10000, message = "Les données détaillées ne peuvent pas dépasser 10000 caractères")
private String donneesDetaillees;
/** Configuration du graphique (couleurs, type, etc.) */
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
private String configurationGraphique;
/** Métadonnées additionnelles */
private Map<String, Object> metadonnees;
/** Indicateur de fiabilité des données (0-100) */
@DecimalMin(value = "0.0", message = "L'indicateur de fiabilité doit être positif")
@DecimalMax(value = "100.0", message = "L'indicateur de fiabilité ne peut pas dépasser 100")
@Digits(integer = 3, fraction = 1, message = "Format d'indicateur de fiabilité invalide")
private BigDecimal indicateurFiabilite;
/** Nombre d'éléments analysés pour calculer cette métrique */
@DecimalMin(value = "0", message = "Le nombre d'éléments doit être positif")
private Integer nombreElementsAnalyses;
/** Temps de calcul en millisecondes */
@DecimalMin(value = "0", message = "Le temps de calcul doit être positif")
private Long tempsCalculMs;
/** Indicateur si la métrique est en temps réel */
@Builder.Default
private Boolean tempsReel = false;
/** Indicateur si la métrique nécessite une mise à jour */
@Builder.Default
private Boolean necessiteMiseAJour = false;
/** Niveau de priorité de la métrique (1=faible, 5=critique) */
@DecimalMin(value = "1", message = "Le niveau de priorité minimum est 1")
@DecimalMax(value = "5", message = "Le niveau de priorité maximum est 5")
private Integer niveauPriorite;
/** Tags pour catégoriser la métrique */
private List<String> tags;
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le libellé à afficher (personnalisé ou par défaut)
*
* @return Le libellé à afficher
*/
public String getLibelleAffichage() {
return libellePersonnalise != null && !libellePersonnalise.trim().isEmpty()
? libellePersonnalise
: typeMetrique.getLibelle();
}
/**
* Retourne l'unité de mesure de la métrique
*
* @return L'unité de mesure
*/
public String getUnite() {
return typeMetrique.getUnite();
}
/**
* Retourne l'icône de la métrique
*
* @return L'icône Material Design
*/
public String getIcone() {
return typeMetrique.getIcone();
}
/**
* Retourne la couleur de la métrique
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return typeMetrique.getCouleur();
}
/**
* Vérifie si la métrique a évolué positivement
*
* @return true si l'évolution est positive
*/
public boolean hasEvolutionPositive() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0;
}
/**
* Vérifie si la métrique a évolué négativement
*
* @return true si l'évolution est négative
*/
public boolean hasEvolutionNegative() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0;
}
/**
* Vérifie si la métrique est stable (pas d'évolution)
*
* @return true si l'évolution est nulle
*/
public boolean isStable() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) == 0;
}
/**
* Retourne la tendance sous forme de texte
*
* @return "hausse", "baisse" ou "stable"
*/
public String getTendance() {
if (hasEvolutionPositive()) return "hausse";
if (hasEvolutionNegative()) return "baisse";
return "stable";
}
/**
* Vérifie si les données sont fiables (indicateur > 80)
*
* @return true si les données sont considérées comme fiables
*/
public boolean isDonneesFiables() {
return indicateurFiabilite != null &&
indicateurFiabilite.compareTo(new BigDecimal("80.0")) >= 0;
}
/**
* Vérifie si la métrique est critique (priorité >= 4)
*
* @return true si la métrique est critique
*/
public boolean isCritique() {
return niveauPriorite != null && niveauPriorite >= 4;
}
/**
* Constructeur avec les champs essentiels
*
* @param typeMetrique Le type de métrique
* @param periodeAnalyse La période d'analyse
* @param valeur La valeur de la métrique
*/
public AnalyticsDataDTO(TypeMetrique typeMetrique, PeriodeAnalyse periodeAnalyse, BigDecimal valeur) {
super();
this.typeMetrique = typeMetrique;
this.periodeAnalyse = periodeAnalyse;
this.valeur = valeur;
this.dateCalcul = LocalDateTime.now();
this.dateDebut = periodeAnalyse.getDateDebut();
this.dateFin = periodeAnalyse.getDateFin();
this.tempsReel = false;
this.necessiteMiseAJour = false;
this.niveauPriorite = 3; // Priorité normale par défaut
this.indicateurFiabilite = new BigDecimal("95.0"); // Fiabilité élevée par défaut
}
private static final long serialVersionUID = 1L;
/** Type de métrique analysée */
@NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique;
/** Période d'analyse */
@NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse;
/** Valeur numérique de la métrique */
@NotNull(message = "La valeur est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur invalide")
private BigDecimal valeur;
/** Valeur précédente pour comparaison */
@DecimalMin(value = "0.0", message = "La valeur précédente doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur précédente invalide")
private BigDecimal valeurPrecedente;
/** Pourcentage d'évolution par rapport à la période précédente */
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
private BigDecimal pourcentageEvolution;
/** Date de début de la période analysée */
@NotNull(message = "La date de début est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebut;
/** Date de fin de la période analysée */
@NotNull(message = "La date de fin est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFin;
/** Date de calcul de la métrique */
@NotNull(message = "La date de calcul est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateCalcul;
/** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Identifiant de l'utilisateur qui a demandé le calcul */
private UUID utilisateurId;
/** Nom de l'utilisateur qui a demandé le calcul */
@Size(max = 200, message = "Le nom de l'utilisateur ne peut pas dépasser 200 caractères")
private String nomUtilisateur;
/** Libellé personnalisé de la métrique */
@Size(max = 300, message = "Le libellé personnalisé ne peut pas dépasser 300 caractères")
private String libellePersonnalise;
/** Description ou commentaire sur la métrique */
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
private String description;
/** Données détaillées pour les graphiques (format JSON) */
@Size(max = 10000, message = "Les données détaillées ne peuvent pas dépasser 10000 caractères")
private String donneesDetaillees;
/** Configuration du graphique (couleurs, type, etc.) */
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
private String configurationGraphique;
/** Métadonnées additionnelles */
private Map<String, Object> metadonnees;
/** Indicateur de fiabilité des données (0-100) */
@DecimalMin(value = "0.0", message = "L'indicateur de fiabilité doit être positif")
@DecimalMax(value = "100.0", message = "L'indicateur de fiabilité ne peut pas dépasser 100")
@Digits(integer = 3, fraction = 1, message = "Format d'indicateur de fiabilité invalide")
private BigDecimal indicateurFiabilite;
/** Nombre d'éléments analysés pour calculer cette métrique */
@DecimalMin(value = "0", message = "Le nombre d'éléments doit être positif")
private Integer nombreElementsAnalyses;
/** Temps de calcul en millisecondes */
@DecimalMin(value = "0", message = "Le temps de calcul doit être positif")
private Long tempsCalculMs;
/** Indicateur si la métrique est en temps réel */
@Builder.Default private Boolean tempsReel = false;
/** Indicateur si la métrique nécessite une mise à jour */
@Builder.Default private Boolean necessiteMiseAJour = false;
/** Niveau de priorité de la métrique (1=faible, 5=critique) */
@DecimalMin(value = "1", message = "Le niveau de priorité minimum est 1")
@DecimalMax(value = "5", message = "Le niveau de priorité maximum est 5")
private Integer niveauPriorite;
/** Tags pour catégoriser la métrique */
private List<String> tags;
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le libellé à afficher (personnalisé ou par défaut)
*
* @return Le libellé à afficher
*/
public String getLibelleAffichage() {
return libellePersonnalise != null && !libellePersonnalise.trim().isEmpty()
? libellePersonnalise
: typeMetrique.getLibelle();
}
/**
* Retourne l'unité de mesure de la métrique
*
* @return L'unité de mesure
*/
public String getUnite() {
return typeMetrique.getUnite();
}
/**
* Retourne l'icône de la métrique
*
* @return L'icône Material Design
*/
public String getIcone() {
return typeMetrique.getIcone();
}
/**
* Retourne la couleur de la métrique
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return typeMetrique.getCouleur();
}
/**
* Vérifie si la métrique a évolué positivement
*
* @return true si l'évolution est positive
*/
public boolean hasEvolutionPositive() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0;
}
/**
* Vérifie si la métrique a évolué négativement
*
* @return true si l'évolution est négative
*/
public boolean hasEvolutionNegative() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0;
}
/**
* Vérifie si la métrique est stable (pas d'évolution)
*
* @return true si l'évolution est nulle
*/
public boolean isStable() {
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) == 0;
}
/**
* Retourne la tendance sous forme de texte
*
* @return "hausse", "baisse" ou "stable"
*/
public String getTendance() {
if (hasEvolutionPositive()) return "hausse";
if (hasEvolutionNegative()) return "baisse";
return "stable";
}
/**
* Vérifie si les données sont fiables (indicateur > 80)
*
* @return true si les données sont considérées comme fiables
*/
public boolean isDonneesFiables() {
return indicateurFiabilite != null
&& indicateurFiabilite.compareTo(new BigDecimal("80.0")) >= 0;
}
/**
* Vérifie si la métrique est critique (priorité >= 4)
*
* @return true si la métrique est critique
*/
public boolean isCritique() {
return niveauPriorite != null && niveauPriorite >= 4;
}
/**
* Constructeur avec les champs essentiels
*
* @param typeMetrique Le type de métrique
* @param periodeAnalyse La période d'analyse
* @param valeur La valeur de la métrique
*/
public AnalyticsDataDTO(
TypeMetrique typeMetrique, PeriodeAnalyse periodeAnalyse, BigDecimal valeur) {
super();
this.typeMetrique = typeMetrique;
this.periodeAnalyse = periodeAnalyse;
this.valeur = valeur;
this.dateCalcul = LocalDateTime.now();
this.dateDebut = periodeAnalyse.getDateDebut();
this.dateFin = periodeAnalyse.getDateFin();
this.tempsReel = false;
this.necessiteMiseAJour = false;
this.niveauPriorite = 3; // Priorité normale par défaut
this.indicateurFiabilite = new BigDecimal("95.0"); // Fiabilité élevée par défaut
}
}

View File

@@ -2,29 +2,28 @@ package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.DecimalMin;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* DTO pour les widgets de tableau de bord analytics UnionFlow
*
* Représente un widget personnalisable affiché sur le tableau de bord
* avec sa configuration, sa position et ses données.
*
*
* <p>Représente un widget personnalisable affiché sur le tableau de bord avec sa configuration, sa
* position et ses données.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -35,309 +34,305 @@ import java.util.UUID;
@NoArgsConstructor
@AllArgsConstructor
public class DashboardWidgetDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Titre du widget */
@NotBlank(message = "Le titre du widget est obligatoire")
@Size(min = 3, max = 200, message = "Le titre du widget doit contenir entre 3 et 200 caractères")
private String titre;
/** Description du widget */
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
private String description;
/** Type de widget (kpi, chart, table, gauge, progress, text) */
@NotBlank(message = "Le type de widget est obligatoire")
@Size(max = 50, message = "Le type de widget ne peut pas dépasser 50 caractères")
private String typeWidget;
/** Type de métrique affiché */
private TypeMetrique typeMetrique;
/** Période d'analyse */
private PeriodeAnalyse periodeAnalyse;
/** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Identifiant de l'utilisateur propriétaire */
@NotNull(message = "L'identifiant de l'utilisateur propriétaire est obligatoire")
private UUID utilisateurProprietaireId;
/** Nom de l'utilisateur propriétaire */
@Size(max = 200, message = "Le nom de l'utilisateur propriétaire ne peut pas dépasser 200 caractères")
private String nomUtilisateurProprietaire;
/** Position X du widget sur la grille */
@NotNull(message = "La position X est obligatoire")
@DecimalMin(value = "0", message = "La position X doit être positive ou nulle")
private Integer positionX;
/** Position Y du widget sur la grille */
@NotNull(message = "La position Y est obligatoire")
@DecimalMin(value = "0", message = "La position Y doit être positive ou nulle")
private Integer positionY;
/** Largeur du widget (en unités de grille) */
@NotNull(message = "La largeur est obligatoire")
@DecimalMin(value = "1", message = "La largeur minimum est 1")
@DecimalMax(value = "12", message = "La largeur maximum est 12")
private Integer largeur;
/** Hauteur du widget (en unités de grille) */
@NotNull(message = "La hauteur est obligatoire")
@DecimalMin(value = "1", message = "La hauteur minimum est 1")
@DecimalMax(value = "12", message = "La hauteur maximum est 12")
private Integer hauteur;
/** Ordre d'affichage (z-index) */
@DecimalMin(value = "0", message = "L'ordre d'affichage doit être positif ou nul")
@Builder.Default
private Integer ordreAffichage = 0;
/** Configuration visuelle du widget */
@Size(max = 5000, message = "La configuration visuelle ne peut pas dépasser 5000 caractères")
private String configurationVisuelle;
/** Couleur principale du widget */
@Size(max = 7, message = "La couleur doit être au format #RRGGBB")
private String couleurPrincipale;
/** Couleur secondaire du widget */
@Size(max = 7, message = "La couleur secondaire doit être au format #RRGGBB")
private String couleurSecondaire;
/** Icône du widget */
@Size(max = 50, message = "L'icône ne peut pas dépasser 50 caractères")
private String icone;
/** Indicateur si le widget est visible */
@Builder.Default
private Boolean visible = true;
/** Indicateur si le widget est redimensionnable */
@Builder.Default
private Boolean redimensionnable = true;
/** Indicateur si le widget est déplaçable */
@Builder.Default
private Boolean deplacable = true;
/** Indicateur si le widget peut être supprimé */
@Builder.Default
private Boolean supprimable = true;
/** Indicateur si le widget se met à jour automatiquement */
@Builder.Default
private Boolean miseAJourAutomatique = true;
/** Fréquence de mise à jour en secondes */
@DecimalMin(value = "30", message = "La fréquence minimum est 30 secondes")
@Builder.Default
private Integer frequenceMiseAJourSecondes = 300; // 5 minutes par défaut
/** Date de dernière mise à jour des données */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereMiseAJour;
/** Prochaine mise à jour programmée */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime prochaineMiseAJour;
/** Données du widget (format JSON) */
@Size(max = 50000, message = "Les données du widget ne peuvent pas dépasser 50000 caractères")
private String donneesWidget;
/** Configuration des filtres */
private Map<String, Object> configurationFiltres;
/** Configuration des alertes */
private Map<String, Object> configurationAlertes;
/** Seuil d'alerte bas */
private Double seuilAlerteBas;
/** Seuil d'alerte haut */
private Double seuilAlerteHaut;
/** Indicateur si une alerte est active */
@Builder.Default
private Boolean alerteActive = false;
/** Message d'alerte actuel */
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
private String messageAlerte;
/** Type d'alerte (info, warning, error, success) */
@Size(max = 20, message = "Le type d'alerte ne peut pas dépasser 20 caractères")
private String typeAlerte;
/** Permissions d'accès au widget */
@Size(max = 1000, message = "Les permissions ne peuvent pas dépasser 1000 caractères")
private String permissions;
/** Rôles autorisés à voir le widget */
@Size(max = 500, message = "Les rôles autorisés ne peuvent pas dépasser 500 caractères")
private String rolesAutorises;
/** Template personnalisé du widget */
@Size(max = 10000, message = "Le template personnalisé ne peut pas dépasser 10000 caractères")
private String templatePersonnalise;
/** CSS personnalisé du widget */
@Size(max = 5000, message = "Le CSS personnalisé ne peut pas dépasser 5000 caractères")
private String cssPersonnalise;
/** JavaScript personnalisé du widget */
@Size(max = 10000, message = "Le JavaScript personnalisé ne peut pas dépasser 10000 caractères")
private String javascriptPersonnalise;
/** Métadonnées additionnelles */
private Map<String, Object> metadonnees;
/** Nombre de vues du widget */
@DecimalMin(value = "0", message = "Le nombre de vues doit être positif")
@Builder.Default
private Long nombreVues = 0L;
/** Nombre d'interactions avec le widget */
@DecimalMin(value = "0", message = "Le nombre d'interactions doit être positif")
@Builder.Default
private Long nombreInteractions = 0L;
/** Temps moyen passé sur le widget (en secondes) */
@DecimalMin(value = "0", message = "Le temps moyen doit être positif")
private Integer tempsMoyenSecondes;
/** Taux d'erreur du widget (en pourcentage) */
@DecimalMin(value = "0.0", message = "Le taux d'erreur doit être positif")
@DecimalMax(value = "100.0", message = "Le taux d'erreur ne peut pas dépasser 100%")
@Builder.Default
private Double tauxErreur = 0.0;
/** Date de dernière erreur */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereErreur;
/** Message de dernière erreur */
@Size(max = 1000, message = "Le message d'erreur ne peut pas dépasser 1000 caractères")
private String messageDerniereErreur;
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le libellé de la métrique si définie
*
* @return Le libellé de la métrique ou null
*/
public String getLibelleMetrique() {
return typeMetrique != null ? typeMetrique.getLibelle() : null;
private static final long serialVersionUID = 1L;
/** Titre du widget */
@NotBlank(message = "Le titre du widget est obligatoire")
@Size(min = 3, max = 200, message = "Le titre du widget doit contenir entre 3 et 200 caractères")
private String titre;
/** Description du widget */
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
private String description;
/** Type de widget (kpi, chart, table, gauge, progress, text) */
@NotBlank(message = "Le type de widget est obligatoire")
@Size(max = 50, message = "Le type de widget ne peut pas dépasser 50 caractères")
private String typeWidget;
/** Type de métrique affiché */
private TypeMetrique typeMetrique;
/** Période d'analyse */
private PeriodeAnalyse periodeAnalyse;
/** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Identifiant de l'utilisateur propriétaire */
@NotNull(message = "L'identifiant de l'utilisateur propriétaire est obligatoire")
private UUID utilisateurProprietaireId;
/** Nom de l'utilisateur propriétaire */
@Size(
max = 200,
message = "Le nom de l'utilisateur propriétaire ne peut pas dépasser 200 caractères")
private String nomUtilisateurProprietaire;
/** Position X du widget sur la grille */
@NotNull(message = "La position X est obligatoire")
@DecimalMin(value = "0", message = "La position X doit être positive ou nulle")
private Integer positionX;
/** Position Y du widget sur la grille */
@NotNull(message = "La position Y est obligatoire")
@DecimalMin(value = "0", message = "La position Y doit être positive ou nulle")
private Integer positionY;
/** Largeur du widget (en unités de grille) */
@NotNull(message = "La largeur est obligatoire")
@DecimalMin(value = "1", message = "La largeur minimum est 1")
@DecimalMax(value = "12", message = "La largeur maximum est 12")
private Integer largeur;
/** Hauteur du widget (en unités de grille) */
@NotNull(message = "La hauteur est obligatoire")
@DecimalMin(value = "1", message = "La hauteur minimum est 1")
@DecimalMax(value = "12", message = "La hauteur maximum est 12")
private Integer hauteur;
/** Ordre d'affichage (z-index) */
@DecimalMin(value = "0", message = "L'ordre d'affichage doit être positif ou nul")
@Builder.Default
private Integer ordreAffichage = 0;
/** Configuration visuelle du widget */
@Size(max = 5000, message = "La configuration visuelle ne peut pas dépasser 5000 caractères")
private String configurationVisuelle;
/** Couleur principale du widget */
@Size(max = 7, message = "La couleur doit être au format #RRGGBB")
private String couleurPrincipale;
/** Couleur secondaire du widget */
@Size(max = 7, message = "La couleur secondaire doit être au format #RRGGBB")
private String couleurSecondaire;
/** Icône du widget */
@Size(max = 50, message = "L'icône ne peut pas dépasser 50 caractères")
private String icone;
/** Indicateur si le widget est visible */
@Builder.Default private Boolean visible = true;
/** Indicateur si le widget est redimensionnable */
@Builder.Default private Boolean redimensionnable = true;
/** Indicateur si le widget est déplaçable */
@Builder.Default private Boolean deplacable = true;
/** Indicateur si le widget peut être supprimé */
@Builder.Default private Boolean supprimable = true;
/** Indicateur si le widget se met à jour automatiquement */
@Builder.Default private Boolean miseAJourAutomatique = true;
/** Fréquence de mise à jour en secondes */
@DecimalMin(value = "30", message = "La fréquence minimum est 30 secondes")
@Builder.Default
private Integer frequenceMiseAJourSecondes = 300; // 5 minutes par défaut
/** Date de dernière mise à jour des données */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereMiseAJour;
/** Prochaine mise à jour programmée */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime prochaineMiseAJour;
/** Données du widget (format JSON) */
@Size(max = 50000, message = "Les données du widget ne peuvent pas dépasser 50000 caractères")
private String donneesWidget;
/** Configuration des filtres */
private Map<String, Object> configurationFiltres;
/** Configuration des alertes */
private Map<String, Object> configurationAlertes;
/** Seuil d'alerte bas */
private Double seuilAlerteBas;
/** Seuil d'alerte haut */
private Double seuilAlerteHaut;
/** Indicateur si une alerte est active */
@Builder.Default private Boolean alerteActive = false;
/** Message d'alerte actuel */
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
private String messageAlerte;
/** Type d'alerte (info, warning, error, success) */
@Size(max = 20, message = "Le type d'alerte ne peut pas dépasser 20 caractères")
private String typeAlerte;
/** Permissions d'accès au widget */
@Size(max = 1000, message = "Les permissions ne peuvent pas dépasser 1000 caractères")
private String permissions;
/** Rôles autorisés à voir le widget */
@Size(max = 500, message = "Les rôles autorisés ne peuvent pas dépasser 500 caractères")
private String rolesAutorises;
/** Template personnalisé du widget */
@Size(max = 10000, message = "Le template personnalisé ne peut pas dépasser 10000 caractères")
private String templatePersonnalise;
/** CSS personnalisé du widget */
@Size(max = 5000, message = "Le CSS personnalisé ne peut pas dépasser 5000 caractères")
private String cssPersonnalise;
/** JavaScript personnalisé du widget */
@Size(max = 10000, message = "Le JavaScript personnalisé ne peut pas dépasser 10000 caractères")
private String javascriptPersonnalise;
/** Métadonnées additionnelles */
private Map<String, Object> metadonnees;
/** Nombre de vues du widget */
@DecimalMin(value = "0", message = "Le nombre de vues doit être positif")
@Builder.Default
private Long nombreVues = 0L;
/** Nombre d'interactions avec le widget */
@DecimalMin(value = "0", message = "Le nombre d'interactions doit être positif")
@Builder.Default
private Long nombreInteractions = 0L;
/** Temps moyen passé sur le widget (en secondes) */
@DecimalMin(value = "0", message = "Le temps moyen doit être positif")
private Integer tempsMoyenSecondes;
/** Taux d'erreur du widget (en pourcentage) */
@DecimalMin(value = "0.0", message = "Le taux d'erreur doit être positif")
@DecimalMax(value = "100.0", message = "Le taux d'erreur ne peut pas dépasser 100%")
@Builder.Default
private Double tauxErreur = 0.0;
/** Date de dernière erreur */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereErreur;
/** Message de dernière erreur */
@Size(max = 1000, message = "Le message d'erreur ne peut pas dépasser 1000 caractères")
private String messageDerniereErreur;
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le libellé de la métrique si définie
*
* @return Le libellé de la métrique ou null
*/
public String getLibelleMetrique() {
return typeMetrique != null ? typeMetrique.getLibelle() : null;
}
/**
* Retourne l'unité de mesure si métrique définie
*
* @return L'unité de mesure ou chaîne vide
*/
public String getUnite() {
return typeMetrique != null ? typeMetrique.getUnite() : "";
}
/**
* Retourne l'icône de la métrique ou l'icône personnalisée
*
* @return L'icône à afficher
*/
public String getIconeAffichage() {
if (icone != null && !icone.trim().isEmpty()) {
return icone;
}
/**
* Retourne l'unité de mesure si métrique définie
*
* @return L'unité de mesure ou chaîne vide
*/
public String getUnite() {
return typeMetrique != null ? typeMetrique.getUnite() : "";
}
/**
* Retourne l'icône de la métrique ou l'icône personnalisée
*
* @return L'icône à afficher
*/
public String getIconeAffichage() {
if (icone != null && !icone.trim().isEmpty()) {
return icone;
}
return typeMetrique != null ? typeMetrique.getIcone() : "dashboard";
}
/**
* Retourne la couleur de la métrique ou la couleur personnalisée
*
* @return La couleur à utiliser
*/
public String getCouleurAffichage() {
if (couleurPrincipale != null && !couleurPrincipale.trim().isEmpty()) {
return couleurPrincipale;
}
return typeMetrique != null ? typeMetrique.getCouleur() : "#757575";
}
/**
* Vérifie si le widget nécessite une mise à jour
*
* @return true si une mise à jour est nécessaire
*/
public boolean necessiteMiseAJour() {
return miseAJourAutomatique && prochaineMiseAJour != null &&
prochaineMiseAJour.isBefore(LocalDateTime.now());
}
/**
* Vérifie si le widget est interactif
*
* @return true si le widget permet des interactions
*/
public boolean isInteractif() {
return "chart".equals(typeWidget) || "table".equals(typeWidget) ||
"gauge".equals(typeWidget);
}
/**
* Vérifie si le widget affiche des données temps réel
*
* @return true si le widget est en temps réel
*/
public boolean isTempsReel() {
return frequenceMiseAJourSecondes != null && frequenceMiseAJourSecondes <= 60;
}
/**
* Retourne la taille du widget (surface occupée)
*
* @return La surface en unités de grille
*/
public int getTailleWidget() {
return largeur * hauteur;
}
/**
* Vérifie si le widget est grand (surface > 6)
*
* @return true si le widget est considéré comme grand
*/
public boolean isWidgetGrand() {
return getTailleWidget() > 6;
}
/**
* Vérifie si le widget a des erreurs récentes (< 24h)
*
* @return true si des erreurs récentes sont détectées
*/
public boolean hasErreursRecentes() {
return dateDerniereErreur != null &&
dateDerniereErreur.isAfter(LocalDateTime.now().minusHours(24));
}
/**
* Retourne le statut du widget
*
* @return "actif", "erreur", "inactif" ou "maintenance"
*/
public String getStatutWidget() {
if (hasErreursRecentes()) return "erreur";
if (!visible) return "inactif";
if (tauxErreur > 10.0) return "maintenance";
return "actif";
return typeMetrique != null ? typeMetrique.getIcone() : "dashboard";
}
/**
* Retourne la couleur de la métrique ou la couleur personnalisée
*
* @return La couleur à utiliser
*/
public String getCouleurAffichage() {
if (couleurPrincipale != null && !couleurPrincipale.trim().isEmpty()) {
return couleurPrincipale;
}
return typeMetrique != null ? typeMetrique.getCouleur() : "#757575";
}
/**
* Vérifie si le widget nécessite une mise à jour
*
* @return true si une mise à jour est nécessaire
*/
public boolean necessiteMiseAJour() {
return miseAJourAutomatique
&& prochaineMiseAJour != null
&& prochaineMiseAJour.isBefore(LocalDateTime.now());
}
/**
* Vérifie si le widget est interactif
*
* @return true si le widget permet des interactions
*/
public boolean isInteractif() {
return "chart".equals(typeWidget) || "table".equals(typeWidget) || "gauge".equals(typeWidget);
}
/**
* Vérifie si le widget affiche des données temps réel
*
* @return true si le widget est en temps réel
*/
public boolean isTempsReel() {
return frequenceMiseAJourSecondes != null && frequenceMiseAJourSecondes <= 60;
}
/**
* Retourne la taille du widget (surface occupée)
*
* @return La surface en unités de grille
*/
public int getTailleWidget() {
return largeur * hauteur;
}
/**
* Vérifie si le widget est grand (surface > 6)
*
* @return true si le widget est considéré comme grand
*/
public boolean isWidgetGrand() {
return getTailleWidget() > 6;
}
/**
* Vérifie si le widget a des erreurs récentes (< 24h)
*
* @return true si des erreurs récentes sont détectées
*/
public boolean hasErreursRecentes() {
return dateDerniereErreur != null
&& dateDerniereErreur.isAfter(LocalDateTime.now().minusHours(24));
}
/**
* Retourne le statut du widget
*
* @return "actif", "erreur", "inactif" ou "maintenance"
*/
public String getStatutWidget() {
if (hasErreursRecentes()) return "erreur";
if (!visible) return "inactif";
if (tauxErreur > 10.0) return "maintenance";
return "actif";
}
}

View File

@@ -2,30 +2,29 @@ package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.DecimalMin;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* DTO pour les tendances et évolutions des KPI UnionFlow
*
* Représente l'évolution d'un KPI dans le temps avec les points de données
* historiques pour générer des graphiques de tendance.
*
*
* <p>Représente l'évolution d'un KPI dans le temps avec les points de données historiques pour
* générer des graphiques de tendance.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -36,280 +35,275 @@ import java.util.UUID;
@NoArgsConstructor
@AllArgsConstructor
public class KPITrendDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Type de métrique pour cette tendance */
@NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique;
/** Période d'analyse globale */
@NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse;
/** Identifiant de l'organisation (optionnel) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Date de début de la période analysée */
@NotNull(message = "La date de début est obligatoire")
private static final long serialVersionUID = 1L;
/** Type de métrique pour cette tendance */
@NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique;
/** Période d'analyse globale */
@NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse;
/** Identifiant de l'organisation (optionnel) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Date de début de la période analysée */
@NotNull(message = "La date de début est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebut;
/** Date de fin de la période analysée */
@NotNull(message = "La date de fin est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFin;
/** Points de données pour la tendance */
@NotNull(message = "Les points de données sont obligatoires")
private List<PointDonneeDTO> pointsDonnees;
/** Valeur actuelle du KPI */
@NotNull(message = "La valeur actuelle est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur actuelle doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur actuelle invalide")
private BigDecimal valeurActuelle;
/** Valeur minimale sur la période */
@DecimalMin(value = "0.0", message = "La valeur minimale doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur minimale invalide")
private BigDecimal valeurMinimale;
/** Valeur maximale sur la période */
@DecimalMin(value = "0.0", message = "La valeur maximale doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur maximale invalide")
private BigDecimal valeurMaximale;
/** Valeur moyenne sur la période */
@DecimalMin(value = "0.0", message = "La valeur moyenne doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur moyenne invalide")
private BigDecimal valeurMoyenne;
/** Écart-type des valeurs */
@DecimalMin(value = "0.0", message = "L'écart-type doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format d'écart-type invalide")
private BigDecimal ecartType;
/** Coefficient de variation (écart-type / moyenne) */
@DecimalMin(value = "0.0", message = "Le coefficient de variation doit être positif ou nul")
@Digits(integer = 6, fraction = 4, message = "Format de coefficient de variation invalide")
private BigDecimal coefficientVariation;
/** Tendance générale (pente de la régression linéaire) */
@Digits(integer = 10, fraction = 6, message = "Format de tendance invalide")
private BigDecimal tendanceGenerale;
/** Coefficient de corrélation R² */
@DecimalMin(value = "0.0", message = "Le coefficient de corrélation doit être positif ou nul")
@DecimalMax(value = "1.0", message = "Le coefficient de corrélation ne peut pas dépasser 1")
@Digits(integer = 1, fraction = 6, message = "Format de coefficient de corrélation invalide")
private BigDecimal coefficientCorrelation;
/** Pourcentage d'évolution depuis le début de la période */
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
private BigDecimal pourcentageEvolutionGlobale;
/** Prédiction pour la prochaine période */
@DecimalMin(value = "0.0", message = "La prédiction doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de prédiction invalide")
private BigDecimal predictionProchainePeriode;
/** Marge d'erreur de la prédiction (en pourcentage) */
@DecimalMin(value = "0.0", message = "La marge d'erreur doit être positive ou nulle")
@DecimalMax(value = "100.0", message = "La marge d'erreur ne peut pas dépasser 100%")
@Digits(integer = 3, fraction = 2, message = "Format de marge d'erreur invalide")
private BigDecimal margeErreurPrediction;
/** Seuil d'alerte bas */
@DecimalMin(value = "0.0", message = "Le seuil d'alerte bas doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte bas invalide")
private BigDecimal seuilAlerteBas;
/** Seuil d'alerte haut */
@DecimalMin(value = "0.0", message = "Le seuil d'alerte haut doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte haut invalide")
private BigDecimal seuilAlerteHaut;
/** Indicateur si une alerte est active */
@Builder.Default private Boolean alerteActive = false;
/** Type d'alerte (bas, haut, anomalie) */
@Size(max = 50, message = "Le type d'alerte ne peut pas dépasser 50 caractères")
private String typeAlerte;
/** Message d'alerte */
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
private String messageAlerte;
/** Configuration du graphique (couleurs, style, etc.) */
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
private String configurationGraphique;
/** Intervalle de regroupement des données */
@Size(max = 20, message = "L'intervalle de regroupement ne peut pas dépasser 20 caractères")
private String intervalleRegroupement;
/** Format d'affichage des dates */
@Size(max = 20, message = "Le format de date ne peut pas dépasser 20 caractères")
private String formatDate;
/** Date de dernière mise à jour */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereMiseAJour;
/** Fréquence de mise à jour en minutes */
@DecimalMin(value = "1", message = "La fréquence de mise à jour minimum est 1 minute")
private Integer frequenceMiseAJourMinutes;
// === CLASSES INTERNES ===
/** Classe interne représentant un point de données dans la tendance */
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class PointDonneeDTO {
/** Date du point de données */
@NotNull(message = "La date du point de données est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebut;
/** Date de fin de la période analysée */
@NotNull(message = "La date de fin est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFin;
/** Points de données pour la tendance */
@NotNull(message = "Les points de données sont obligatoires")
private List<PointDonneeDTO> pointsDonnees;
/** Valeur actuelle du KPI */
@NotNull(message = "La valeur actuelle est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur actuelle doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur actuelle invalide")
private BigDecimal valeurActuelle;
/** Valeur minimale sur la période */
@DecimalMin(value = "0.0", message = "La valeur minimale doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur minimale invalide")
private BigDecimal valeurMinimale;
/** Valeur maximale sur la période */
@DecimalMin(value = "0.0", message = "La valeur maximale doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur maximale invalide")
private BigDecimal valeurMaximale;
/** Valeur moyenne sur la période */
@DecimalMin(value = "0.0", message = "La valeur moyenne doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur moyenne invalide")
private BigDecimal valeurMoyenne;
/** Écart-type des valeurs */
@DecimalMin(value = "0.0", message = "L'écart-type doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format d'écart-type invalide")
private BigDecimal ecartType;
/** Coefficient de variation (écart-type / moyenne) */
@DecimalMin(value = "0.0", message = "Le coefficient de variation doit être positif ou nul")
@Digits(integer = 6, fraction = 4, message = "Format de coefficient de variation invalide")
private BigDecimal coefficientVariation;
/** Tendance générale (pente de la régression linéaire) */
@Digits(integer = 10, fraction = 6, message = "Format de tendance invalide")
private BigDecimal tendanceGenerale;
/** Coefficient de corrélation R² */
@DecimalMin(value = "0.0", message = "Le coefficient de corrélation doit être positif ou nul")
@DecimalMax(value = "1.0", message = "Le coefficient de corrélation ne peut pas dépasser 1")
@Digits(integer = 1, fraction = 6, message = "Format de coefficient de corrélation invalide")
private BigDecimal coefficientCorrelation;
/** Pourcentage d'évolution depuis le début de la période */
@Digits(integer = 6, fraction = 2, message = "Format de pourcentage d'évolution invalide")
private BigDecimal pourcentageEvolutionGlobale;
/** Prédiction pour la prochaine période */
@DecimalMin(value = "0.0", message = "La prédiction doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de prédiction invalide")
private BigDecimal predictionProchainePeriode;
/** Marge d'erreur de la prédiction (en pourcentage) */
@DecimalMin(value = "0.0", message = "La marge d'erreur doit être positive ou nulle")
@DecimalMax(value = "100.0", message = "La marge d'erreur ne peut pas dépasser 100%")
@Digits(integer = 3, fraction = 2, message = "Format de marge d'erreur invalide")
private BigDecimal margeErreurPrediction;
/** Seuil d'alerte bas */
@DecimalMin(value = "0.0", message = "Le seuil d'alerte bas doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte bas invalide")
private BigDecimal seuilAlerteBas;
/** Seuil d'alerte haut */
@DecimalMin(value = "0.0", message = "Le seuil d'alerte haut doit être positif ou nul")
@Digits(integer = 15, fraction = 4, message = "Format de seuil d'alerte haut invalide")
private BigDecimal seuilAlerteHaut;
/** Indicateur si une alerte est active */
@Builder.Default
private Boolean alerteActive = false;
/** Type d'alerte (bas, haut, anomalie) */
@Size(max = 50, message = "Le type d'alerte ne peut pas dépasser 50 caractères")
private String typeAlerte;
/** Message d'alerte */
@Size(max = 500, message = "Le message d'alerte ne peut pas dépasser 500 caractères")
private String messageAlerte;
/** Configuration du graphique (couleurs, style, etc.) */
@Size(max = 2000, message = "La configuration graphique ne peut pas dépasser 2000 caractères")
private String configurationGraphique;
/** Intervalle de regroupement des données */
@Size(max = 20, message = "L'intervalle de regroupement ne peut pas dépasser 20 caractères")
private String intervalleRegroupement;
/** Format d'affichage des dates */
@Size(max = 20, message = "Le format de date ne peut pas dépasser 20 caractères")
private String formatDate;
/** Date de dernière mise à jour */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereMiseAJour;
/** Fréquence de mise à jour en minutes */
@DecimalMin(value = "1", message = "La fréquence de mise à jour minimum est 1 minute")
private Integer frequenceMiseAJourMinutes;
// === CLASSES INTERNES ===
/**
* Classe interne représentant un point de données dans la tendance
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class PointDonneeDTO {
/** Date du point de données */
@NotNull(message = "La date du point de données est obligatoire")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime date;
/** Valeur du point de données */
@NotNull(message = "La valeur du point de données est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur du point doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur du point invalide")
private BigDecimal valeur;
/** Libellé du point (optionnel) */
@Size(max = 100, message = "Le libellé du point ne peut pas dépasser 100 caractères")
private String libelle;
/** Indicateur si le point est une anomalie */
@Builder.Default
private Boolean anomalie = false;
/** Indicateur si le point est une prédiction */
@Builder.Default
private Boolean prediction = false;
/** Métadonnées additionnelles du point */
private String metadonnees;
}
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le libellé de la métrique
*
* @return Le libellé de la métrique
*/
public String getLibelleMetrique() {
return typeMetrique.getLibelle();
}
/**
* Retourne l'unité de mesure
*
* @return L'unité de mesure
*/
public String getUnite() {
return typeMetrique.getUnite();
}
/**
* Retourne l'icône de la métrique
*
* @return L'icône Material Design
*/
public String getIcone() {
return typeMetrique.getIcone();
}
/**
* Retourne la couleur de la métrique
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return typeMetrique.getCouleur();
}
/**
* Vérifie si la tendance est positive
*
* @return true si la tendance générale est positive
*/
public boolean isTendancePositive() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) > 0;
}
/**
* Vérifie si la tendance est négative
*
* @return true si la tendance générale est négative
*/
public boolean isTendanceNegative() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) < 0;
}
/**
* Vérifie si la tendance est stable
*
* @return true si la tendance générale est stable
*/
public boolean isTendanceStable() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) == 0;
}
/**
* Retourne la volatilité du KPI (basée sur le coefficient de variation)
*
* @return "faible", "moyenne" ou "élevée"
*/
public String getVolatilite() {
if (coefficientVariation == null) return "inconnue";
BigDecimal cv = coefficientVariation;
if (cv.compareTo(new BigDecimal("0.1")) <= 0) return "faible";
if (cv.compareTo(new BigDecimal("0.3")) <= 0) return "moyenne";
return "élevée";
}
/**
* Vérifie si la prédiction est fiable (R² > 0.7)
*
* @return true si la prédiction est considérée comme fiable
*/
public boolean isPredictionFiable() {
return coefficientCorrelation != null &&
coefficientCorrelation.compareTo(new BigDecimal("0.7")) >= 0;
}
/**
* Retourne le nombre de points de données
*
* @return Le nombre de points de données
*/
public int getNombrePointsDonnees() {
return pointsDonnees != null ? pointsDonnees.size() : 0;
}
/**
* Vérifie si des anomalies ont été détectées
*
* @return true si au moins un point est marqué comme anomalie
*/
public boolean hasAnomalies() {
return pointsDonnees != null &&
pointsDonnees.stream().anyMatch(PointDonneeDTO::getAnomalie);
}
private LocalDateTime date;
/** Valeur du point de données */
@NotNull(message = "La valeur du point de données est obligatoire")
@DecimalMin(value = "0.0", message = "La valeur du point doit être positive ou nulle")
@Digits(integer = 15, fraction = 4, message = "Format de valeur du point invalide")
private BigDecimal valeur;
/** Libellé du point (optionnel) */
@Size(max = 100, message = "Le libellé du point ne peut pas dépasser 100 caractères")
private String libelle;
/** Indicateur si le point est une anomalie */
@Builder.Default private Boolean anomalie = false;
/** Indicateur si le point est une prédiction */
@Builder.Default private Boolean prediction = false;
/** Métadonnées additionnelles du point */
private String metadonnees;
}
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le libellé de la métrique
*
* @return Le libellé de la métrique
*/
public String getLibelleMetrique() {
return typeMetrique.getLibelle();
}
/**
* Retourne l'unité de mesure
*
* @return L'unité de mesure
*/
public String getUnite() {
return typeMetrique.getUnite();
}
/**
* Retourne l'icône de la métrique
*
* @return L'icône Material Design
*/
public String getIcone() {
return typeMetrique.getIcone();
}
/**
* Retourne la couleur de la métrique
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return typeMetrique.getCouleur();
}
/**
* Vérifie si la tendance est positive
*
* @return true si la tendance générale est positive
*/
public boolean isTendancePositive() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) > 0;
}
/**
* Vérifie si la tendance est négative
*
* @return true si la tendance générale est négative
*/
public boolean isTendanceNegative() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) < 0;
}
/**
* Vérifie si la tendance est stable
*
* @return true si la tendance générale est stable
*/
public boolean isTendanceStable() {
return tendanceGenerale != null && tendanceGenerale.compareTo(BigDecimal.ZERO) == 0;
}
/**
* Retourne la volatilité du KPI (basée sur le coefficient de variation)
*
* @return "faible", "moyenne" ou "élevée"
*/
public String getVolatilite() {
if (coefficientVariation == null) return "inconnue";
BigDecimal cv = coefficientVariation;
if (cv.compareTo(new BigDecimal("0.1")) <= 0) return "faible";
if (cv.compareTo(new BigDecimal("0.3")) <= 0) return "moyenne";
return "élevée";
}
/**
* Vérifie si la prédiction est fiable (R² > 0.7)
*
* @return true si la prédiction est considérée comme fiable
*/
public boolean isPredictionFiable() {
return coefficientCorrelation != null
&& coefficientCorrelation.compareTo(new BigDecimal("0.7")) >= 0;
}
/**
* Retourne le nombre de points de données
*
* @return Le nombre de points de données
*/
public int getNombrePointsDonnees() {
return pointsDonnees != null ? pointsDonnees.size() : 0;
}
/**
* Vérifie si des anomalies ont été détectées
*
* @return true si au moins un point est marqué comme anomalie
*/
public boolean hasAnomalies() {
return pointsDonnees != null
&& pointsDonnees.stream().anyMatch(point -> Boolean.TRUE.equals(point.getAnomalie()));
}
}

View File

@@ -2,32 +2,31 @@ package dev.lions.unionflow.server.api.dto.analytics;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import dev.lions.unionflow.server.api.enums.analytics.FormatExport;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.Size;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;
import dev.lions.unionflow.server.api.enums.analytics.TypeMetrique;
import jakarta.validation.Valid;
import lombok.Getter;
import lombok.Setter;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* DTO pour la configuration des rapports analytics UnionFlow
*
* Représente la configuration d'un rapport personnalisé avec ses métriques,
* sa mise en forme et ses paramètres d'export.
*
*
* <p>Représente la configuration d'un rapport personnalisé avec ses métriques, sa mise en forme et
* ses paramètres d'export.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -38,300 +37,291 @@ import java.util.UUID;
@NoArgsConstructor
@AllArgsConstructor
public class ReportConfigDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Nom du rapport */
@NotBlank(message = "Le nom du rapport est obligatoire")
@Size(min = 3, max = 200, message = "Le nom du rapport doit contenir entre 3 et 200 caractères")
private static final long serialVersionUID = 1L;
/** Nom du rapport */
@NotBlank(message = "Le nom du rapport est obligatoire")
@Size(min = 3, max = 200, message = "Le nom du rapport doit contenir entre 3 et 200 caractères")
private String nom;
/** Description du rapport */
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
private String description;
/** Type de rapport (executif, analytique, technique, operationnel) */
@NotBlank(message = "Le type de rapport est obligatoire")
@Size(max = 50, message = "Le type de rapport ne peut pas dépasser 50 caractères")
private String typeRapport;
/** Période d'analyse par défaut */
@NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse;
/** Date de début personnalisée (si période personnalisée) */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebutPersonnalisee;
/** Date de fin personnalisée (si période personnalisée) */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFinPersonnalisee;
/** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Identifiant de l'utilisateur créateur */
@NotNull(message = "L'identifiant de l'utilisateur créateur est obligatoire")
private UUID utilisateurCreateurId;
/** Nom de l'utilisateur créateur */
@Size(max = 200, message = "Le nom de l'utilisateur créateur ne peut pas dépasser 200 caractères")
private String nomUtilisateurCreateur;
/** Métriques incluses dans le rapport */
@NotNull(message = "Les métriques sont obligatoires")
@Valid
private List<MetriqueConfigDTO> metriques;
/** Sections du rapport */
@Valid private List<SectionRapportDTO> sections;
/** Format d'export par défaut */
@NotNull(message = "Le format d'export est obligatoire")
private FormatExport formatExport;
/** Formats d'export autorisés */
private List<FormatExport> formatsExportAutorises;
/** Modèle de rapport à utiliser */
@Size(max = 100, message = "Le modèle de rapport ne peut pas dépasser 100 caractères")
private String modeleRapport;
/** Configuration de la mise en page */
@Size(
max = 2000,
message = "La configuration de mise en page ne peut pas dépasser 2000 caractères")
private String configurationMiseEnPage;
/** Logo personnalisé (URL ou base64) */
@Size(max = 5000, message = "Le logo personnalisé ne peut pas dépasser 5000 caractères")
private String logoPersonnalise;
/** Couleurs personnalisées du rapport */
private Map<String, String> couleursPersonnalisees;
/** Indicateur si le rapport est public */
@Builder.Default private Boolean rapportPublic = false;
/** Indicateur si le rapport est automatique */
@Builder.Default private Boolean rapportAutomatique = false;
/** Fréquence de génération automatique (en heures) */
@DecimalMin(value = "1", message = "La fréquence minimum est 1 heure")
private Integer frequenceGenerationHeures;
/** Prochaine génération automatique */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime prochaineGeneration;
/** Liste des destinataires pour l'envoi automatique */
private List<String> destinatairesEmail;
/** Objet de l'email pour l'envoi automatique */
@Size(max = 200, message = "L'objet de l'email ne peut pas dépasser 200 caractères")
private String objetEmail;
/** Corps de l'email pour l'envoi automatique */
@Size(max = 2000, message = "Le corps de l'email ne peut pas dépasser 2000 caractères")
private String corpsEmail;
/** Paramètres de filtrage avancé */
private Map<String, Object> parametresFiltrage;
/** Tags pour catégoriser le rapport */
private List<String> tags;
/** Niveau de confidentialité (1=public, 5=confidentiel) */
@DecimalMin(value = "1", message = "Le niveau de confidentialité minimum est 1")
@DecimalMax(value = "5", message = "Le niveau de confidentialité maximum est 5")
@Builder.Default
private Integer niveauConfidentialite = 1;
/** Date de dernière génération */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereGeneration;
/** Nombre de générations effectuées */
@DecimalMin(value = "0", message = "Le nombre de générations doit être positif")
@Builder.Default
private Integer nombreGenerations = 0;
/** Taille moyenne des rapports générés (en KB) */
@DecimalMin(value = "0", message = "La taille moyenne doit être positive")
private Long tailleMoyenneKB;
/** Temps moyen de génération (en secondes) */
@DecimalMin(value = "0", message = "Le temps moyen de génération doit être positif")
private Integer tempsMoyenGenerationSecondes;
// === CLASSES INTERNES ===
/** Configuration d'une métrique dans le rapport */
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class MetriqueConfigDTO {
/** Type de métrique */
@NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique;
/** Libellé personnalisé */
@Size(max = 200, message = "Le libellé personnalisé ne peut pas dépasser 200 caractères")
private String libellePersonnalise;
/** Position dans le rapport (ordre d'affichage) */
@DecimalMin(value = "1", message = "La position minimum est 1")
private Integer position;
/** Taille d'affichage (1=petit, 2=moyen, 3=grand) */
@DecimalMin(value = "1", message = "La taille minimum est 1")
@DecimalMax(value = "3", message = "La taille maximum est 3")
@Builder.Default
private Integer tailleAffichage = 2;
/** Couleur personnalisée */
@Size(max = 7, message = "La couleur doit être au format #RRGGBB")
private String couleurPersonnalisee;
/** Indicateur si la métrique inclut un graphique */
@Builder.Default private Boolean inclureGraphique = true;
/** Type de graphique (line, bar, pie, area) */
@Size(max = 20, message = "Le type de graphique ne peut pas dépasser 20 caractères")
@Builder.Default
private String typeGraphique = "line";
/** Indicateur si la métrique inclut la tendance */
@Builder.Default private Boolean inclureTendance = true;
/** Indicateur si la métrique inclut la comparaison */
@Builder.Default private Boolean inclureComparaison = true;
/** Seuils d'alerte personnalisés */
private Map<String, Object> seuilsAlerte;
/** Filtres spécifiques à cette métrique */
private Map<String, Object> filtresSpecifiques;
}
/** Configuration d'une section du rapport */
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SectionRapportDTO {
/** Nom de la section */
@NotBlank(message = "Le nom de la section est obligatoire")
@Size(max = 200, message = "Le nom de la section ne peut pas dépasser 200 caractères")
private String nom;
/** Description du rapport */
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
/** Description de la section */
@Size(max = 500, message = "La description de la section ne peut pas dépasser 500 caractères")
private String description;
/** Type de rapport (executif, analytique, technique, operationnel) */
@NotBlank(message = "Le type de rapport est obligatoire")
@Size(max = 50, message = "Le type de rapport ne peut pas dépasser 50 caractères")
private String typeRapport;
/** Période d'analyse par défaut */
@NotNull(message = "La période d'analyse est obligatoire")
private PeriodeAnalyse periodeAnalyse;
/** Date de début personnalisée (si période personnalisée) */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDebutPersonnalisee;
/** Date de fin personnalisée (si période personnalisée) */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateFinPersonnalisee;
/** Identifiant de l'organisation (optionnel pour filtrage) */
private UUID organisationId;
/** Nom de l'organisation */
@Size(max = 200, message = "Le nom de l'organisation ne peut pas dépasser 200 caractères")
private String nomOrganisation;
/** Identifiant de l'utilisateur créateur */
@NotNull(message = "L'identifiant de l'utilisateur créateur est obligatoire")
private UUID utilisateurCreateurId;
/** Nom de l'utilisateur créateur */
@Size(max = 200, message = "Le nom de l'utilisateur créateur ne peut pas dépasser 200 caractères")
private String nomUtilisateurCreateur;
/** Métriques incluses dans le rapport */
@NotNull(message = "Les métriques sont obligatoires")
@Valid
private List<MetriqueConfigDTO> metriques;
/** Sections du rapport */
@Valid
private List<SectionRapportDTO> sections;
/** Format d'export par défaut */
@NotNull(message = "Le format d'export est obligatoire")
private FormatExport formatExport;
/** Formats d'export autorisés */
private List<FormatExport> formatsExportAutorises;
/** Modèle de rapport à utiliser */
@Size(max = 100, message = "Le modèle de rapport ne peut pas dépasser 100 caractères")
private String modeleRapport;
/** Configuration de la mise en page */
@Size(max = 2000, message = "La configuration de mise en page ne peut pas dépasser 2000 caractères")
private String configurationMiseEnPage;
/** Logo personnalisé (URL ou base64) */
@Size(max = 5000, message = "Le logo personnalisé ne peut pas dépasser 5000 caractères")
private String logoPersonnalise;
/** Couleurs personnalisées du rapport */
private Map<String, String> couleursPersonnalisees;
/** Indicateur si le rapport est public */
@Builder.Default
private Boolean rapportPublic = false;
/** Indicateur si le rapport est automatique */
@Builder.Default
private Boolean rapportAutomatique = false;
/** Fréquence de génération automatique (en heures) */
@DecimalMin(value = "1", message = "La fréquence minimum est 1 heure")
private Integer frequenceGenerationHeures;
/** Prochaine génération automatique */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime prochaineGeneration;
/** Liste des destinataires pour l'envoi automatique */
private List<String> destinatairesEmail;
/** Objet de l'email pour l'envoi automatique */
@Size(max = 200, message = "L'objet de l'email ne peut pas dépasser 200 caractères")
private String objetEmail;
/** Corps de l'email pour l'envoi automatique */
@Size(max = 2000, message = "Le corps de l'email ne peut pas dépasser 2000 caractères")
private String corpsEmail;
/** Paramètres de filtrage avancé */
private Map<String, Object> parametresFiltrage;
/** Tags pour catégoriser le rapport */
private List<String> tags;
/** Niveau de confidentialité (1=public, 5=confidentiel) */
@DecimalMin(value = "1", message = "Le niveau de confidentialité minimum est 1")
@DecimalMax(value = "5", message = "Le niveau de confidentialité maximum est 5")
@Builder.Default
private Integer niveauConfidentialite = 1;
/** Date de dernière génération */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateDerniereGeneration;
/** Nombre de générations effectuées */
@DecimalMin(value = "0", message = "Le nombre de générations doit être positif")
@Builder.Default
private Integer nombreGenerations = 0;
/** Taille moyenne des rapports générés (en KB) */
@DecimalMin(value = "0", message = "La taille moyenne doit être positive")
private Long tailleMoyenneKB;
/** Temps moyen de génération (en secondes) */
@DecimalMin(value = "0", message = "Le temps moyen de génération doit être positif")
private Integer tempsMoyenGenerationSecondes;
// === CLASSES INTERNES ===
/**
* Configuration d'une métrique dans le rapport
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class MetriqueConfigDTO {
/** Type de métrique */
@NotNull(message = "Le type de métrique est obligatoire")
private TypeMetrique typeMetrique;
/** Libellé personnalisé */
@Size(max = 200, message = "Le libellé personnalisé ne peut pas dépasser 200 caractères")
private String libellePersonnalise;
/** Position dans le rapport (ordre d'affichage) */
@DecimalMin(value = "1", message = "La position minimum est 1")
private Integer position;
/** Taille d'affichage (1=petit, 2=moyen, 3=grand) */
@DecimalMin(value = "1", message = "La taille minimum est 1")
@DecimalMax(value = "3", message = "La taille maximum est 3")
@Builder.Default
private Integer tailleAffichage = 2;
/** Couleur personnalisée */
@Size(max = 7, message = "La couleur doit être au format #RRGGBB")
private String couleurPersonnalisee;
/** Indicateur si la métrique inclut un graphique */
@Builder.Default
private Boolean inclureGraphique = true;
/** Type de graphique (line, bar, pie, area) */
@Size(max = 20, message = "Le type de graphique ne peut pas dépasser 20 caractères")
@Builder.Default
private String typeGraphique = "line";
/** Indicateur si la métrique inclut la tendance */
@Builder.Default
private Boolean inclureTendance = true;
/** Indicateur si la métrique inclut la comparaison */
@Builder.Default
private Boolean inclureComparaison = true;
/** Seuils d'alerte personnalisés */
private Map<String, Object> seuilsAlerte;
/** Filtres spécifiques à cette métrique */
private Map<String, Object> filtresSpecifiques;
}
/**
* Configuration d'une section du rapport
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SectionRapportDTO {
/** Nom de la section */
@NotBlank(message = "Le nom de la section est obligatoire")
@Size(max = 200, message = "Le nom de la section ne peut pas dépasser 200 caractères")
private String nom;
/** Description de la section */
@Size(max = 500, message = "La description de la section ne peut pas dépasser 500 caractères")
private String description;
/** Position de la section dans le rapport */
@DecimalMin(value = "1", message = "La position minimum est 1")
private Integer position;
/** Type de section (resume, metriques, graphiques, tableaux, analyse) */
@NotBlank(message = "Le type de section est obligatoire")
@Size(max = 50, message = "Le type de section ne peut pas dépasser 50 caractères")
private String typeSection;
/** Métriques incluses dans cette section */
private List<TypeMetrique> metriquesIncluses;
/** Configuration spécifique de la section */
private Map<String, Object> configurationSection;
/** Indicateur si la section est visible */
@Builder.Default
private Boolean visible = true;
/** Indicateur si la section peut être réduite */
@Builder.Default
private Boolean pliable = false;
}
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le nombre de métriques configurées
*
* @return Le nombre de métriques
*/
public int getNombreMetriques() {
return metriques != null ? metriques.size() : 0;
}
/**
* Retourne le nombre de sections configurées
*
* @return Le nombre de sections
*/
public int getNombreSections() {
return sections != null ? sections.size() : 0;
}
/**
* Vérifie si le rapport utilise une période personnalisée
*
* @return true si la période est personnalisée
*/
public boolean isPeriodePersonnalisee() {
return periodeAnalyse == PeriodeAnalyse.PERIODE_PERSONNALISEE;
}
/**
* Vérifie si le rapport est confidentiel (niveau >= 4)
*
* @return true si le rapport est confidentiel
*/
public boolean isConfidentiel() {
return niveauConfidentialite != null && niveauConfidentialite >= 4;
}
/**
* Vérifie si le rapport nécessite une génération
*
* @return true si la prochaine génération est due
*/
public boolean necessiteGeneration() {
return rapportAutomatique && prochaineGeneration != null &&
prochaineGeneration.isBefore(LocalDateTime.now());
}
/**
* Retourne la fréquence de génération en texte
*
* @return La fréquence sous forme de texte
*/
public String getFrequenceTexte() {
if (frequenceGenerationHeures == null) return "Manuelle";
return switch (frequenceGenerationHeures) {
case 1 -> "Toutes les heures";
case 24 -> "Quotidienne";
case 168 -> "Hebdomadaire"; // 24 * 7
case 720 -> "Mensuelle"; // 24 * 30
default -> "Toutes les " + frequenceGenerationHeures + " heures";
};
}
/** Position de la section dans le rapport */
@DecimalMin(value = "1", message = "La position minimum est 1")
private Integer position;
/** Type de section (resume, metriques, graphiques, tableaux, analyse) */
@NotBlank(message = "Le type de section est obligatoire")
@Size(max = 50, message = "Le type de section ne peut pas dépasser 50 caractères")
private String typeSection;
/** Métriques incluses dans cette section */
private List<TypeMetrique> metriquesIncluses;
/** Configuration spécifique de la section */
private Map<String, Object> configurationSection;
/** Indicateur si la section est visible */
@Builder.Default private Boolean visible = true;
/** Indicateur si la section peut être réduite */
@Builder.Default private Boolean pliable = false;
}
// === MÉTHODES UTILITAIRES ===
/**
* Retourne le nombre de métriques configurées
*
* @return Le nombre de métriques
*/
public int getNombreMetriques() {
return metriques != null ? metriques.size() : 0;
}
/**
* Retourne le nombre de sections configurées
*
* @return Le nombre de sections
*/
public int getNombreSections() {
return sections != null ? sections.size() : 0;
}
/**
* Vérifie si le rapport utilise une période personnalisée
*
* @return true si la période est personnalisée
*/
public boolean isPeriodePersonnalisee() {
return periodeAnalyse == PeriodeAnalyse.PERIODE_PERSONNALISEE;
}
/**
* Vérifie si le rapport est confidentiel (niveau >= 4)
*
* @return true si le rapport est confidentiel
*/
public boolean isConfidentiel() {
return niveauConfidentialite != null && niveauConfidentialite >= 4;
}
/**
* Vérifie si le rapport nécessite une génération
*
* @return true si la prochaine génération est due
*/
public boolean necessiteGeneration() {
return rapportAutomatique
&& prochaineGeneration != null
&& prochaineGeneration.isBefore(LocalDateTime.now());
}
/**
* Retourne la fréquence de génération en texte
*
* @return La fréquence sous forme de texte
*/
public String getFrequenceTexte() {
if (frequenceGenerationHeures == null) return "Manuelle";
return switch (frequenceGenerationHeures) {
case 1 -> "Toutes les heures";
case 24 -> "Quotidienne";
case 168 -> "Hebdomadaire"; // 24 * 7
case 720 -> "Mensuelle"; // 24 * 30
default -> "Toutes les " + frequenceGenerationHeures + " heures";
};
}
}

View File

@@ -1,6 +1,7 @@
package dev.lions.unionflow.server.api.dto.base;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.UUID;
@@ -18,18 +19,18 @@ import lombok.Setter;
@Setter
public abstract class BaseDTO implements Serializable {
private static final long serialVersionUID = 1L;
@Serial private static final long serialVersionUID = 1L;
/** Identifiant unique UUID */
private UUID id;
/** Date de création de l'enregistrement */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateCreation;
public LocalDateTime dateCreation;
/** Date de dernière modification */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateModification;
public LocalDateTime dateModification;
/** Utilisateur qui a créé l'enregistrement */
private String creePar;

View File

@@ -2,6 +2,10 @@ package dev.lions.unionflow.server.api.dto.evenement;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import dev.lions.unionflow.server.api.validation.ValidationConstants;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
@@ -36,30 +40,29 @@ public class EvenementDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Titre de l'événement */
@NotBlank(message = "Le titre est obligatoire")
@Size(min = 3, max = 100, message = "Le titre doit contenir entre 3 et 100 caractères")
@NotBlank(message = "Le titre" + ValidationConstants.OBLIGATOIRE_MESSAGE)
@Size(
min = ValidationConstants.TITRE_MIN_LENGTH,
max = ValidationConstants.TITRE_MAX_LENGTH,
message = ValidationConstants.TITRE_SIZE_MESSAGE)
private String titre;
/** Description détaillée de l'événement */
@Size(max = 1000, message = "La description ne peut pas dépasser 1000 caractères")
@Size(
max = ValidationConstants.DESCRIPTION_COURTE_MAX_LENGTH,
message = ValidationConstants.DESCRIPTION_COURTE_SIZE_MESSAGE)
private String description;
/** Type d'événement */
@NotNull(message = "Le type d'événement est obligatoire")
@Pattern(
regexp =
"^(ASSEMBLEE_GENERALE|FORMATION|ACTIVITE_SOCIALE|ACTION_CARITATIVE|REUNION_BUREAU|CONFERENCE|ATELIER|CEREMONIE|AUTRE)$",
message = "Type d'événement invalide")
private String typeEvenement;
private TypeEvenementMetier typeEvenement;
/** Statut de l'événement */
@NotNull(message = "Le statut est obligatoire")
@Pattern(regexp = "^(PLANIFIE|EN_COURS|TERMINE|ANNULE|REPORTE)$", message = "Statut invalide")
private String statut;
private StatutEvenement statut;
/** Priorité de l'événement */
@Pattern(regexp = "^(BASSE|NORMALE|HAUTE|CRITIQUE)$", message = "Priorité invalide")
private String priorite;
private PrioriteEvenement priorite;
/** Date de début de l'événement */
@JsonFormat(pattern = "yyyy-MM-dd")
@@ -140,17 +143,29 @@ public class EvenementDTO extends BaseDTO {
private Integer participantsPresents;
/** Budget prévu pour l'événement */
@DecimalMin(value = "0.0", message = "Le budget ne peut pas être négatif")
@Digits(integer = 10, fraction = 2, message = "Format de budget invalide")
@DecimalMin(
value = ValidationConstants.MONTANT_MIN_VALUE,
message = ValidationConstants.MONTANT_POSITIF_MESSAGE)
@Digits(
integer = ValidationConstants.MONTANT_INTEGER_DIGITS,
fraction = ValidationConstants.MONTANT_FRACTION_DIGITS,
message = ValidationConstants.MONTANT_DIGITS_MESSAGE)
private BigDecimal budget;
/** Coût réel de l'événement */
@DecimalMin(value = "0.0", message = "Le coût ne peut pas être négatif")
@Digits(integer = 10, fraction = 2, message = "Format de coût invalide")
@DecimalMin(
value = ValidationConstants.MONTANT_MIN_VALUE,
message = ValidationConstants.MONTANT_POSITIF_MESSAGE)
@Digits(
integer = ValidationConstants.MONTANT_INTEGER_DIGITS,
fraction = ValidationConstants.MONTANT_FRACTION_DIGITS,
message = ValidationConstants.MONTANT_DIGITS_MESSAGE)
private BigDecimal coutReel;
/** Code de la devise */
@Size(min = 3, max = 3, message = "Le code devise doit faire exactement 3 caractères")
@Pattern(
regexp = ValidationConstants.DEVISE_PATTERN,
message = ValidationConstants.DEVISE_MESSAGE)
private String codeDevise;
/** Indique si l'inscription est obligatoire */
@@ -209,8 +224,8 @@ public class EvenementDTO extends BaseDTO {
// Constructeurs
public EvenementDTO() {
super();
this.statut = "PLANIFIE";
this.priorite = "NORMALE";
this.statut = StatutEvenement.PLANIFIE;
this.priorite = PrioriteEvenement.NORMALE;
this.participantsInscrits = 0;
this.participantsPresents = 0;
this.inscriptionObligatoire = false;
@@ -219,7 +234,8 @@ public class EvenementDTO extends BaseDTO {
this.codeDevise = "XOF"; // Franc CFA par défaut
}
public EvenementDTO(String titre, String typeEvenement, LocalDate dateDebut, String lieu) {
public EvenementDTO(
String titre, TypeEvenementMetier typeEvenement, LocalDate dateDebut, String lieu) {
this();
this.titre = titre;
this.typeEvenement = typeEvenement;
@@ -244,27 +260,27 @@ public class EvenementDTO extends BaseDTO {
this.description = description;
}
public String getTypeEvenement() {
public TypeEvenementMetier getTypeEvenement() {
return typeEvenement;
}
public void setTypeEvenement(String typeEvenement) {
public void setTypeEvenement(TypeEvenementMetier typeEvenement) {
this.typeEvenement = typeEvenement;
}
public String getStatut() {
public StatutEvenement getStatut() {
return statut;
}
public void setStatut(String statut) {
public void setStatut(StatutEvenement statut) {
this.statut = statut;
}
public String getPriorite() {
public PrioriteEvenement getPriorite() {
return priorite;
}
public void setPriorite(String priorite) {
public void setPriorite(PrioriteEvenement priorite) {
this.priorite = priorite;
}
@@ -555,8 +571,8 @@ public class EvenementDTO extends BaseDTO {
*
* @return true si l'événement est actuellement en cours
*/
public boolean isEnCours() {
return "EN_COURS".equals(statut);
public boolean estEnCours() {
return StatutEvenement.EN_COURS.equals(statut);
}
/**
@@ -564,8 +580,8 @@ public class EvenementDTO extends BaseDTO {
*
* @return true si l'événement est terminé
*/
public boolean isTermine() {
return "TERMINE".equals(statut);
public boolean estTermine() {
return StatutEvenement.TERMINE.equals(statut);
}
/**
@@ -573,8 +589,8 @@ public class EvenementDTO extends BaseDTO {
*
* @return true si l'événement est annulé
*/
public boolean isAnnule() {
return "ANNULE".equals(statut);
public boolean estAnnule() {
return StatutEvenement.ANNULE.equals(statut);
}
/**
@@ -582,7 +598,7 @@ public class EvenementDTO extends BaseDTO {
*
* @return true si le nombre d'inscrits atteint la capacité maximale
*/
public boolean isComplet() {
public boolean estComplet() {
return capaciteMax != null
&& participantsInscrits != null
&& participantsInscrits >= capaciteMax;
@@ -629,8 +645,8 @@ public class EvenementDTO extends BaseDTO {
*
* @return true si les inscriptions sont ouvertes
*/
public boolean isInscriptionsOuvertes() {
if (isAnnule() || isTermine()) {
public boolean sontInscriptionsOuvertes() {
if (estAnnule() || estTermine()) {
return false;
}
@@ -638,7 +654,7 @@ public class EvenementDTO extends BaseDTO {
return false;
}
return !isComplet();
return !estComplet();
}
/**
@@ -659,7 +675,7 @@ public class EvenementDTO extends BaseDTO {
*
* @return true si l'événement s'étend sur plusieurs jours
*/
public boolean isEvenementMultiJours() {
public boolean estEvenementMultiJours() {
return dateFin != null && !dateDebut.equals(dateFin);
}
@@ -669,20 +685,7 @@ public class EvenementDTO extends BaseDTO {
* @return Le libellé du type
*/
public String getTypeEvenementLibelle() {
if (typeEvenement == null) return "Non défini";
return switch (typeEvenement) {
case "ASSEMBLEE_GENERALE" -> "Assemblée Générale";
case "FORMATION" -> "Formation";
case "ACTIVITE_SOCIALE" -> "Activité Sociale";
case "ACTION_CARITATIVE" -> "Action Caritative";
case "REUNION_BUREAU" -> "Réunion de Bureau";
case "CONFERENCE" -> "Conférence";
case "ATELIER" -> "Atelier";
case "CEREMONIE" -> "Cérémonie";
case "AUTRE" -> "Autre";
default -> typeEvenement;
};
return typeEvenement != null ? typeEvenement.getLibelle() : "Non défini";
}
/**
@@ -691,16 +694,7 @@ public class EvenementDTO extends BaseDTO {
* @return Le libellé du statut
*/
public String getStatutLibelle() {
if (statut == null) return "Non défini";
return switch (statut) {
case "PLANIFIE" -> "Planifié";
case "EN_COURS" -> "En cours";
case "TERMINE" -> "Terminé";
case "ANNULE" -> "Annulé";
case "REPORTE" -> "Reporté";
default -> statut;
};
return statut != null ? statut.getLibelle() : "Non défini";
}
/**
@@ -709,15 +703,7 @@ public class EvenementDTO extends BaseDTO {
* @return Le libellé de la priorité
*/
public String getPrioriteLibelle() {
if (priorite == null) return "Normale";
return switch (priorite) {
case "BASSE" -> "Basse";
case "NORMALE" -> "Normale";
case "HAUTE" -> "Haute";
case "CRITIQUE" -> "Critique";
default -> priorite;
};
return priorite != null ? priorite.getLibelle() : "Normale";
}
/**
@@ -776,7 +762,7 @@ public class EvenementDTO extends BaseDTO {
*
* @return true si le coût réel dépasse le budget
*/
public boolean isBudgetDepasse() {
public boolean estBudgetDepasse() {
return getEcartBudgetaire().compareTo(BigDecimal.ZERO) < 0;
}

View File

@@ -13,6 +13,7 @@ import jakarta.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.UUID;
import lombok.Getter;
import lombok.Setter;
@@ -449,7 +450,7 @@ public class CotisationDTO extends BaseDTO {
if (dateEcheance == null || !isEnRetard()) {
return 0;
}
return dateEcheance.until(LocalDate.now()).getDays();
return ChronoUnit.DAYS.between(dateEcheance, LocalDate.now());
}
/**

View File

@@ -2,6 +2,8 @@ package dev.lions.unionflow.server.api.dto.membre;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.membre.StatutMembre;
import dev.lions.unionflow.server.api.validation.ValidationConstants;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -27,31 +29,39 @@ public class MembreDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Numéro unique du membre (format: UF-YYYY-XXXXXXXX) */
@NotBlank(message = "Le numéro de membre est obligatoire")
@NotBlank(message = "Le numéro de membre" + ValidationConstants.OBLIGATOIRE_MESSAGE)
@Pattern(
regexp = "^UF-\\d{4}-[A-Z0-9]{8}$",
message = "Format de numéro de membre invalide (UF-YYYY-XXXXXXXX)")
regexp = ValidationConstants.NUMERO_MEMBRE_PATTERN,
message = ValidationConstants.NUMERO_MEMBRE_MESSAGE)
private String numeroMembre;
/** Nom de famille du membre */
@NotBlank(message = "Le nom est obligatoire")
@Size(min = 2, max = 50, message = "Le nom doit contenir entre 2 et 50 caractères")
@NotBlank(message = "Le nom" + ValidationConstants.OBLIGATOIRE_MESSAGE)
@Size(
min = ValidationConstants.NOM_PRENOM_MIN_LENGTH,
max = ValidationConstants.NOM_PRENOM_MAX_LENGTH,
message = ValidationConstants.NOM_SIZE_MESSAGE)
@Pattern(
regexp = "^[a-zA-ZÀ-ÿ\\s\\-']+$",
message = "Le nom ne peut contenir que des lettres, espaces, tirets et apostrophes")
private String nom;
/** Prénom du membre */
@NotBlank(message = "Le prénom est obligatoire")
@Size(min = 2, max = 50, message = "Le prénom doit contenir entre 2 et 50 caractères")
@NotBlank(message = "Le prénom" + ValidationConstants.OBLIGATOIRE_MESSAGE)
@Size(
min = ValidationConstants.NOM_PRENOM_MIN_LENGTH,
max = ValidationConstants.NOM_PRENOM_MAX_LENGTH,
message = ValidationConstants.PRENOM_SIZE_MESSAGE)
@Pattern(
regexp = "^[a-zA-ZÀ-ÿ\\s\\-']+$",
message = "Le prénom ne peut contenir que des lettres, espaces, tirets et apostrophes")
private String prenom;
/** Adresse email du membre */
@Email(message = "Format d'email invalide")
@Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
@Email(message = ValidationConstants.EMAIL_FORMAT_MESSAGE)
@Size(
max = ValidationConstants.EMAIL_MAX_LENGTH,
message = ValidationConstants.EMAIL_SIZE_MESSAGE)
private String email;
/** Numéro de téléphone du membre */
@@ -87,10 +97,9 @@ public class MembreDTO extends BaseDTO {
@Size(max = 20, message = "Le type d'identité ne peut pas dépasser 20 caractères")
private String typeIdentite;
/** Statut du membre (ACTIF, INACTIF, SUSPENDU, RADIE) */
/** Statut du membre */
@NotNull(message = "Le statut est obligatoire")
@Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
private String statut;
private StatutMembre statut;
/** Identifiant de l'association à laquelle appartient le membre */
@NotNull(message = "L'association est obligatoire")
@@ -132,7 +141,7 @@ public class MembreDTO extends BaseDTO {
// Constructeurs
public MembreDTO() {
super();
this.statut = "ACTIF";
this.statut = StatutMembre.ACTIF;
this.dateAdhesion = LocalDate.now();
this.membreBureau = false;
this.responsable = false;
@@ -243,11 +252,11 @@ public class MembreDTO extends BaseDTO {
this.typeIdentite = typeIdentite;
}
public String getStatut() {
public StatutMembre getStatut() {
return statut;
}
public void setStatut(String statut) {
public void setStatut(StatutMembre statut) {
this.statut = statut;
}
@@ -354,7 +363,7 @@ public class MembreDTO extends BaseDTO {
*
* @return true si le membre est majeur, false sinon
*/
public boolean isMajeur() {
public boolean estMajeur() {
if (dateNaissance == null) {
return false;
}
@@ -379,8 +388,8 @@ public class MembreDTO extends BaseDTO {
*
* @return true si le statut est ACTIF
*/
public boolean isActif() {
return "ACTIF".equals(statut);
public boolean estActif() {
return StatutMembre.ACTIF.equals(statut);
}
/**
@@ -398,15 +407,7 @@ public class MembreDTO extends BaseDTO {
* @return Le libellé du statut
*/
public String getStatutLibelle() {
if (statut == null) return "Non défini";
return switch (statut) {
case "ACTIF" -> "Actif";
case "INACTIF" -> "Inactif";
case "SUSPENDU" -> "Suspendu";
case "RADIE" -> "Radié";
default -> statut;
};
return statut != null ? statut.getLibelle() : "Non défini";
}
/**
@@ -414,7 +415,7 @@ public class MembreDTO extends BaseDTO {
*
* @return true si les données sont valides
*/
public boolean isDataValid() {
public boolean sontDonneesValides() {
return numeroMembre != null
&& !numeroMembre.trim().isEmpty()
&& nom != null
@@ -422,7 +423,6 @@ public class MembreDTO extends BaseDTO {
&& prenom != null
&& !prenom.trim().isEmpty()
&& statut != null
&& !statut.trim().isEmpty()
&& associationId != null;
}

View File

@@ -5,20 +5,19 @@ import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
/**
* DTO pour les critères de recherche avancée des membres
* Permet de filtrer les membres selon de multiples critères
*
* DTO pour les critères de recherche avancée des membres Permet de filtrer les membres selon de
* multiples critères
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-19
@@ -30,200 +29,198 @@ import java.util.UUID;
@Schema(description = "Critères de recherche avancée pour les membres")
public class MembreSearchCriteria {
/** Terme de recherche général (nom, prénom, email) */
@Schema(description = "Terme de recherche général dans nom, prénom ou email", example = "marie")
@Size(max = 100, message = "Le terme de recherche ne peut pas dépasser 100 caractères")
private String query;
/** Terme de recherche général (nom, prénom, email) */
@Schema(description = "Terme de recherche général dans nom, prénom ou email", example = "marie")
@Size(max = 100, message = "Le terme de recherche ne peut pas dépasser 100 caractères")
private String query;
/** Recherche par nom exact ou partiel */
@Schema(description = "Filtre par nom (recherche partielle)", example = "Dupont")
@Size(max = 50, message = "Le nom ne peut pas dépasser 50 caractères")
private String nom;
/** Recherche par nom exact ou partiel */
@Schema(description = "Filtre par nom (recherche partielle)", example = "Dupont")
@Size(max = 50, message = "Le nom ne peut pas dépasser 50 caractères")
private String nom;
/** Recherche par prénom exact ou partiel */
@Schema(description = "Filtre par prénom (recherche partielle)", example = "Marie")
@Size(max = 50, message = "Le prénom ne peut pas dépasser 50 caractères")
private String prenom;
/** Recherche par prénom exact ou partiel */
@Schema(description = "Filtre par prénom (recherche partielle)", example = "Marie")
@Size(max = 50, message = "Le prénom ne peut pas dépasser 50 caractères")
private String prenom;
/** Recherche par email exact ou partiel */
@Schema(description = "Filtre par email (recherche partielle)", example = "@unionflow.com")
@Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
private String email;
/** Recherche par email exact ou partiel */
@Schema(description = "Filtre par email (recherche partielle)", example = "@unionflow.com")
@Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
private String email;
/** Filtre par numéro de téléphone */
@Schema(description = "Filtre par numéro de téléphone", example = "+221")
@Size(max = 20, message = "Le téléphone ne peut pas dépasser 20 caractères")
private String telephone;
/** Filtre par numéro de téléphone */
@Schema(description = "Filtre par numéro de téléphone", example = "+221")
@Size(max = 20, message = "Le téléphone ne peut pas dépasser 20 caractères")
private String telephone;
/** Liste des IDs d'organisations */
@Schema(description = "Liste des IDs d'organisations à inclure")
private List<UUID> organisationIds;
/** Liste des IDs d'organisations */
@Schema(description = "Liste des IDs d'organisations à inclure")
private List<UUID> organisationIds;
/** Liste des rôles à rechercher */
@Schema(description = "Liste des rôles à rechercher", example = "[\"PRESIDENT\", \"SECRETAIRE\"]")
private List<String> roles;
/** Liste des rôles à rechercher */
@Schema(description = "Liste des rôles à rechercher", example = "[\"PRESIDENT\", \"SECRETAIRE\"]")
private List<String> roles;
/** Filtre par statut d'activité */
@Schema(description = "Filtre par statut d'activité", example = "ACTIF")
@Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
private String statut;
/** Filtre par statut d'activité */
@Schema(description = "Filtre par statut d'activité", example = "ACTIF")
@Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
private String statut;
/** Date d'adhésion minimum */
@Schema(description = "Date d'adhésion minimum", example = "2020-01-01")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateAdhesionMin;
/** Date d'adhésion minimum */
@Schema(description = "Date d'adhésion minimum", example = "2020-01-01")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateAdhesionMin;
/** Date d'adhésion maximum */
@Schema(description = "Date d'adhésion maximum", example = "2025-12-31")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateAdhesionMax;
/** Date d'adhésion maximum */
@Schema(description = "Date d'adhésion maximum", example = "2025-12-31")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateAdhesionMax;
/** Âge minimum */
@Schema(description = "Âge minimum", example = "18")
@Min(value = 0, message = "L'âge minimum doit être positif")
@Max(value = 120, message = "L'âge minimum ne peut pas dépasser 120 ans")
private Integer ageMin;
/** Âge minimum */
@Schema(description = "Âge minimum", example = "18")
@Min(value = 0, message = "L'âge minimum doit être positif")
@Max(value = 120, message = "L'âge minimum ne peut pas dépasser 120 ans")
private Integer ageMin;
/** Âge maximum */
@Schema(description = "Âge maximum", example = "65")
@Min(value = 0, message = "L'âge maximum doit être positif")
@Max(value = 120, message = "L'âge maximum ne peut pas dépasser 120 ans")
private Integer ageMax;
/** Âge maximum */
@Schema(description = "Âge maximum", example = "65")
@Min(value = 0, message = "L'âge maximum doit être positif")
@Max(value = 120, message = "L'âge maximum ne peut pas dépasser 120 ans")
private Integer ageMax;
/** Filtre par région */
@Schema(description = "Filtre par région", example = "Dakar")
@Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
private String region;
/** Filtre par région */
@Schema(description = "Filtre par région", example = "Dakar")
@Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
private String region;
/** Filtre par ville */
@Schema(description = "Filtre par ville", example = "Dakar")
@Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
private String ville;
/** Filtre par ville */
@Schema(description = "Filtre par ville", example = "Dakar")
@Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
private String ville;
/** Filtre par profession */
@Schema(description = "Filtre par profession", example = "Ingénieur")
@Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères")
private String profession;
/** Filtre par profession */
@Schema(description = "Filtre par profession", example = "Ingénieur")
@Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères")
private String profession;
/** Filtre par nationalité */
@Schema(description = "Filtre par nationalité", example = "Sénégalaise")
@Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères")
private String nationalite;
/** Filtre par nationalité */
@Schema(description = "Filtre par nationalité", example = "Sénégalaise")
@Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères")
private String nationalite;
/** Filtre membres du bureau uniquement */
@Schema(description = "Filtre pour les membres du bureau uniquement")
private Boolean membreBureau;
/** Filtre membres du bureau uniquement */
@Schema(description = "Filtre pour les membres du bureau uniquement")
private Boolean membreBureau;
/** Filtre responsables uniquement */
@Schema(description = "Filtre pour les responsables uniquement")
private Boolean responsable;
/** Filtre responsables uniquement */
@Schema(description = "Filtre pour les responsables uniquement")
private Boolean responsable;
/** Inclure les membres inactifs dans la recherche */
@Schema(description = "Inclure les membres inactifs", defaultValue = "false")
@Builder.Default
private Boolean includeInactifs = false;
/** Inclure les membres inactifs dans la recherche */
@Schema(description = "Inclure les membres inactifs", defaultValue = "false")
@Builder.Default
private Boolean includeInactifs = false;
/**
* Vérifie si au moins un critère de recherche est défini
*
* @return true si au moins un critère est défini
*/
public boolean hasAnyCriteria() {
return query != null && !query.trim().isEmpty() ||
nom != null && !nom.trim().isEmpty() ||
prenom != null && !prenom.trim().isEmpty() ||
email != null && !email.trim().isEmpty() ||
telephone != null && !telephone.trim().isEmpty() ||
organisationIds != null && !organisationIds.isEmpty() ||
roles != null && !roles.isEmpty() ||
statut != null && !statut.trim().isEmpty() ||
dateAdhesionMin != null ||
dateAdhesionMax != null ||
ageMin != null ||
ageMax != null ||
region != null && !region.trim().isEmpty() ||
ville != null && !ville.trim().isEmpty() ||
profession != null && !profession.trim().isEmpty() ||
nationalite != null && !nationalite.trim().isEmpty() ||
membreBureau != null ||
responsable != null;
/**
* Vérifie si au moins un critère de recherche est défini
*
* @return true si au moins un critère est défini
*/
public boolean hasAnyCriteria() {
return query != null && !query.trim().isEmpty()
|| nom != null && !nom.trim().isEmpty()
|| prenom != null && !prenom.trim().isEmpty()
|| email != null && !email.trim().isEmpty()
|| telephone != null && !telephone.trim().isEmpty()
|| organisationIds != null && !organisationIds.isEmpty()
|| roles != null && !roles.isEmpty()
|| statut != null && !statut.trim().isEmpty()
|| dateAdhesionMin != null
|| dateAdhesionMax != null
|| ageMin != null
|| ageMax != null
|| region != null && !region.trim().isEmpty()
|| ville != null && !ville.trim().isEmpty()
|| profession != null && !profession.trim().isEmpty()
|| nationalite != null && !nationalite.trim().isEmpty()
|| membreBureau != null
|| responsable != null;
}
/**
* Valide la cohérence des critères de recherche
*
* @return true si les critères sont cohérents
*/
public boolean isValid() {
// Validation des dates
if (dateAdhesionMin != null && dateAdhesionMax != null) {
if (dateAdhesionMin.isAfter(dateAdhesionMax)) {
return false;
}
}
/**
* Valide la cohérence des critères de recherche
*
* @return true si les critères sont cohérents
*/
public boolean isValid() {
// Validation des dates
if (dateAdhesionMin != null && dateAdhesionMax != null) {
if (dateAdhesionMin.isAfter(dateAdhesionMax)) {
return false;
}
}
// Validation des âges
if (ageMin != null && ageMax != null) {
if (ageMin > ageMax) {
return false;
}
}
return true;
// Validation des âges
if (ageMin != null && ageMax != null) {
if (ageMin > ageMax) {
return false;
}
}
/**
* Nettoie les chaînes de caractères (trim et null si vide)
*/
public void sanitize() {
query = sanitizeString(query);
nom = sanitizeString(nom);
prenom = sanitizeString(prenom);
email = sanitizeString(email);
telephone = sanitizeString(telephone);
statut = sanitizeString(statut);
region = sanitizeString(region);
ville = sanitizeString(ville);
profession = sanitizeString(profession);
nationalite = sanitizeString(nationalite);
}
return true;
}
private String sanitizeString(String str) {
if (str == null) return null;
str = str.trim();
return str.isEmpty() ? null : str;
}
/** Nettoie les chaînes de caractères (trim et null si vide) */
public void sanitize() {
query = sanitizeString(query);
nom = sanitizeString(nom);
prenom = sanitizeString(prenom);
email = sanitizeString(email);
telephone = sanitizeString(telephone);
statut = sanitizeString(statut);
region = sanitizeString(region);
ville = sanitizeString(ville);
profession = sanitizeString(profession);
nationalite = sanitizeString(nationalite);
}
/**
* Retourne une description textuelle des critères actifs
*
* @return Description des critères
*/
public String getDescription() {
StringBuilder sb = new StringBuilder();
if (query != null) sb.append("Recherche: '").append(query).append("' ");
if (nom != null) sb.append("Nom: '").append(nom).append("' ");
if (prenom != null) sb.append("Prénom: '").append(prenom).append("' ");
if (email != null) sb.append("Email: '").append(email).append("' ");
if (statut != null) sb.append("Statut: ").append(statut).append(" ");
if (organisationIds != null && !organisationIds.isEmpty()) {
sb.append("Organisations: ").append(organisationIds.size()).append(" ");
}
if (roles != null && !roles.isEmpty()) {
sb.append("Rôles: ").append(String.join(", ", roles)).append(" ");
}
if (dateAdhesionMin != null) sb.append("Adhésion >= ").append(dateAdhesionMin).append(" ");
if (dateAdhesionMax != null) sb.append("Adhésion <= ").append(dateAdhesionMax).append(" ");
if (ageMin != null) sb.append("Âge >= ").append(ageMin).append(" ");
if (ageMax != null) sb.append("Âge <= ").append(ageMax).append(" ");
if (region != null) sb.append("Région: '").append(region).append("' ");
if (ville != null) sb.append("Ville: '").append(ville).append("' ");
if (profession != null) sb.append("Profession: '").append(profession).append("' ");
if (nationalite != null) sb.append("Nationalité: '").append(nationalite).append("' ");
if (Boolean.TRUE.equals(membreBureau)) sb.append("Membre bureau ");
if (Boolean.TRUE.equals(responsable)) sb.append("Responsable ");
return sb.toString().trim();
private String sanitizeString(String str) {
if (str == null) return null;
str = str.trim();
return str.isEmpty() ? null : str;
}
/**
* Retourne une description textuelle des critères actifs
*
* @return Description des critères
*/
public String getDescription() {
StringBuilder sb = new StringBuilder();
if (query != null) sb.append("Recherche: '").append(query).append("' ");
if (nom != null) sb.append("Nom: '").append(nom).append("' ");
if (prenom != null) sb.append("Prénom: '").append(prenom).append("' ");
if (email != null) sb.append("Email: '").append(email).append("' ");
if (statut != null) sb.append("Statut: ").append(statut).append(" ");
if (organisationIds != null && !organisationIds.isEmpty()) {
sb.append("Organisations: ").append(organisationIds.size()).append(" ");
}
if (roles != null && !roles.isEmpty()) {
sb.append("Rôles: ").append(String.join(", ", roles)).append(" ");
}
if (dateAdhesionMin != null) sb.append("Adhésion >= ").append(dateAdhesionMin).append(" ");
if (dateAdhesionMax != null) sb.append("Adhésion <= ").append(dateAdhesionMax).append(" ");
if (ageMin != null) sb.append("Âge >= ").append(ageMin).append(" ");
if (ageMax != null) sb.append("Âge <= ").append(ageMax).append(" ");
if (region != null) sb.append("Région: '").append(region).append("' ");
if (ville != null) sb.append("Ville: '").append(ville).append("' ");
if (profession != null) sb.append("Profession: '").append(profession).append("' ");
if (nationalite != null) sb.append("Nationalité: '").append(nationalite).append("' ");
if (Boolean.TRUE.equals(membreBureau)) sb.append("Membre bureau ");
if (Boolean.TRUE.equals(responsable)) sb.append("Responsable ");
return sb.toString().trim();
}
}

View File

@@ -1,17 +1,16 @@
package dev.lions.unionflow.server.api.dto.membre;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.util.List;
/**
* DTO pour les résultats de recherche avancée des membres
* Contient les résultats paginés et les métadonnées de recherche
*
* DTO pour les résultats de recherche avancée des membres Contient les résultats paginés et les
* métadonnées de recherche
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-19
@@ -23,182 +22,178 @@ import java.util.List;
@Schema(description = "Résultats de recherche avancée des membres avec pagination")
public class MembreSearchResultDTO {
/** Liste des membres trouvés */
@Schema(description = "Liste des membres correspondant aux critères")
private List<MembreDTO> membres;
/** Liste des membres trouvés */
@Schema(description = "Liste des membres correspondant aux critères")
private List<MembreDTO> membres;
/** Nombre total de résultats (toutes pages confondues) */
@Schema(description = "Nombre total de résultats trouvés", example = "247")
private long totalElements;
/** Nombre total de résultats (toutes pages confondues) */
@Schema(description = "Nombre total de résultats trouvés", example = "247")
private long totalElements;
/** Nombre total de pages */
@Schema(description = "Nombre total de pages", example = "13")
private int totalPages;
/** Nombre total de pages */
@Schema(description = "Nombre total de pages", example = "13")
private int totalPages;
/** Numéro de la page actuelle (0-based) */
@Schema(description = "Numéro de la page actuelle", example = "0")
private int currentPage;
/** Numéro de la page actuelle (0-based) */
@Schema(description = "Numéro de la page actuelle", example = "0")
private int currentPage;
/** Taille de la page */
@Schema(description = "Nombre d'éléments par page", example = "20")
private int pageSize;
/** Taille de la page */
@Schema(description = "Nombre d'éléments par page", example = "20")
private int pageSize;
/** Nombre d'éléments sur la page actuelle */
@Schema(description = "Nombre d'éléments sur cette page", example = "20")
private int numberOfElements;
/** Nombre d'éléments sur la page actuelle */
@Schema(description = "Nombre d'éléments sur cette page", example = "20")
private int numberOfElements;
/** Indique s'il y a une page suivante */
@Schema(description = "Indique s'il y a une page suivante")
private boolean hasNext;
/** Indique s'il y a une page suivante */
@Schema(description = "Indique s'il y a une page suivante")
private boolean hasNext;
/** Indique s'il y a une page précédente */
@Schema(description = "Indique s'il y a une page précédente")
private boolean hasPrevious;
/** Indique s'il y a une page précédente */
@Schema(description = "Indique s'il y a une page précédente")
private boolean hasPrevious;
/** Indique si c'est la première page */
@Schema(description = "Indique si c'est la première page")
private boolean isFirst;
/** Indique si c'est la première page */
@Schema(description = "Indique si c'est la première page")
private boolean isFirst;
/** Indique si c'est la dernière page */
@Schema(description = "Indique si c'est la dernière page")
private boolean isLast;
/** Indique si c'est la dernière page */
@Schema(description = "Indique si c'est la dernière page")
private boolean isLast;
/** Critères de recherche utilisés */
@Schema(description = "Critères de recherche qui ont été appliqués")
private MembreSearchCriteria criteria;
/** Critères de recherche utilisés */
@Schema(description = "Critères de recherche qui ont été appliqués")
private MembreSearchCriteria criteria;
/** Temps d'exécution de la recherche en millisecondes */
@Schema(description = "Temps d'exécution de la recherche en ms", example = "45")
private long executionTimeMs;
/** Temps d'exécution de la recherche en millisecondes */
@Schema(description = "Temps d'exécution de la recherche en ms", example = "45")
private long executionTimeMs;
/** Statistiques de recherche */
@Schema(description = "Statistiques sur les résultats de recherche")
private SearchStatistics statistics;
/** Statistiques de recherche */
@Schema(description = "Statistiques sur les résultats de recherche")
private SearchStatistics statistics;
/**
* Statistiques sur les résultats de recherche
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Schema(description = "Statistiques sur les résultats de recherche")
public static class SearchStatistics {
/** Répartition par statut */
@Schema(description = "Nombre de membres actifs dans les résultats")
private long membresActifs;
@Schema(description = "Nombre de membres inactifs dans les résultats")
private long membresInactifs;
/** Répartition par âge */
@Schema(description = "Âge moyen des membres trouvés")
private double ageMoyen;
@Schema(description = "Âge minimum des membres trouvés")
private int ageMin;
@Schema(description = "Âge maximum des membres trouvés")
private int ageMax;
/** Répartition par organisation */
@Schema(description = "Nombre d'organisations représentées")
private long nombreOrganisations;
/** Répartition par région */
@Schema(description = "Nombre de régions représentées")
private long nombreRegions;
/** Ancienneté moyenne */
@Schema(description = "Ancienneté moyenne en années")
private double ancienneteMoyenne;
/** Statistiques sur les résultats de recherche */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Schema(description = "Statistiques sur les résultats de recherche")
public static class SearchStatistics {
/** Répartition par statut */
@Schema(description = "Nombre de membres actifs dans les résultats")
private long membresActifs;
@Schema(description = "Nombre de membres inactifs dans les résultats")
private long membresInactifs;
/** Répartition par âge */
@Schema(description = "Âge moyen des membres trouvés")
private double ageMoyen;
@Schema(description = "Âge minimum des membres trouvés")
private int ageMin;
@Schema(description = "Âge maximum des membres trouvés")
private int ageMax;
/** Répartition par organisation */
@Schema(description = "Nombre d'organisations représentées")
private long nombreOrganisations;
/** Répartition par région */
@Schema(description = "Nombre de régions représentées")
private long nombreRegions;
/** Ancienneté moyenne */
@Schema(description = "Ancienneté moyenne en années")
private double ancienneteMoyenne;
}
/** Calcule et met à jour les indicateurs de pagination */
public void calculatePaginationFlags() {
this.isFirst = currentPage == 0;
this.isLast = currentPage >= totalPages - 1;
this.hasPrevious = currentPage > 0;
this.hasNext = currentPage < totalPages - 1;
this.numberOfElements = membres != null ? membres.size() : 0;
}
/**
* Vérifie si les résultats sont vides
*
* @return true si aucun résultat
*/
public boolean isEmpty() {
return membres == null || membres.isEmpty();
}
/**
* Retourne le numéro de la page suivante (1-based pour affichage)
*
* @return Numéro de page suivante ou -1 si pas de page suivante
*/
public int getNextPageNumber() {
return hasNext ? currentPage + 2 : -1;
}
/**
* Retourne le numéro de la page précédente (1-based pour affichage)
*
* @return Numéro de page précédente ou -1 si pas de page précédente
*/
public int getPreviousPageNumber() {
return hasPrevious ? currentPage : -1;
}
/**
* Retourne une description textuelle des résultats
*
* @return Description des résultats
*/
public String getResultDescription() {
if (isEmpty()) {
return "Aucun membre trouvé";
}
/**
* Calcule et met à jour les indicateurs de pagination
*/
public void calculatePaginationFlags() {
this.isFirst = currentPage == 0;
this.isLast = currentPage >= totalPages - 1;
this.hasPrevious = currentPage > 0;
this.hasNext = currentPage < totalPages - 1;
this.numberOfElements = membres != null ? membres.size() : 0;
if (totalElements == 1) {
return "1 membre trouvé";
}
/**
* Vérifie si les résultats sont vides
*
* @return true si aucun résultat
*/
public boolean isEmpty() {
return membres == null || membres.isEmpty();
if (totalPages == 1) {
return String.format("%d membres trouvés", totalElements);
}
/**
* Retourne le numéro de la page suivante (1-based pour affichage)
*
* @return Numéro de page suivante ou -1 si pas de page suivante
*/
public int getNextPageNumber() {
return hasNext ? currentPage + 2 : -1;
}
int startElement = currentPage * pageSize + 1;
int endElement = Math.min(startElement + numberOfElements - 1, (int) totalElements);
/**
* Retourne le numéro de la page précédente (1-based pour affichage)
*
* @return Numéro de page précédente ou -1 si pas de page précédente
*/
public int getPreviousPageNumber() {
return hasPrevious ? currentPage : -1;
}
return String.format(
"Membres %d-%d sur %d (page %d/%d)",
startElement, endElement, totalElements, currentPage + 1, totalPages);
}
/**
* Retourne une description textuelle des résultats
*
* @return Description des résultats
*/
public String getResultDescription() {
if (isEmpty()) {
return "Aucun membre trouvé";
}
if (totalElements == 1) {
return "1 membre trouvé";
}
if (totalPages == 1) {
return String.format("%d membres trouvés", totalElements);
}
int startElement = currentPage * pageSize + 1;
int endElement = Math.min(startElement + numberOfElements - 1, (int) totalElements);
return String.format("Membres %d-%d sur %d (page %d/%d)",
startElement, endElement, totalElements,
currentPage + 1, totalPages);
}
/**
* Factory method pour créer un résultat vide
*
* @param criteria Critères de recherche
* @return Résultat vide
*/
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria) {
return MembreSearchResultDTO.builder()
.membres(List.of())
.totalElements(0)
.totalPages(0)
.currentPage(0)
.pageSize(20)
.numberOfElements(0)
.hasNext(false)
.hasPrevious(false)
.isFirst(true)
.isLast(true)
.criteria(criteria)
.executionTimeMs(0)
.build();
}
/**
* Factory method pour créer un résultat vide
*
* @param criteria Critères de recherche
* @return Résultat vide
*/
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria) {
MembreSearchResultDTO result = new MembreSearchResultDTO();
result.setMembres(List.of());
result.setTotalElements(0L);
result.setTotalPages(0);
result.setCurrentPage(0);
result.setPageSize(20);
result.setNumberOfElements(0);
result.setHasNext(false);
result.setHasPrevious(false);
result.setFirst(true);
result.setLast(true);
result.setCriteria(criteria);
result.setExecutionTimeMs(0L);
return result;
}
}

View File

@@ -1,426 +1,477 @@
package dev.lions.unionflow.server.api.dto.notification;
import jakarta.validation.constraints.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.validation.constraints.*;
import java.util.Map;
/**
* DTO pour les actions rapides des notifications UnionFlow
*
* Ce DTO représente une action que l'utilisateur peut exécuter directement
* depuis la notification sans ouvrir l'application.
*
*
* <p>Ce DTO représente une action que l'utilisateur peut exécuter directement depuis la
* notification sans ouvrir l'application.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ActionNotificationDTO {
/**
* Identifiant unique de l'action
*/
@NotBlank(message = "L'identifiant de l'action est obligatoire")
private String id;
/**
* Libellé affiché sur le bouton d'action
*/
@NotBlank(message = "Le libellé de l'action est obligatoire")
@Size(max = 30, message = "Le libellé ne peut pas dépasser 30 caractères")
private String libelle;
/**
* Description de l'action (tooltip)
*/
@Size(max = 100, message = "La description ne peut pas dépasser 100 caractères")
private String description;
/**
* Type d'action à exécuter
*/
@NotBlank(message = "Le type d'action est obligatoire")
private String typeAction;
/**
* Icône de l'action (Material Design)
*/
private String icone;
/**
* Couleur de l'action (hexadécimal)
*/
private String couleur;
/**
* URL à ouvrir (pour les actions de type "url")
*/
private String url;
/**
* Route de l'application à ouvrir (pour les actions de type "route")
*/
private String route;
/**
* Paramètres de l'action
*/
private Map<String, String> parametres;
/**
* Indique si l'action ferme la notification
*/
private Boolean fermeNotification;
/**
* Indique si l'action nécessite une confirmation
*/
private Boolean necessiteConfirmation;
/**
* Message de confirmation à afficher
*/
private String messageConfirmation;
/**
* Indique si l'action est destructive (suppression, etc.)
*/
private Boolean estDestructive;
/**
* Ordre d'affichage de l'action
*/
private Integer ordre;
/**
* Indique si l'action est activée
*/
private Boolean estActivee;
/**
* Condition d'affichage de l'action (expression)
*/
private String conditionAffichage;
/**
* Rôles autorisés à exécuter cette action
*/
private String[] rolesAutorises;
/**
* Permissions requises pour exécuter cette action
*/
private String[] permissionsRequises;
/**
* Délai d'expiration de l'action en minutes
*/
private Integer delaiExpirationMinutes;
/**
* Nombre maximum d'exécutions autorisées
*/
private Integer maxExecutions;
/**
* Nombre d'exécutions actuelles
*/
private Integer nombreExecutions;
/**
* Indique si l'action peut être exécutée plusieurs fois
*/
private Boolean peutEtreRepetee;
/**
* Style du bouton (primary, secondary, outline, text)
*/
private String styleBouton;
/**
* Taille du bouton (small, medium, large)
*/
private String tailleBouton;
/**
* Position du bouton (left, center, right)
*/
private String positionBouton;
/**
* Données personnalisées de l'action
*/
private Map<String, Object> donneesPersonnalisees;
// === CONSTRUCTEURS ===
/**
* Constructeur par défaut
*/
public ActionNotificationDTO() {
this.fermeNotification = true;
this.necessiteConfirmation = false;
this.estDestructive = false;
this.ordre = 0;
this.estActivee = true;
this.maxExecutions = 1;
this.nombreExecutions = 0;
this.peutEtreRepetee = false;
this.styleBouton = "primary";
this.tailleBouton = "medium";
this.positionBouton = "right";
/** Identifiant unique de l'action */
@NotBlank(message = "L'identifiant de l'action est obligatoire")
private String id;
/** Libellé affiché sur le bouton d'action */
@NotBlank(message = "Le libellé de l'action est obligatoire")
@Size(max = 30, message = "Le libellé ne peut pas dépasser 30 caractères")
private String libelle;
/** Description de l'action (tooltip) */
@Size(max = 100, message = "La description ne peut pas dépasser 100 caractères")
private String description;
/** Type d'action à exécuter */
@NotBlank(message = "Le type d'action est obligatoire")
private String typeAction;
/** Icône de l'action (Material Design) */
private String icone;
/** Couleur de l'action (hexadécimal) */
private String couleur;
/** URL à ouvrir (pour les actions de type "url") */
private String url;
/** Route de l'application à ouvrir (pour les actions de type "route") */
private String route;
/** Paramètres de l'action */
private Map<String, String> parametres;
/** Indique si l'action ferme la notification */
private Boolean fermeNotification;
/** Indique si l'action nécessite une confirmation */
private Boolean necessiteConfirmation;
/** Message de confirmation à afficher */
private String messageConfirmation;
/** Indique si l'action est destructive (suppression, etc.) */
private Boolean estDestructive;
/** Ordre d'affichage de l'action */
private Integer ordre;
/** Indique si l'action est activée */
private Boolean estActivee;
/** Condition d'affichage de l'action (expression) */
private String conditionAffichage;
/** Rôles autorisés à exécuter cette action */
private String[] rolesAutorises;
/** Permissions requises pour exécuter cette action */
private String[] permissionsRequises;
/** Délai d'expiration de l'action en minutes */
private Integer delaiExpirationMinutes;
/** Nombre maximum d'exécutions autorisées */
private Integer maxExecutions;
/** Nombre d'exécutions actuelles */
private Integer nombreExecutions;
/** Indique si l'action peut être exécutée plusieurs fois */
private Boolean peutEtreRepetee;
/** Style du bouton (primary, secondary, outline, text) */
private String styleBouton;
/** Taille du bouton (small, medium, large) */
private String tailleBouton;
/** Position du bouton (left, center, right) */
private String positionBouton;
/** Données personnalisées de l'action */
private Map<String, Object> donneesPersonnalisees;
// === CONSTRUCTEURS ===
/** Constructeur par défaut */
public ActionNotificationDTO() {
this.fermeNotification = true;
this.necessiteConfirmation = false;
this.estDestructive = false;
this.ordre = 0;
this.estActivee = true;
this.maxExecutions = 1;
this.nombreExecutions = 0;
this.peutEtreRepetee = false;
this.styleBouton = "primary";
this.tailleBouton = "medium";
this.positionBouton = "right";
}
/** Constructeur avec paramètres essentiels */
public ActionNotificationDTO(String id, String libelle, String typeAction) {
this();
this.id = id;
this.libelle = libelle;
this.typeAction = typeAction;
}
/** Constructeur pour action URL */
public ActionNotificationDTO(String id, String libelle, String url, String icone) {
this(id, libelle, "url");
this.url = url;
this.icone = icone;
}
/** Constructeur pour action de route */
public ActionNotificationDTO(
String id, String libelle, String route, String icone, Map<String, String> parametres) {
this(id, libelle, "route");
this.route = route;
this.icone = icone;
this.parametres = parametres;
}
// === GETTERS ET SETTERS ===
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLibelle() {
return libelle;
}
public void setLibelle(String libelle) {
this.libelle = libelle;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getTypeAction() {
return typeAction;
}
public void setTypeAction(String typeAction) {
this.typeAction = typeAction;
}
public String getIcone() {
return icone;
}
public void setIcone(String icone) {
this.icone = icone;
}
public String getCouleur() {
return couleur;
}
public void setCouleur(String couleur) {
this.couleur = couleur;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getRoute() {
return route;
}
public void setRoute(String route) {
this.route = route;
}
public Map<String, String> getParametres() {
return parametres;
}
public void setParametres(Map<String, String> parametres) {
this.parametres = parametres;
}
public Boolean getFermeNotification() {
return fermeNotification;
}
public void setFermeNotification(Boolean fermeNotification) {
this.fermeNotification = fermeNotification;
}
public Boolean getNecessiteConfirmation() {
return necessiteConfirmation;
}
public void setNecessiteConfirmation(Boolean necessiteConfirmation) {
this.necessiteConfirmation = necessiteConfirmation;
}
public String getMessageConfirmation() {
return messageConfirmation;
}
public void setMessageConfirmation(String messageConfirmation) {
this.messageConfirmation = messageConfirmation;
}
public Boolean getEstDestructive() {
return estDestructive;
}
public void setEstDestructive(Boolean estDestructive) {
this.estDestructive = estDestructive;
}
public Integer getOrdre() {
return ordre;
}
public void setOrdre(Integer ordre) {
this.ordre = ordre;
}
public Boolean getEstActivee() {
return estActivee;
}
public void setEstActivee(Boolean estActivee) {
this.estActivee = estActivee;
}
public String getConditionAffichage() {
return conditionAffichage;
}
public void setConditionAffichage(String conditionAffichage) {
this.conditionAffichage = conditionAffichage;
}
public String[] getRolesAutorises() {
return rolesAutorises;
}
public void setRolesAutorises(String[] rolesAutorises) {
this.rolesAutorises = rolesAutorises;
}
public String[] getPermissionsRequises() {
return permissionsRequises;
}
public void setPermissionsRequises(String[] permissionsRequises) {
this.permissionsRequises = permissionsRequises;
}
public Integer getDelaiExpirationMinutes() {
return delaiExpirationMinutes;
}
public void setDelaiExpirationMinutes(Integer delaiExpirationMinutes) {
this.delaiExpirationMinutes = delaiExpirationMinutes;
}
public Integer getMaxExecutions() {
return maxExecutions;
}
public void setMaxExecutions(Integer maxExecutions) {
this.maxExecutions = maxExecutions;
}
public Integer getNombreExecutions() {
return nombreExecutions;
}
public void setNombreExecutions(Integer nombreExecutions) {
this.nombreExecutions = nombreExecutions;
}
public Boolean getPeutEtreRepetee() {
return peutEtreRepetee;
}
public void setPeutEtreRepetee(Boolean peutEtreRepetee) {
this.peutEtreRepetee = peutEtreRepetee;
}
public String getStyleBouton() {
return styleBouton;
}
public void setStyleBouton(String styleBouton) {
this.styleBouton = styleBouton;
}
public String getTailleBouton() {
return tailleBouton;
}
public void setTailleBouton(String tailleBouton) {
this.tailleBouton = tailleBouton;
}
public String getPositionBouton() {
return positionBouton;
}
public void setPositionBouton(String positionBouton) {
this.positionBouton = positionBouton;
}
public Map<String, Object> getDonneesPersonnalisees() {
return donneesPersonnalisees;
}
public void setDonneesPersonnalisees(Map<String, Object> donneesPersonnalisees) {
this.donneesPersonnalisees = donneesPersonnalisees;
}
// === MÉTHODES UTILITAIRES ===
/** Vérifie si l'action peut être exécutée */
public boolean peutEtreExecutee() {
return estActivee && (nombreExecutions < maxExecutions || peutEtreRepetee);
}
/** Vérifie si l'action est expirée */
public boolean isExpiree() {
// Implémentation basée sur delaiExpirationMinutes et date de création de la notification
return false; // À implémenter selon la logique métier
}
/** Incrémente le nombre d'exécutions */
public void incrementerExecutions() {
if (nombreExecutions == null) {
nombreExecutions = 0;
}
/**
* Constructeur avec paramètres essentiels
*/
public ActionNotificationDTO(String id, String libelle, String typeAction) {
this();
this.id = id;
this.libelle = libelle;
this.typeAction = typeAction;
}
/**
* Constructeur pour action URL
*/
public ActionNotificationDTO(String id, String libelle, String url, String icone) {
this(id, libelle, "url");
this.url = url;
this.icone = icone;
}
/**
* Constructeur pour action de route
*/
public ActionNotificationDTO(String id, String libelle, String route, String icone, Map<String, String> parametres) {
this(id, libelle, "route");
this.route = route;
this.icone = icone;
this.parametres = parametres;
}
// === GETTERS ET SETTERS ===
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getLibelle() { return libelle; }
public void setLibelle(String libelle) { this.libelle = libelle; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getTypeAction() { return typeAction; }
public void setTypeAction(String typeAction) { this.typeAction = typeAction; }
public String getIcone() { return icone; }
public void setIcone(String icone) { this.icone = icone; }
public String getCouleur() { return couleur; }
public void setCouleur(String couleur) { this.couleur = couleur; }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public String getRoute() { return route; }
public void setRoute(String route) { this.route = route; }
public Map<String, String> getParametres() { return parametres; }
public void setParametres(Map<String, String> parametres) { this.parametres = parametres; }
public Boolean getFermeNotification() { return fermeNotification; }
public void setFermeNotification(Boolean fermeNotification) { this.fermeNotification = fermeNotification; }
public Boolean getNecessiteConfirmation() { return necessiteConfirmation; }
public void setNecessiteConfirmation(Boolean necessiteConfirmation) { this.necessiteConfirmation = necessiteConfirmation; }
public String getMessageConfirmation() { return messageConfirmation; }
public void setMessageConfirmation(String messageConfirmation) { this.messageConfirmation = messageConfirmation; }
public Boolean getEstDestructive() { return estDestructive; }
public void setEstDestructive(Boolean estDestructive) { this.estDestructive = estDestructive; }
public Integer getOrdre() { return ordre; }
public void setOrdre(Integer ordre) { this.ordre = ordre; }
public Boolean getEstActivee() { return estActivee; }
public void setEstActivee(Boolean estActivee) { this.estActivee = estActivee; }
public String getConditionAffichage() { return conditionAffichage; }
public void setConditionAffichage(String conditionAffichage) { this.conditionAffichage = conditionAffichage; }
public String[] getRolesAutorises() { return rolesAutorises; }
public void setRolesAutorises(String[] rolesAutorises) { this.rolesAutorises = rolesAutorises; }
public String[] getPermissionsRequises() { return permissionsRequises; }
public void setPermissionsRequises(String[] permissionsRequises) { this.permissionsRequises = permissionsRequises; }
public Integer getDelaiExpirationMinutes() { return delaiExpirationMinutes; }
public void setDelaiExpirationMinutes(Integer delaiExpirationMinutes) { this.delaiExpirationMinutes = delaiExpirationMinutes; }
public Integer getMaxExecutions() { return maxExecutions; }
public void setMaxExecutions(Integer maxExecutions) { this.maxExecutions = maxExecutions; }
public Integer getNombreExecutions() { return nombreExecutions; }
public void setNombreExecutions(Integer nombreExecutions) { this.nombreExecutions = nombreExecutions; }
public Boolean getPeutEtreRepetee() { return peutEtreRepetee; }
public void setPeutEtreRepetee(Boolean peutEtreRepetee) { this.peutEtreRepetee = peutEtreRepetee; }
public String getStyleBouton() { return styleBouton; }
public void setStyleBouton(String styleBouton) { this.styleBouton = styleBouton; }
public String getTailleBouton() { return tailleBouton; }
public void setTailleBouton(String tailleBouton) { this.tailleBouton = tailleBouton; }
public String getPositionBouton() { return positionBouton; }
public void setPositionBouton(String positionBouton) { this.positionBouton = positionBouton; }
public Map<String, Object> getDonneesPersonnalisees() { return donneesPersonnalisees; }
public void setDonneesPersonnalisees(Map<String, Object> donneesPersonnalisees) {
this.donneesPersonnalisees = donneesPersonnalisees;
}
// === MÉTHODES UTILITAIRES ===
/**
* Vérifie si l'action peut être exécutée
*/
public boolean peutEtreExecutee() {
return estActivee && (nombreExecutions < maxExecutions || peutEtreRepetee);
}
/**
* Vérifie si l'action est expirée
*/
public boolean isExpiree() {
// Implémentation basée sur delaiExpirationMinutes et date de création de la notification
return false; // À implémenter selon la logique métier
}
/**
* Incrémente le nombre d'exécutions
*/
public void incrementerExecutions() {
if (nombreExecutions == null) {
nombreExecutions = 0;
nombreExecutions++;
}
/** Vérifie si l'utilisateur a les permissions requises */
public boolean utilisateurAutorise(String[] rolesUtilisateur, String[] permissionsUtilisateur) {
// Vérification des rôles
if (rolesAutorises != null && rolesAutorises.length > 0) {
boolean roleAutorise = false;
for (String roleRequis : rolesAutorises) {
for (String roleUtilisateur : rolesUtilisateur) {
if (roleRequis.equals(roleUtilisateur)) {
roleAutorise = true;
break;
}
}
nombreExecutions++;
if (roleAutorise) break;
}
if (!roleAutorise) return false;
}
/**
* Vérifie si l'utilisateur a les permissions requises
*/
public boolean utilisateurAutorise(String[] rolesUtilisateur, String[] permissionsUtilisateur) {
// Vérification des rôles
if (rolesAutorises != null && rolesAutorises.length > 0) {
boolean roleAutorise = false;
for (String roleRequis : rolesAutorises) {
for (String roleUtilisateur : rolesUtilisateur) {
if (roleRequis.equals(roleUtilisateur)) {
roleAutorise = true;
break;
}
}
if (roleAutorise) break;
}
if (!roleAutorise) return false;
// Vérification des permissions
if (permissionsRequises != null && permissionsRequises.length > 0) {
boolean permissionAutorisee = false;
for (String permissionRequise : permissionsRequises) {
for (String permissionUtilisateur : permissionsUtilisateur) {
if (permissionRequise.equals(permissionUtilisateur)) {
permissionAutorisee = true;
break;
}
}
// Vérification des permissions
if (permissionsRequises != null && permissionsRequises.length > 0) {
boolean permissionAutorisee = false;
for (String permissionRequise : permissionsRequises) {
for (String permissionUtilisateur : permissionsUtilisateur) {
if (permissionRequise.equals(permissionUtilisateur)) {
permissionAutorisee = true;
break;
}
}
if (permissionAutorisee) break;
}
if (!permissionAutorisee) return false;
}
return true;
}
/**
* Retourne la couleur par défaut selon le type d'action
*/
public String getCouleurParDefaut() {
if (couleur != null) return couleur;
return switch (typeAction) {
case "confirm" -> "#4CAF50"; // Vert pour confirmation
case "cancel" -> "#F44336"; // Rouge pour annulation
case "info" -> "#2196F3"; // Bleu pour information
case "warning" -> "#FF9800"; // Orange pour avertissement
case "url", "route" -> "#2196F3"; // Bleu pour navigation
default -> "#9E9E9E"; // Gris par défaut
};
}
/**
* Retourne l'icône par défaut selon le type d'action
*/
public String getIconeParDefaut() {
if (icone != null) return icone;
return switch (typeAction) {
case "confirm" -> "check";
case "cancel" -> "close";
case "info" -> "info";
case "warning" -> "warning";
case "url" -> "open_in_new";
case "route" -> "arrow_forward";
case "call" -> "phone";
case "message" -> "message";
case "email" -> "email";
case "share" -> "share";
default -> "touch_app";
};
}
/**
* Crée une action de confirmation
*/
public static ActionNotificationDTO creerActionConfirmation(String id, String libelle) {
ActionNotificationDTO action = new ActionNotificationDTO(id, libelle, "confirm");
action.setCouleur("#4CAF50");
action.setIcone("check");
action.setStyleBouton("primary");
return action;
}
/**
* Crée une action d'annulation
*/
public static ActionNotificationDTO creerActionAnnulation(String id, String libelle) {
ActionNotificationDTO action = new ActionNotificationDTO(id, libelle, "cancel");
action.setCouleur("#F44336");
action.setIcone("close");
action.setStyleBouton("outline");
action.setEstDestructive(true);
return action;
}
/**
* Crée une action de navigation
*/
public static ActionNotificationDTO creerActionNavigation(String id, String libelle, String route) {
ActionNotificationDTO action = new ActionNotificationDTO(id, libelle, "route");
action.setRoute(route);
action.setCouleur("#2196F3");
action.setIcone("arrow_forward");
return action;
}
@Override
public String toString() {
return String.format("ActionNotificationDTO{id='%s', libelle='%s', type='%s'}",
id, libelle, typeAction);
if (permissionAutorisee) break;
}
if (!permissionAutorisee) return false;
}
return true;
}
/** Retourne la couleur par défaut selon le type d'action */
public String getCouleurParDefaut() {
if (couleur != null) return couleur;
return switch (typeAction) {
case "confirm" -> "#4CAF50"; // Vert pour confirmation
case "cancel" -> "#F44336"; // Rouge pour annulation
case "info" -> "#2196F3"; // Bleu pour information
case "warning" -> "#FF9800"; // Orange pour avertissement
case "url", "route" -> "#2196F3"; // Bleu pour navigation
default -> "#9E9E9E"; // Gris par défaut
};
}
/** Retourne l'icône par défaut selon le type d'action */
public String getIconeParDefaut() {
if (icone != null) return icone;
return switch (typeAction) {
case "confirm" -> "check";
case "cancel" -> "close";
case "info" -> "info";
case "warning" -> "warning";
case "url" -> "open_in_new";
case "route" -> "arrow_forward";
case "call" -> "phone";
case "message" -> "message";
case "email" -> "email";
case "share" -> "share";
default -> "touch_app";
};
}
/** Crée une action de confirmation */
public static ActionNotificationDTO creerActionConfirmation(String id, String libelle) {
ActionNotificationDTO action = new ActionNotificationDTO(id, libelle, "confirm");
action.setCouleur("#4CAF50");
action.setIcone("check");
action.setStyleBouton("primary");
return action;
}
/** Crée une action d'annulation */
public static ActionNotificationDTO creerActionAnnulation(String id, String libelle) {
ActionNotificationDTO action = new ActionNotificationDTO(id, libelle, "cancel");
action.setCouleur("#F44336");
action.setIcone("close");
action.setStyleBouton("outline");
action.setEstDestructive(true);
return action;
}
/** Crée une action de navigation */
public static ActionNotificationDTO creerActionNavigation(
String id, String libelle, String route) {
ActionNotificationDTO action = new ActionNotificationDTO(id, libelle, "route");
action.setRoute(route);
action.setCouleur("#2196F3");
action.setIcone("arrow_forward");
return action;
}
@Override
public String toString() {
return String.format(
"ActionNotificationDTO{id='%s', libelle='%s', type='%s'}", id, libelle, typeAction);
}
}

View File

@@ -5,88 +5,115 @@ import jakarta.validation.constraints.*;
/**
* DTO pour les préférences spécifiques à un canal de notification
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PreferenceCanalNotificationDTO {
/**
* Indique si ce canal est activé
*/
private Boolean active;
/**
* Niveau d'importance personnalisé (1-5)
*/
@Min(value = 1, message = "L'importance doit être comprise entre 1 et 5")
@Max(value = 5, message = "L'importance doit être comprise entre 1 et 5")
private Integer importance;
/**
* Son personnalisé pour ce canal
*/
private String sonPersonnalise;
/**
* Pattern de vibration personnalisé
*/
private long[] patternVibration;
/**
* Couleur LED personnalisée
*/
private String couleurLED;
/**
* Indique si le son est activé pour ce canal
*/
private Boolean sonActive;
/**
* Indique si la vibration est activée pour ce canal
*/
private Boolean vibrationActive;
/**
* Indique si la LED est activée pour ce canal
*/
private Boolean ledActive;
/**
* Indique si ce canal peut être désactivé par l'utilisateur
*/
private Boolean peutEtreDesactive;
// Constructeurs, getters et setters
public PreferenceCanalNotificationDTO() {}
public Boolean getActive() { return active; }
public void setActive(Boolean active) { this.active = active; }
public Integer getImportance() { return importance; }
public void setImportance(Integer importance) { this.importance = importance; }
public String getSonPersonnalise() { return sonPersonnalise; }
public void setSonPersonnalise(String sonPersonnalise) { this.sonPersonnalise = sonPersonnalise; }
public long[] getPatternVibration() { return patternVibration; }
public void setPatternVibration(long[] patternVibration) { this.patternVibration = patternVibration; }
public String getCouleurLED() { return couleurLED; }
public void setCouleurLED(String couleurLED) { this.couleurLED = couleurLED; }
public Boolean getSonActive() { return sonActive; }
public void setSonActive(Boolean sonActive) { this.sonActive = sonActive; }
public Boolean getVibrationActive() { return vibrationActive; }
public void setVibrationActive(Boolean vibrationActive) { this.vibrationActive = vibrationActive; }
public Boolean getLedActive() { return ledActive; }
public void setLedActive(Boolean ledActive) { this.ledActive = ledActive; }
public Boolean getPeutEtreDesactive() { return peutEtreDesactive; }
public void setPeutEtreDesactive(Boolean peutEtreDesactive) { this.peutEtreDesactive = peutEtreDesactive; }
/** Indique si ce canal est activé */
private Boolean active;
/** Niveau d'importance personnalisé (1-5) */
@Min(value = 1, message = "L'importance doit être comprise entre 1 et 5")
@Max(value = 5, message = "L'importance doit être comprise entre 1 et 5")
private Integer importance;
/** Son personnalisé pour ce canal */
private String sonPersonnalise;
/** Pattern de vibration personnalisé */
private long[] patternVibration;
/** Couleur LED personnalisée */
private String couleurLED;
/** Indique si le son est activé pour ce canal */
private Boolean sonActive;
/** Indique si la vibration est activée pour ce canal */
private Boolean vibrationActive;
/** Indique si la LED est activée pour ce canal */
private Boolean ledActive;
/** Indique si ce canal peut être désactivé par l'utilisateur */
private Boolean peutEtreDesactive;
// Constructeurs, getters et setters
public PreferenceCanalNotificationDTO() {}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
public Integer getImportance() {
return importance;
}
public void setImportance(Integer importance) {
this.importance = importance;
}
public String getSonPersonnalise() {
return sonPersonnalise;
}
public void setSonPersonnalise(String sonPersonnalise) {
this.sonPersonnalise = sonPersonnalise;
}
public long[] getPatternVibration() {
return patternVibration;
}
public void setPatternVibration(long[] patternVibration) {
this.patternVibration = patternVibration;
}
public String getCouleurLED() {
return couleurLED;
}
public void setCouleurLED(String couleurLED) {
this.couleurLED = couleurLED;
}
public Boolean getSonActive() {
return sonActive;
}
public void setSonActive(Boolean sonActive) {
this.sonActive = sonActive;
}
public Boolean getVibrationActive() {
return vibrationActive;
}
public void setVibrationActive(Boolean vibrationActive) {
this.vibrationActive = vibrationActive;
}
public Boolean getLedActive() {
return ledActive;
}
public void setLedActive(Boolean ledActive) {
this.ledActive = ledActive;
}
public Boolean getPeutEtreDesactive() {
return peutEtreDesactive;
}
public void setPeutEtreDesactive(Boolean peutEtreDesactive) {
this.peutEtreDesactive = peutEtreDesactive;
}
}

View File

@@ -5,98 +5,128 @@ import jakarta.validation.constraints.*;
/**
* DTO pour les préférences spécifiques à un type de notification
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PreferenceTypeNotificationDTO {
/**
* Indique si ce type de notification est activé
*/
private Boolean active;
/**
* Priorité personnalisée (1-5)
*/
@Min(value = 1, message = "La priorité doit être comprise entre 1 et 5")
@Max(value = 5, message = "La priorité doit être comprise entre 1 et 5")
private Integer priorite;
/**
* Son personnalisé pour ce type
*/
private String sonPersonnalise;
/**
* Pattern de vibration personnalisé
*/
private long[] patternVibration;
/**
* Couleur LED personnalisée
*/
private String couleurLED;
/**
* Durée d'affichage personnalisée (secondes)
*/
@Min(value = 1, message = "La durée d'affichage doit être au moins 1 seconde")
@Max(value = 300, message = "La durée d'affichage ne peut pas dépasser 5 minutes")
private Integer dureeAffichageSecondes;
/**
* Indique si les notifications de ce type doivent vibrer
*/
private Boolean doitVibrer;
/**
* Indique si les notifications de ce type doivent émettre un son
*/
private Boolean doitEmettreSon;
/**
* Indique si les notifications de ce type doivent allumer la LED
*/
private Boolean doitAllumerLED;
/**
* Indique si ce type ignore le mode silencieux
*/
private Boolean ignoreModesilencieux;
// Constructeurs, getters et setters
public PreferenceTypeNotificationDTO() {}
public Boolean getActive() { return active; }
public void setActive(Boolean active) { this.active = active; }
public Integer getPriorite() { return priorite; }
public void setPriorite(Integer priorite) { this.priorite = priorite; }
public String getSonPersonnalise() { return sonPersonnalise; }
public void setSonPersonnalise(String sonPersonnalise) { this.sonPersonnalise = sonPersonnalise; }
public long[] getPatternVibration() { return patternVibration; }
public void setPatternVibration(long[] patternVibration) { this.patternVibration = patternVibration; }
public String getCouleurLED() { return couleurLED; }
public void setCouleurLED(String couleurLED) { this.couleurLED = couleurLED; }
public Integer getDureeAffichageSecondes() { return dureeAffichageSecondes; }
public void setDureeAffichageSecondes(Integer dureeAffichageSecondes) { this.dureeAffichageSecondes = dureeAffichageSecondes; }
public Boolean getDoitVibrer() { return doitVibrer; }
public void setDoitVibrer(Boolean doitVibrer) { this.doitVibrer = doitVibrer; }
public Boolean getDoitEmettreSon() { return doitEmettreSon; }
public void setDoitEmettreSon(Boolean doitEmettreSon) { this.doitEmettreSon = doitEmettreSon; }
public Boolean getDoitAllumerLED() { return doitAllumerLED; }
public void setDoitAllumerLED(Boolean doitAllumerLED) { this.doitAllumerLED = doitAllumerLED; }
public Boolean getIgnoreModeSilencieux() { return ignoreModesilencieux; }
public void setIgnoreModeSilencieux(Boolean ignoreModesilencieux) { this.ignoreModesilencieux = ignoreModesilencieux; }
/** Indique si ce type de notification est activé */
private Boolean active;
/** Priorité personnalisée (1-5) */
@Min(value = 1, message = "La priorité doit être comprise entre 1 et 5")
@Max(value = 5, message = "La priorité doit être comprise entre 1 et 5")
private Integer priorite;
/** Son personnalisé pour ce type */
private String sonPersonnalise;
/** Pattern de vibration personnalisé */
private long[] patternVibration;
/** Couleur LED personnalisée */
private String couleurLED;
/** Durée d'affichage personnalisée (secondes) */
@Min(value = 1, message = "La durée d'affichage doit être au moins 1 seconde")
@Max(value = 300, message = "La durée d'affichage ne peut pas dépasser 5 minutes")
private Integer dureeAffichageSecondes;
/** Indique si les notifications de ce type doivent vibrer */
private Boolean doitVibrer;
/** Indique si les notifications de ce type doivent émettre un son */
private Boolean doitEmettreSon;
/** Indique si les notifications de ce type doivent allumer la LED */
private Boolean doitAllumerLED;
/** Indique si ce type ignore le mode silencieux */
private Boolean ignoreModesilencieux;
// Constructeurs, getters et setters
public PreferenceTypeNotificationDTO() {}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
public Integer getPriorite() {
return priorite;
}
public void setPriorite(Integer priorite) {
this.priorite = priorite;
}
public String getSonPersonnalise() {
return sonPersonnalise;
}
public void setSonPersonnalise(String sonPersonnalise) {
this.sonPersonnalise = sonPersonnalise;
}
public long[] getPatternVibration() {
return patternVibration;
}
public void setPatternVibration(long[] patternVibration) {
this.patternVibration = patternVibration;
}
public String getCouleurLED() {
return couleurLED;
}
public void setCouleurLED(String couleurLED) {
this.couleurLED = couleurLED;
}
public Integer getDureeAffichageSecondes() {
return dureeAffichageSecondes;
}
public void setDureeAffichageSecondes(Integer dureeAffichageSecondes) {
this.dureeAffichageSecondes = dureeAffichageSecondes;
}
public Boolean getDoitVibrer() {
return doitVibrer;
}
public void setDoitVibrer(Boolean doitVibrer) {
this.doitVibrer = doitVibrer;
}
public Boolean getDoitEmettreSon() {
return doitEmettreSon;
}
public void setDoitEmettreSon(Boolean doitEmettreSon) {
this.doitEmettreSon = doitEmettreSon;
}
public Boolean getDoitAllumerLED() {
return doitAllumerLED;
}
public void setDoitAllumerLED(Boolean doitAllumerLED) {
this.doitAllumerLED = doitAllumerLED;
}
public Boolean getIgnoreModeSilencieux() {
return ignoreModesilencieux;
}
public void setIgnoreModeSilencieux(Boolean ignoreModesilencieux) {
this.ignoreModesilencieux = ignoreModesilencieux;
}
}

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.organisation.StatutOrganisation;
import dev.lions.unionflow.server.api.enums.organisation.TypeOrganisation;
import dev.lions.unionflow.server.api.validation.ValidationConstants;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
@@ -34,12 +35,17 @@ public class OrganisationDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Nom de l'organisation */
@NotBlank(message = "Le nom de l'organisation est obligatoire")
@Size(min = 2, max = 200, message = "Le nom doit contenir entre 2 et 200 caractères")
@NotBlank(message = "Le nom de l'organisation" + ValidationConstants.OBLIGATOIRE_MESSAGE)
@Size(
min = ValidationConstants.NOM_ORGANISATION_MIN_LENGTH,
max = ValidationConstants.NOM_ORGANISATION_MAX_LENGTH,
message = ValidationConstants.NOM_ORGANISATION_SIZE_MESSAGE)
private String nom;
/** Nom court ou sigle */
@Size(max = 50, message = "Le nom court ne peut pas dépasser 50 caractères")
@Size(
max = ValidationConstants.NOM_COURT_MAX_LENGTH,
message = ValidationConstants.NOM_COURT_SIZE_MESSAGE)
private String nomCourt;
/** Type d'organisation */
@@ -51,7 +57,9 @@ public class OrganisationDTO extends BaseDTO {
private StatutOrganisation statut;
/** Description de l'organisation */
@Size(max = 2000, message = "La description ne peut pas dépasser 2000 caractères")
@Size(
max = ValidationConstants.DESCRIPTION_MAX_LENGTH,
message = ValidationConstants.DESCRIPTION_SIZE_MESSAGE)
private String description;
/** Date de fondation */
@@ -225,7 +233,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si l'organisation est active
*/
public boolean isActive() {
public boolean estActive() {
return StatutOrganisation.ACTIVE.equals(statut);
}
@@ -234,7 +242,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si l'organisation est inactive
*/
public boolean isInactive() {
public boolean estInactive() {
return StatutOrganisation.INACTIVE.equals(statut);
}
@@ -243,7 +251,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si l'organisation est suspendue
*/
public boolean isSuspendue() {
public boolean estSuspendue() {
return StatutOrganisation.SUSPENDUE.equals(statut);
}
@@ -252,7 +260,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si l'organisation est en création
*/
public boolean isEnCreation() {
public boolean estEnCreation() {
return StatutOrganisation.EN_CREATION.equals(statut);
}
@@ -261,7 +269,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si l'organisation est dissoute
*/
public boolean isDissoute() {
public boolean estDissoute() {
return StatutOrganisation.DISSOUTE.equals(statut);
}
@@ -291,7 +299,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si latitude et longitude sont définies
*/
public boolean hasGeolocalisation() {
public boolean possedGeolocalisation() {
return latitude != null && longitude != null;
}
@@ -300,7 +308,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si l'organisation n'a pas de parent
*/
public boolean isOrganisationRacine() {
public boolean estOrganisationRacine() {
return organisationParenteId == null;
}
@@ -309,7 +317,7 @@ public class OrganisationDTO extends BaseDTO {
*
* @return true si le niveau hiérarchique est supérieur à 0
*/
public boolean hasSousOrganisations() {
public boolean possedeSousOrganisations() {
return niveauHierarchique != null && niveauHierarchique > 0;
}
@@ -408,6 +416,17 @@ public class OrganisationDTO extends BaseDTO {
marquerCommeModifie(utilisateur);
}
/**
* Désactive l'organisation
*
* @param utilisateur L'utilisateur qui désactive l'organisation
*/
public void desactiver(String utilisateur) {
this.statut = StatutOrganisation.INACTIVE;
this.accepteNouveauxMembres = false;
marquerCommeModifie(utilisateur);
}
/**
* Met à jour le nombre de membres
*
@@ -469,4 +488,31 @@ public class OrganisationDTO extends BaseDTO {
+ "} "
+ super.toString();
}
// === MÉTHODES UTILITAIRES ===
/** Retourne le libellé du statut */
public String getStatutLibelle() {
return statut != null ? statut.getLibelle() : "Non défini";
}
/** Retourne le libellé du type d'organisation */
public String getTypeLibelle() {
return typeOrganisation != null ? typeOrganisation.getLibelle() : "Non défini";
}
/** Ajoute un administrateur */
public void ajouterAdministrateur(String utilisateur) {
if (nombreAdministrateurs == null) nombreAdministrateurs = 0;
nombreAdministrateurs++;
marquerCommeModifie(utilisateur);
}
/** Retire un administrateur */
public void retirerAdministrateur(String utilisateur) {
if (nombreAdministrateurs != null && nombreAdministrateurs > 0) {
nombreAdministrateurs--;
marquerCommeModifie(utilisateur);
}
}
}

View File

@@ -1,16 +1,15 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.time.LocalDate;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les bénéficiaires d'une aide
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -20,80 +19,53 @@ import java.time.LocalDate;
@AllArgsConstructor
@Builder
public class BeneficiaireAideDTO {
/**
* Identifiant unique du bénéficiaire
*/
private String id;
/**
* Nom complet du bénéficiaire
*/
@NotBlank(message = "Le nom du bénéficiaire est obligatoire")
@Size(max = 100, message = "Le nom ne peut pas dépasser 100 caractères")
private String nomComplet;
/**
* Relation avec le demandeur
*/
@NotBlank(message = "La relation avec le demandeur est obligatoire")
private String relationDemandeur;
/**
* Date de naissance
*/
private LocalDate dateNaissance;
/**
* Âge calculé
*/
private Integer age;
/**
* Genre
*/
private String genre;
/**
* Numéro de téléphone
*/
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone n'est pas valide")
private String telephone;
/**
* Adresse email
*/
@Email(message = "L'adresse email n'est pas valide")
private String email;
/**
* Adresse physique
*/
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
private String adresse;
/**
* Situation particulière (handicap, maladie, etc.)
*/
@Size(max = 500, message = "La situation particulière ne peut pas dépasser 500 caractères")
private String situationParticuliere;
/**
* Indique si le bénéficiaire est le demandeur principal
*/
@Builder.Default
private Boolean estDemandeurPrincipal = false;
/**
* Pourcentage de l'aide destiné à ce bénéficiaire
*/
@DecimalMin(value = "0.0", message = "Le pourcentage doit être positif")
@DecimalMax(value = "100.0", message = "Le pourcentage ne peut pas dépasser 100%")
private Double pourcentageAide;
/**
* Montant spécifique pour ce bénéficiaire
*/
@DecimalMin(value = "0.0", message = "Le montant doit être positif")
private Double montantSpecifique;
/** Identifiant unique du bénéficiaire */
private String id;
/** Nom complet du bénéficiaire */
@NotBlank(message = "Le nom du bénéficiaire est obligatoire")
@Size(max = 100, message = "Le nom ne peut pas dépasser 100 caractères")
private String nomComplet;
/** Relation avec le demandeur */
@NotBlank(message = "La relation avec le demandeur est obligatoire")
private String relationDemandeur;
/** Date de naissance */
private LocalDate dateNaissance;
/** Âge calculé */
private Integer age;
/** Genre */
private String genre;
/** Numéro de téléphone */
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone n'est pas valide")
private String telephone;
/** Adresse email */
@Email(message = "L'adresse email n'est pas valide")
private String email;
/** Adresse physique */
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
private String adresse;
/** Situation particulière (handicap, maladie, etc.) */
@Size(max = 500, message = "La situation particulière ne peut pas dépasser 500 caractères")
private String situationParticuliere;
/** Indique si le bénéficiaire est le demandeur principal */
@Builder.Default private Boolean estDemandeurPrincipal = false;
/** Pourcentage de l'aide destiné à ce bénéficiaire */
@DecimalMin(value = "0.0", message = "Le pourcentage doit être positif")
@DecimalMax(value = "100.0", message = "Le pourcentage ne peut pas dépasser 100%")
private Double pourcentageAide;
/** Montant spécifique pour ce bénéficiaire */
@DecimalMin(value = "0.0", message = "Le montant doit être positif")
private Double montantSpecifique;
}

View File

@@ -1,17 +1,16 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.time.LocalDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les commentaires sur une demande d'aide
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -21,110 +20,67 @@ import java.util.List;
@AllArgsConstructor
@Builder
public class CommentaireAideDTO {
/**
* Identifiant unique du commentaire
*/
private String id;
/**
* Contenu du commentaire
*/
@NotBlank(message = "Le contenu du commentaire est obligatoire")
@Size(min = 5, max = 2000, message = "Le commentaire doit contenir entre 5 et 2000 caractères")
private String contenu;
/**
* Type de commentaire
*/
@NotBlank(message = "Le type de commentaire est obligatoire")
private String typeCommentaire;
/**
* Date de création du commentaire
*/
@NotNull(message = "La date de création est obligatoire")
@Builder.Default
private LocalDateTime dateCreation = LocalDateTime.now();
/**
* Date de dernière modification
*/
private LocalDateTime dateModification;
/**
* Identifiant de l'auteur du commentaire
*/
@NotBlank(message = "L'identifiant de l'auteur est obligatoire")
private String auteurId;
/**
* Nom de l'auteur du commentaire
*/
private String auteurNom;
/**
* Rôle de l'auteur
*/
private String auteurRole;
/**
* Indique si le commentaire est privé (visible seulement aux évaluateurs)
*/
@Builder.Default
private Boolean estPrive = false;
/**
* Indique si le commentaire est important
*/
@Builder.Default
private Boolean estImportant = false;
/**
* Identifiant du commentaire parent (pour les réponses)
*/
private String commentaireParentId;
/**
* Réponses à ce commentaire
*/
private List<CommentaireAideDTO> reponses;
/**
* Pièces jointes au commentaire
*/
private List<PieceJustificativeDTO> piecesJointes;
/**
* Mentions d'utilisateurs dans le commentaire
*/
private List<String> mentionsUtilisateurs;
/**
* Indique si le commentaire a été modifié
*/
@Builder.Default
private Boolean estModifie = false;
/**
* Nombre de likes/réactions
*/
@Builder.Default
private Integer nombreReactions = 0;
/**
* Indique si le commentaire est résolu (pour les questions)
*/
@Builder.Default
private Boolean estResolu = false;
/**
* Date de résolution
*/
private LocalDateTime dateResolution;
/**
* Identifiant de la personne qui a marqué comme résolu
*/
private String resoluteurId;
/** Identifiant unique du commentaire */
private String id;
/** Contenu du commentaire */
@NotBlank(message = "Le contenu du commentaire est obligatoire")
@Size(min = 5, max = 2000, message = "Le commentaire doit contenir entre 5 et 2000 caractères")
private String contenu;
/** Type de commentaire */
@NotBlank(message = "Le type de commentaire est obligatoire")
private String typeCommentaire;
/** Date de création du commentaire */
@NotNull(message = "La date de création est obligatoire")
@Builder.Default
private LocalDateTime dateCreation = LocalDateTime.now();
/** Date de dernière modification */
private LocalDateTime dateModification;
/** Identifiant de l'auteur du commentaire */
@NotBlank(message = "L'identifiant de l'auteur est obligatoire")
private String auteurId;
/** Nom de l'auteur du commentaire */
private String auteurNom;
/** Rôle de l'auteur */
private String auteurRole;
/** Indique si le commentaire est privé (visible seulement aux évaluateurs) */
@Builder.Default private Boolean estPrive = false;
/** Indique si le commentaire est important */
@Builder.Default private Boolean estImportant = false;
/** Identifiant du commentaire parent (pour les réponses) */
private String commentaireParentId;
/** Réponses à ce commentaire */
private List<CommentaireAideDTO> reponses;
/** Pièces jointes au commentaire */
private List<PieceJustificativeDTO> piecesJointes;
/** Mentions d'utilisateurs dans le commentaire */
private List<String> mentionsUtilisateurs;
/** Indique si le commentaire a été modifié */
@Builder.Default private Boolean estModifie = false;
/** Nombre de likes/réactions */
@Builder.Default private Integer nombreReactions = 0;
/** Indique si le commentaire est résolu (pour les questions) */
@Builder.Default private Boolean estResolu = false;
/** Date de résolution */
private LocalDateTime dateResolution;
/** Identifiant de la personne qui a marqué comme résolu */
private String resoluteurId;
}

View File

@@ -1,14 +1,14 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les informations de contact du proposant d'aide
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -18,92 +18,60 @@ import lombok.Builder;
@AllArgsConstructor
@Builder
public class ContactProposantDTO {
/**
* Numéro de téléphone principal
*/
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone n'est pas valide")
private String telephonePrincipal;
/**
* Numéro de téléphone secondaire
*/
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone secondaire n'est pas valide")
private String telephoneSecondaire;
/**
* Adresse email
*/
@Email(message = "L'adresse email n'est pas valide")
private String email;
/**
* Adresse email secondaire
*/
@Email(message = "L'adresse email secondaire n'est pas valide")
private String emailSecondaire;
/**
* Identifiant WhatsApp
*/
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro WhatsApp n'est pas valide")
private String whatsapp;
/**
* Identifiant Telegram
*/
@Size(max = 50, message = "L'identifiant Telegram ne peut pas dépasser 50 caractères")
private String telegram;
/**
* Autres moyens de contact (réseaux sociaux, etc.)
*/
private java.util.Map<String, String> autresContacts;
/**
* Adresse physique pour rencontres
*/
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
private String adressePhysique;
/**
* Indique si les rencontres physiques sont possibles
*/
@Builder.Default
private Boolean rencontresPhysiquesPossibles = false;
/**
* Indique si les appels téléphoniques sont acceptés
*/
@Builder.Default
private Boolean appelsAcceptes = true;
/**
* Indique si les SMS sont acceptés
*/
@Builder.Default
private Boolean smsAcceptes = true;
/**
* Indique si les emails sont acceptés
*/
@Builder.Default
private Boolean emailsAcceptes = true;
/**
* Horaires de disponibilité pour contact
*/
@Size(max = 200, message = "Les horaires ne peuvent pas dépasser 200 caractères")
private String horairesDisponibilite;
/**
* Langue(s) de communication préférée(s)
*/
private java.util.List<String> languesPreferees;
/**
* Instructions spéciales pour le contact
*/
@Size(max = 300, message = "Les instructions ne peuvent pas dépasser 300 caractères")
private String instructionsSpeciales;
/** Numéro de téléphone principal */
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone n'est pas valide")
private String telephonePrincipal;
/** Numéro de téléphone secondaire */
@Pattern(
regexp = "^\\+?[0-9]{8,15}$",
message = "Le numéro de téléphone secondaire n'est pas valide")
private String telephoneSecondaire;
/** Adresse email */
@Email(message = "L'adresse email n'est pas valide")
private String email;
/** Adresse email secondaire */
@Email(message = "L'adresse email secondaire n'est pas valide")
private String emailSecondaire;
/** Identifiant WhatsApp */
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro WhatsApp n'est pas valide")
private String whatsapp;
/** Identifiant Telegram */
@Size(max = 50, message = "L'identifiant Telegram ne peut pas dépasser 50 caractères")
private String telegram;
/** Autres moyens de contact (réseaux sociaux, etc.) */
private java.util.Map<String, String> autresContacts;
/** Adresse physique pour rencontres */
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
private String adressePhysique;
/** Indique si les rencontres physiques sont possibles */
@Builder.Default private Boolean rencontresPhysiquesPossibles = false;
/** Indique si les appels téléphoniques sont acceptés */
@Builder.Default private Boolean appelsAcceptes = true;
/** Indique si les SMS sont acceptés */
@Builder.Default private Boolean smsAcceptes = true;
/** Indique si les emails sont acceptés */
@Builder.Default private Boolean emailsAcceptes = true;
/** Horaires de disponibilité pour contact */
@Size(max = 200, message = "Les horaires ne peuvent pas dépasser 200 caractères")
private String horairesDisponibilite;
/** Langue(s) de communication préférée(s) */
private java.util.List<String> languesPreferees;
/** Instructions spéciales pour le contact */
@Size(max = 300, message = "Les instructions ne peuvent pas dépasser 300 caractères")
private String instructionsSpeciales;
}

View File

@@ -1,14 +1,14 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les informations de contact d'urgence
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -18,67 +18,47 @@ import lombok.Builder;
@AllArgsConstructor
@Builder
public class ContactUrgenceDTO {
/**
* Nom complet du contact d'urgence
*/
@NotBlank(message = "Le nom du contact d'urgence est obligatoire")
@Size(max = 100, message = "Le nom ne peut pas dépasser 100 caractères")
private String nomComplet;
/**
* Relation avec le demandeur
*/
@NotBlank(message = "La relation avec le demandeur est obligatoire")
@Size(max = 50, message = "La relation ne peut pas dépasser 50 caractères")
private String relation;
/**
* Numéro de téléphone principal
*/
@NotBlank(message = "Le numéro de téléphone est obligatoire")
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone n'est pas valide")
private String telephonePrincipal;
/**
* Numéro de téléphone secondaire
*/
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone secondaire n'est pas valide")
private String telephoneSecondaire;
/**
* Adresse email
*/
@Email(message = "L'adresse email n'est pas valide")
private String email;
/**
* Adresse physique
*/
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
private String adresse;
/**
* Disponibilité (horaires)
*/
@Size(max = 100, message = "La disponibilité ne peut pas dépasser 100 caractères")
private String disponibilite;
/**
* Indique si ce contact peut prendre des décisions pour le demandeur
*/
@Builder.Default
private Boolean peutPrendreDecisions = false;
/**
* Indique si ce contact doit être notifié automatiquement
*/
@Builder.Default
private Boolean notificationAutomatique = true;
/**
* Commentaires additionnels
*/
@Size(max = 300, message = "Les commentaires ne peuvent pas dépasser 300 caractères")
private String commentaires;
/** Nom complet du contact d'urgence */
@NotBlank(message = "Le nom du contact d'urgence est obligatoire")
@Size(max = 100, message = "Le nom ne peut pas dépasser 100 caractères")
private String nomComplet;
/** Relation avec le demandeur */
@NotBlank(message = "La relation avec le demandeur est obligatoire")
@Size(max = 50, message = "La relation ne peut pas dépasser 50 caractères")
private String relation;
/** Numéro de téléphone principal */
@NotBlank(message = "Le numéro de téléphone est obligatoire")
@Pattern(regexp = "^\\+?[0-9]{8,15}$", message = "Le numéro de téléphone n'est pas valide")
private String telephonePrincipal;
/** Numéro de téléphone secondaire */
@Pattern(
regexp = "^\\+?[0-9]{8,15}$",
message = "Le numéro de téléphone secondaire n'est pas valide")
private String telephoneSecondaire;
/** Adresse email */
@Email(message = "L'adresse email n'est pas valide")
private String email;
/** Adresse physique */
@Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
private String adresse;
/** Disponibilité (horaires) */
@Size(max = 100, message = "La disponibilité ne peut pas dépasser 100 caractères")
private String disponibilite;
/** Indique si ce contact peut prendre des décisions pour le demandeur */
@Builder.Default private Boolean peutPrendreDecisions = false;
/** Indique si ce contact doit être notifié automatiquement */
@Builder.Default private Boolean notificationAutomatique = true;
/** Commentaires additionnels */
@Size(max = 300, message = "Les commentaires ne peuvent pas dépasser 300 caractères")
private String commentaires;
}

View File

@@ -1,18 +1,17 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.time.LocalDate;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les créneaux de disponibilité du proposant
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -22,158 +21,117 @@ import java.time.LocalDate;
@AllArgsConstructor
@Builder
public class CreneauDisponibiliteDTO {
/**
* Identifiant unique du créneau
*/
private String id;
/**
* Jour de la semaine (pour créneaux récurrents)
*/
private DayOfWeek jourSemaine;
/**
* Date spécifique (pour créneaux ponctuels)
*/
private LocalDate dateSpecifique;
/**
* Heure de début
*/
@NotNull(message = "L'heure de début est obligatoire")
private LocalTime heureDebut;
/**
* Heure de fin
*/
@NotNull(message = "L'heure de fin est obligatoire")
private LocalTime heureFin;
/**
* Type de créneau
*/
@NotNull(message = "Le type de créneau est obligatoire")
@Builder.Default
private TypeCreneau type = TypeCreneau.RECURRENT;
/**
* Indique si le créneau est actif
*/
@Builder.Default
private Boolean estActif = true;
/**
* Fuseau horaire
*/
@Builder.Default
private String fuseauHoraire = "Africa/Abidjan";
/**
* Commentaires sur le créneau
*/
@Size(max = 200, message = "Les commentaires ne peuvent pas dépasser 200 caractères")
private String commentaires;
/**
* Priorité du créneau (1 = haute, 5 = basse)
*/
@Min(value = 1, message = "La priorité doit être au moins 1")
@Max(value = 5, message = "La priorité ne peut pas dépasser 5")
@Builder.Default
private Integer priorite = 3;
/**
* Durée maximale d'intervention en minutes
*/
@Min(value = 15, message = "La durée doit être au moins 15 minutes")
@Max(value = 480, message = "La durée ne peut pas dépasser 8 heures")
private Integer dureeMaxMinutes;
/**
* Indique si des pauses sont nécessaires
*/
@Builder.Default
private Boolean pausesNecessaires = false;
/**
* Durée des pauses en minutes
*/
@Min(value = 5, message = "La durée de pause doit être au moins 5 minutes")
private Integer dureePauseMinutes;
/**
* Énumération des types de créneaux
*/
public enum TypeCreneau {
RECURRENT("Récurrent"),
PONCTUEL("Ponctuel"),
URGENCE("Urgence"),
FLEXIBLE("Flexible");
private final String libelle;
TypeCreneau(String libelle) {
this.libelle = libelle;
}
public String getLibelle() {
return libelle;
}
/** Identifiant unique du créneau */
private String id;
/** Jour de la semaine (pour créneaux récurrents) */
private DayOfWeek jourSemaine;
/** Date spécifique (pour créneaux ponctuels) */
private LocalDate dateSpecifique;
/** Heure de début */
@NotNull(message = "L'heure de début est obligatoire")
private LocalTime heureDebut;
/** Heure de fin */
@NotNull(message = "L'heure de fin est obligatoire")
private LocalTime heureFin;
/** Type de créneau */
@NotNull(message = "Le type de créneau est obligatoire")
@Builder.Default
private TypeCreneau type = TypeCreneau.RECURRENT;
/** Indique si le créneau est actif */
@Builder.Default private Boolean estActif = true;
/** Fuseau horaire */
@Builder.Default private String fuseauHoraire = "Africa/Abidjan";
/** Commentaires sur le créneau */
@Size(max = 200, message = "Les commentaires ne peuvent pas dépasser 200 caractères")
private String commentaires;
/** Priorité du créneau (1 = haute, 5 = basse) */
@Min(value = 1, message = "La priorité doit être au moins 1")
@Max(value = 5, message = "La priorité ne peut pas dépasser 5")
@Builder.Default
private Integer priorite = 3;
/** Durée maximale d'intervention en minutes */
@Min(value = 15, message = "La durée doit être au moins 15 minutes")
@Max(value = 480, message = "La durée ne peut pas dépasser 8 heures")
private Integer dureeMaxMinutes;
/** Indique si des pauses sont nécessaires */
@Builder.Default private Boolean pausesNecessaires = false;
/** Durée des pauses en minutes */
@Min(value = 5, message = "La durée de pause doit être au moins 5 minutes")
private Integer dureePauseMinutes;
/** Énumération des types de créneaux */
public enum TypeCreneau {
RECURRENT("Récurrent"),
PONCTUEL("Ponctuel"),
URGENCE("Urgence"),
FLEXIBLE("Flexible");
private final String libelle;
TypeCreneau(String libelle) {
this.libelle = libelle;
}
// === MÉTHODES UTILITAIRES ===
/**
* Vérifie si le créneau est valide (heure fin > heure début)
*/
public boolean isValide() {
return heureDebut != null && heureFin != null && heureFin.isAfter(heureDebut);
}
/**
* Calcule la durée du créneau en minutes
*/
public long getDureeMinutes() {
if (!isValide()) return 0;
return java.time.Duration.between(heureDebut, heureFin).toMinutes();
}
/**
* Vérifie si le créneau est disponible à une date donnée
*/
public boolean isDisponibleLe(LocalDate date) {
if (!estActif) return false;
return switch (type) {
case PONCTUEL -> dateSpecifique != null && dateSpecifique.equals(date);
case RECURRENT -> jourSemaine != null && date.getDayOfWeek() == jourSemaine;
case URGENCE, FLEXIBLE -> true;
};
}
/**
* Vérifie si une heure est dans le créneau
*/
public boolean contientHeure(LocalTime heure) {
if (!isValide()) return false;
return !heure.isBefore(heureDebut) && !heure.isAfter(heureFin);
}
/**
* Retourne le libellé du créneau
*/
public String getLibelle() {
StringBuilder sb = new StringBuilder();
if (type == TypeCreneau.RECURRENT && jourSemaine != null) {
sb.append(jourSemaine.name()).append(" ");
} else if (type == TypeCreneau.PONCTUEL && dateSpecifique != null) {
sb.append(dateSpecifique.toString()).append(" ");
}
sb.append(heureDebut.toString()).append(" - ").append(heureFin.toString());
return sb.toString();
return libelle;
}
}
// === MÉTHODES UTILITAIRES ===
/** Vérifie si le créneau est valide (heure fin > heure début) */
public boolean isValide() {
return heureDebut != null && heureFin != null && heureFin.isAfter(heureDebut);
}
/** Calcule la durée du créneau en minutes */
public long getDureeMinutes() {
if (!isValide()) return 0;
return java.time.Duration.between(heureDebut, heureFin).toMinutes();
}
/** Vérifie si le créneau est disponible à une date donnée */
public boolean isDisponibleLe(LocalDate date) {
if (!estActif) return false;
return switch (type) {
case PONCTUEL -> dateSpecifique != null && dateSpecifique.equals(date);
case RECURRENT -> jourSemaine != null && date.getDayOfWeek() == jourSemaine;
case URGENCE, FLEXIBLE -> true;
};
}
/** Vérifie si une heure est dans le créneau */
public boolean contientHeure(LocalTime heure) {
if (!isValide()) return false;
return !heure.isBefore(heureDebut) && !heure.isAfter(heureFin);
}
/** Retourne le libellé du créneau */
public String getLibelle() {
StringBuilder sb = new StringBuilder();
if (type == TypeCreneau.RECURRENT && jourSemaine != null) {
sb.append(jourSemaine.name()).append(" ");
} else if (type == TypeCreneau.PONCTUEL && dateSpecifique != null) {
sb.append(dateSpecifique.toString()).append(" ");
}
sb.append(heureDebut.toString()).append(" - ").append(heureFin.toString());
return sb.toString();
}
}

View File

@@ -1,14 +1,14 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les critères de sélection des bénéficiaires
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -18,54 +18,37 @@ import lombok.Builder;
@AllArgsConstructor
@Builder
public class CritereSelectionDTO {
/**
* Nom du critère
*/
@NotBlank(message = "Le nom du critère est obligatoire")
@Size(max = 100, message = "Le nom ne peut pas dépasser 100 caractères")
private String nom;
/**
* Type de critère (age, situation, localisation, etc.)
*/
@NotBlank(message = "Le type de critère est obligatoire")
private String type;
/**
* Opérateur de comparaison (equals, greater_than, less_than, contains, etc.)
*/
@NotBlank(message = "L'opérateur est obligatoire")
private String operateur;
/**
* Valeur de référence pour la comparaison
*/
@NotBlank(message = "La valeur est obligatoire")
private String valeur;
/**
* Valeur maximale (pour les plages)
*/
private String valeurMax;
/**
* Indique si le critère est obligatoire
*/
@Builder.Default
private Boolean estObligatoire = false;
/**
* Poids du critère dans la sélection (1-10)
*/
@Min(value = 1, message = "Le poids doit être au moins 1")
@Max(value = 10, message = "Le poids ne peut pas dépasser 10")
@Builder.Default
private Integer poids = 5;
/**
* Description du critère
*/
@Size(max = 200, message = "La description ne peut pas dépasser 200 caractères")
private String description;
/** Nom du critère */
@NotBlank(message = "Le nom du critère est obligatoire")
@Size(max = 100, message = "Le nom ne peut pas dépasser 100 caractères")
private String nom;
/** Type de critère (age, situation, localisation, etc.) */
@NotBlank(message = "Le type de critère est obligatoire")
private String type;
/** Opérateur de comparaison (equals, greater_than, less_than, contains, etc.) */
@NotBlank(message = "L'opérateur est obligatoire")
private String operateur;
/** Valeur de référence pour la comparaison */
@NotBlank(message = "La valeur est obligatoire")
private String valeur;
/** Valeur maximale (pour les plages) */
private String valeurMax;
/** Indique si le critère est obligatoire */
@Builder.Default private Boolean estObligatoire = false;
/** Poids du critère dans la sélection (1-10) */
@Min(value = 1, message = "Le poids doit être au moins 1")
@Max(value = 10, message = "Le poids ne peut pas dépasser 10")
@Builder.Default
private Integer poids = 5;
/** Description du critère */
@Size(max = 200, message = "La description ne peut pas dépasser 200 caractères")
private String description;
}

View File

@@ -1,374 +1,468 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import dev.lions.unionflow.server.api.enums.solidarite.PrioriteAide;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.api.validation.ValidationConstants;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* DTO pour les demandes d'aide dans le système de solidarité
*
* Ce DTO représente une demande d'aide complète avec toutes les informations
* nécessaires pour le traitement, l'évaluation et le suivi.
*
* DTO unifié pour les demandes d'aide dans le système de solidarité
*
* <p>Ce DTO représente une demande d'aide complète avec toutes les informations nécessaires pour le
* traitement, l'évaluation et le suivi. Remplace l'ancien AideDTO pour une approche unifiée.
*
* @author UnionFlow Team
* @version 1.0
* @version 2.0
* @since 2025-01-16
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DemandeAideDTO {
// === IDENTIFICATION ===
/**
* Identifiant unique de la demande d'aide
*/
private String id;
/**
* Numéro de référence de la demande (généré automatiquement)
*/
@Pattern(regexp = "^DA-\\d{4}-\\d{6}$", message = "Le numéro de référence doit suivre le format DA-YYYY-NNNNNN")
private String numeroReference;
// === INFORMATIONS DE BASE ===
/**
* Type d'aide demandée
*/
@NotNull(message = "Le type d'aide est obligatoire")
private TypeAide typeAide;
/**
* Titre court de la demande
*/
@NotBlank(message = "Le titre est obligatoire")
@Size(min = 10, max = 100, message = "Le titre doit contenir entre 10 et 100 caractères")
private String titre;
/**
* Description détaillée de la demande
*/
@NotBlank(message = "La description est obligatoire")
@Size(min = 50, max = 2000, message = "La description doit contenir entre 50 et 2000 caractères")
private String description;
/**
* Justification de la demande
*/
@Size(max = 1000, message = "La justification ne peut pas dépasser 1000 caractères")
private String justification;
// === MONTANT ET FINANCES ===
/**
* Montant demandé (si applicable)
*/
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant doit être positif")
@DecimalMax(value = "1000000.0", message = "Le montant ne peut pas dépasser 1 000 000 FCFA")
private Double montantDemande;
/**
* Montant approuvé (si différent du montant demandé)
*/
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant approuvé doit être positif")
private Double montantApprouve;
/**
* Montant versé effectivement
*/
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant versé doit être positif")
private Double montantVerse;
/**
* Devise du montant
*/
@Builder.Default
private String devise = "FCFA";
// === ACTEURS ===
/**
* Identifiant du demandeur
*/
@NotBlank(message = "L'identifiant du demandeur est obligatoire")
private String demandeurId;
/**
* Nom complet du demandeur
*/
private String demandeurNom;
/**
* Identifiant de l'évaluateur assigné
*/
private String evaluateurId;
/**
* Nom de l'évaluateur
*/
private String evaluateurNom;
/**
* Identifiant de l'approbateur
*/
private String approvateurId;
/**
* Nom de l'approbateur
*/
private String approvateurNom;
/**
* Identifiant de l'organisation
*/
@NotBlank(message = "L'identifiant de l'organisation est obligatoire")
private String organisationId;
// === STATUT ET PRIORITÉ ===
/**
* Statut actuel de la demande
*/
@NotNull(message = "Le statut est obligatoire")
@Builder.Default
private StatutAide statut = StatutAide.BROUILLON;
/**
* Priorité de la demande
*/
@NotNull(message = "La priorité est obligatoire")
@Builder.Default
private PrioriteAide priorite = PrioriteAide.NORMALE;
/**
* Motif de rejet (si applicable)
*/
@Size(max = 500, message = "Le motif de rejet ne peut pas dépasser 500 caractères")
private String motifRejet;
/**
* Commentaires de l'évaluateur
*/
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
private String commentairesEvaluateur;
// === DATES ===
/**
* Date de création de la demande
*/
@NotNull(message = "La date de création est obligatoire")
@Builder.Default
private LocalDateTime dateCreation = LocalDateTime.now();
/**
* Date de soumission de la demande
*/
private LocalDateTime dateSoumission;
/**
* Date limite de traitement
*/
private LocalDateTime dateLimiteTraitement;
/**
* Date d'évaluation
*/
private LocalDateTime dateEvaluation;
/**
* Date d'approbation
*/
private LocalDateTime dateApprobation;
/**
* Date de versement
*/
private LocalDateTime dateVersement;
/**
* Date de clôture
*/
private LocalDateTime dateCloture;
/**
* Date de dernière modification
*/
@Builder.Default
private LocalDateTime dateModification = LocalDateTime.now();
// === INFORMATIONS COMPLÉMENTAIRES ===
/**
* Pièces justificatives attachées
*/
private List<PieceJustificativeDTO> piecesJustificatives;
/**
* Bénéficiaires de l'aide (si différents du demandeur)
*/
private List<BeneficiaireAideDTO> beneficiaires;
/**
* Historique des changements de statut
*/
private List<HistoriqueStatutDTO> historiqueStatuts;
/**
* Commentaires et échanges
*/
private List<CommentaireAideDTO> commentaires;
/**
* Données personnalisées spécifiques au type d'aide
*/
private Map<String, Object> donneesPersonnalisees;
/**
* Tags pour catégorisation
*/
private List<String> tags;
// === MÉTADONNÉES ===
/**
* Indique si la demande est confidentielle
*/
@Builder.Default
private Boolean estConfidentielle = false;
/**
* Indique si la demande nécessite un suivi
*/
@Builder.Default
private Boolean necessiteSuivi = false;
/**
* Score de priorité calculé automatiquement
*/
private Double scorePriorite;
/**
* Nombre de vues de la demande
*/
@Builder.Default
private Integer nombreVues = 0;
/**
* Version du document (pour gestion des conflits)
*/
@Builder.Default
private Integer version = 1;
/**
* Informations de géolocalisation (si pertinent)
*/
private LocalisationDTO localisation;
/**
* Informations de contact d'urgence
*/
private ContactUrgenceDTO contactUrgence;
// === MÉTHODES UTILITAIRES ===
/**
* Vérifie si la demande est modifiable
*/
public boolean isModifiable() {
return statut != null && statut.permetModification();
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class DemandeAideDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
// === IDENTIFICATION ===
// ID hérité de BaseDTO
/** Numéro de référence de la demande (généré automatiquement) */
@Pattern(
regexp = ValidationConstants.REFERENCE_AIDE_PATTERN,
message = ValidationConstants.REFERENCE_AIDE_MESSAGE)
private String numeroReference;
// === INFORMATIONS DE BASE ===
/** Type d'aide demandée */
@NotNull(message = "Le type d'aide est obligatoire.")
private TypeAide typeAide;
/** Titre court de la demande */
@NotBlank(message = "Le titre" + ValidationConstants.OBLIGATOIRE_MESSAGE)
@Size(
min = ValidationConstants.TITRE_MIN_LENGTH,
max = ValidationConstants.TITRE_MAX_LENGTH,
message = ValidationConstants.TITRE_SIZE_MESSAGE)
private String titre;
/** Description détaillée de la demande */
@NotBlank(message = "La description" + ValidationConstants.OBLIGATOIRE_MESSAGE)
@Size(
min = ValidationConstants.DESCRIPTION_MIN_LENGTH,
max = ValidationConstants.DESCRIPTION_MAX_LENGTH,
message = ValidationConstants.DESCRIPTION_SIZE_MESSAGE)
private String description;
/** Justification de la demande */
@Size(
max = ValidationConstants.JUSTIFICATION_MAX_LENGTH,
message = ValidationConstants.JUSTIFICATION_SIZE_MESSAGE)
private String justification;
// === MONTANT ET FINANCES ===
/** Montant demandé (si applicable) */
@DecimalMin(
value = ValidationConstants.MONTANT_MIN_VALUE,
inclusive = false,
message = ValidationConstants.MONTANT_POSITIF_MESSAGE)
@Digits(
integer = ValidationConstants.MONTANT_INTEGER_DIGITS,
fraction = ValidationConstants.MONTANT_FRACTION_DIGITS,
message = ValidationConstants.MONTANT_DIGITS_MESSAGE)
private BigDecimal montantDemande;
/** Montant approuvé (si différent du montant demandé) */
@DecimalMin(
value = ValidationConstants.MONTANT_MIN_VALUE,
inclusive = false,
message = ValidationConstants.MONTANT_POSITIF_MESSAGE)
@Digits(
integer = ValidationConstants.MONTANT_INTEGER_DIGITS,
fraction = ValidationConstants.MONTANT_FRACTION_DIGITS,
message = ValidationConstants.MONTANT_DIGITS_MESSAGE)
private BigDecimal montantApprouve;
/** Montant versé effectivement */
@DecimalMin(
value = ValidationConstants.MONTANT_MIN_VALUE,
inclusive = false,
message = ValidationConstants.MONTANT_POSITIF_MESSAGE)
@Digits(
integer = ValidationConstants.MONTANT_INTEGER_DIGITS,
fraction = ValidationConstants.MONTANT_FRACTION_DIGITS,
message = ValidationConstants.MONTANT_DIGITS_MESSAGE)
private BigDecimal montantVerse;
/** Devise du montant (code ISO 3 lettres) */
@Pattern(
regexp = ValidationConstants.DEVISE_PATTERN,
message = ValidationConstants.DEVISE_MESSAGE)
private String devise = "XOF";
// === ACTEURS ===
/** Identifiant du demandeur (UUID) */
@NotNull(message = "L'identifiant du demandeur est obligatoire")
private UUID membreDemandeurId;
/** Nom complet du demandeur */
private String nomDemandeur;
/** Numéro de membre du demandeur */
private String numeroMembreDemandeur;
/** Identifiant de l'évaluateur assigné */
private String evaluateurId;
/** Nom de l'évaluateur */
private String evaluateurNom;
/** Identifiant de l'approbateur */
private String approvateurId;
/** Nom de l'approbateur */
private String approvateurNom;
/** Identifiant de l'organisation (UUID) */
@NotNull(message = "L'identifiant de l'organisation est obligatoire")
private UUID associationId;
/** Nom de l'association */
private String nomAssociation;
// === STATUT ET PRIORITÉ ===
/** Statut actuel de la demande */
@NotNull(message = "Le statut est obligatoire")
private StatutAide statut = StatutAide.BROUILLON;
/** Priorité de la demande */
@NotNull(message = "La priorité est obligatoire")
private PrioriteAide priorite = PrioriteAide.NORMALE;
/** Motif de rejet (si applicable) */
@Size(max = 500, message = "Le motif de rejet ne peut pas dépasser 500 caractères")
private String motifRejet;
/** Commentaires de l'évaluateur */
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
private String commentairesEvaluateur;
// === DATES ===
// Date de création héritée de BaseDTO
/** Date de soumission de la demande */
private LocalDateTime dateSoumission;
/** Date limite de traitement */
private LocalDateTime dateLimiteTraitement;
/** Date d'évaluation */
private LocalDateTime dateEvaluation;
/** Date d'approbation */
private LocalDateTime dateApprobation;
/** Date de versement */
private LocalDateTime dateVersement;
/** Date de clôture */
private LocalDateTime dateCloture;
// Date de modification héritée de BaseDTO
// === INFORMATIONS COMPLÉMENTAIRES ===
/** Pièces justificatives attachées */
private List<PieceJustificativeDTO> piecesJustificatives;
/** Bénéficiaires de l'aide (si différents du demandeur) */
private List<BeneficiaireAideDTO> beneficiaires;
/** Historique des changements de statut */
private List<HistoriqueStatutDTO> historiqueStatuts;
/** Commentaires et échanges */
private List<CommentaireAideDTO> commentaires;
/** Données personnalisées spécifiques au type d'aide */
private Map<String, Object> donneesPersonnalisees;
/** Tags pour catégorisation */
private List<String> tags;
// === MÉTADONNÉES ===
/** Indique si la demande est confidentielle */
private Boolean estConfidentielle = false;
/** Indique si la demande nécessite un suivi */
private Boolean necessiteSuivi = false;
/** Score de priorité calculé automatiquement */
private Double scorePriorite;
/** Nombre de vues de la demande */
private Integer nombreVues = 0;
// Version héritée de BaseDTO
/** Informations de géolocalisation (si pertinent) */
private LocalisationDTO localisation;
/** Informations de contact d'urgence */
private ContactUrgenceDTO contactUrgence;
// === CHAMPS ADDITIONNELS D'AIDE ===
/** Date limite pour l'aide */
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateLimite;
/** Justificatifs fournis */
private Boolean justificatifsFournis = false;
/** Liste des documents joints (noms de fichiers) */
@Size(max = 1000, message = "La liste des documents ne peut pas dépasser 1000 caractères")
private String documentsJoints;
/** Date de début de l'aide */
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateDebutAide;
/** Date de fin de l'aide */
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateFinAide;
/** Identifiant du membre aidant */
private UUID membreAidantId;
/** Nom du membre aidant */
private String nomAidant;
/** Mode de versement */
@Size(max = 50, message = "Le mode de versement ne peut pas dépasser 50 caractères")
private String modeVersement;
/** Numéro de transaction */
@Size(max = 100, message = "Le numéro de transaction ne peut pas dépasser 100 caractères")
private String numeroTransaction;
/** Identifiant de celui qui a rejeté */
private UUID rejeteParId;
/** Nom de celui qui a rejeté */
private String rejetePar;
/** Date de rejet */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateRejet;
/** Raison du rejet (si applicable) */
@Size(max = 500, message = "La raison du rejet ne peut pas dépasser 500 caractères")
private String raisonRejet;
// === CONSTRUCTEURS ===
/** Constructeur par défaut */
public DemandeAideDTO() {
super(); // Appelle le constructeur de BaseDTO qui génère l'UUID
this.statut = StatutAide.EN_ATTENTE;
this.priorite = PrioriteAide.NORMALE;
this.devise = "XOF";
this.nombreVues = 0;
this.numeroReference = genererNumeroReference();
}
// === MÉTHODES UTILITAIRES ===
/** Vérifie si la demande est modifiable */
public boolean estModifiable() {
return statut != null && statut.permetModification();
}
/** Vérifie si la demande peut être annulée */
public boolean peutEtreAnnulee() {
return statut != null && statut.permetAnnulation();
}
/** Vérifie si la demande est urgente */
public boolean estUrgente() {
return priorite != null && priorite.isUrgente();
}
/** Vérifie si la demande est terminée */
public boolean estTerminee() {
return statut != null && statut.isEstFinal();
}
/** Vérifie si la demande est en succès */
public boolean estEnSucces() {
return statut != null && statut.isSucces();
}
/** Calcule le pourcentage d'avancement */
public double getPourcentageAvancement() {
if (statut == null) {
return 0.0;
}
/**
* Vérifie si la demande peut être annulée
*/
public boolean peutEtreAnnulee() {
return statut != null && statut.permetAnnulation();
return switch (statut) {
case BROUILLON -> 5.0;
case SOUMISE -> 10.0;
case EN_ATTENTE -> 20.0;
case EN_COURS_EVALUATION -> 40.0;
case INFORMATIONS_REQUISES -> 35.0;
case APPROUVEE, APPROUVEE_PARTIELLEMENT -> 60.0;
case EN_COURS_TRAITEMENT -> 70.0;
case EN_COURS_VERSEMENT -> 85.0;
case VERSEE, LIVREE, TERMINEE -> 100.0;
case REJETEE, ANNULEE, EXPIREE -> 100.0;
case SUSPENDUE -> 50.0;
case EN_SUIVI -> 95.0;
case CLOTUREE -> 100.0;
};
}
/** Retourne le délai restant en heures */
public long getDelaiRestantHeures() {
if (dateLimiteTraitement == null) {
return -1;
}
/**
* Vérifie si la demande est urgente
*/
public boolean isUrgente() {
return priorite != null && priorite.isUrgente();
LocalDateTime maintenant = LocalDateTime.now();
if (maintenant.isAfter(dateLimiteTraitement)) {
return 0;
}
/**
* Vérifie si la demande est terminée
*/
public boolean isTerminee() {
return statut != null && statut.isEstFinal();
return java.time.Duration.between(maintenant, dateLimiteTraitement).toHours();
}
/** Vérifie si le délai est dépassé */
public boolean estDelaiDepasse() {
return getDelaiRestantHeures() == 0;
}
/** Retourne la durée de traitement en jours */
public long getDureeTraitementJours() {
if (dateCreation == null) {
return 0;
}
/**
* Vérifie si la demande est en succès
*/
public boolean isEnSucces() {
return statut != null && statut.isSucces();
}
/**
* Calcule le pourcentage d'avancement
*/
public double getPourcentageAvancement() {
if (statut == null) return 0.0;
return switch (statut) {
case BROUILLON -> 5.0;
case SOUMISE -> 10.0;
case EN_ATTENTE -> 20.0;
case EN_COURS_EVALUATION -> 40.0;
case INFORMATIONS_REQUISES -> 35.0;
case APPROUVEE, APPROUVEE_PARTIELLEMENT -> 60.0;
case EN_COURS_TRAITEMENT -> 70.0;
case EN_COURS_VERSEMENT -> 85.0;
case VERSEE, LIVREE, TERMINEE -> 100.0;
case REJETEE, ANNULEE, EXPIREE -> 100.0;
case SUSPENDUE -> 50.0;
case EN_SUIVI -> 95.0;
case CLOTUREE -> 100.0;
};
}
/**
* Retourne le délai restant en heures
*/
public long getDelaiRestantHeures() {
if (dateLimiteTraitement == null) return -1;
LocalDateTime maintenant = LocalDateTime.now();
if (maintenant.isAfter(dateLimiteTraitement)) return 0;
return java.time.Duration.between(maintenant, dateLimiteTraitement).toHours();
}
/**
* Vérifie si le délai est dépassé
*/
public boolean isDelaiDepasse() {
return getDelaiRestantHeures() == 0;
}
/**
* Retourne la durée de traitement en jours
*/
public long getDureeTraitementJours() {
if (dateCreation == null) return 0;
LocalDateTime dateFin = dateCloture != null ? dateCloture : LocalDateTime.now();
return java.time.Duration.between(dateCreation, dateFin).toDays();
LocalDateTime dateFin = dateCloture != null ? dateCloture : LocalDateTime.now();
return java.time.Duration.between(dateCreation, dateFin).toDays();
}
// === MÉTHODES MÉTIER D'AIDE ===
/** Retourne le libellé du statut */
public String getStatutLibelle() {
return statut != null ? statut.getLibelle() : "Non défini";
}
/** Retourne le libellé de la priorité */
public String getPrioriteLibelle() {
return priorite != null ? priorite.getLibelle() : "Normale";
}
/** Approuve la demande d'aide */
public void approuver(
UUID evaluateurId, String nomEvaluateur, BigDecimal montantApprouve, String commentaires) {
this.statut = StatutAide.APPROUVEE;
this.evaluateurId = evaluateurId.toString();
this.evaluateurNom = nomEvaluateur;
this.montantApprouve = montantApprouve;
this.commentairesEvaluateur = commentaires;
this.dateEvaluation = LocalDateTime.now();
this.dateApprobation = LocalDateTime.now();
marquerCommeModifie(nomEvaluateur);
}
/** Rejette la demande d'aide */
public void rejeter(UUID evaluateurId, String nomEvaluateur, String raison) {
this.statut = StatutAide.REJETEE;
this.rejeteParId = evaluateurId;
this.rejetePar = nomEvaluateur;
this.raisonRejet = raison;
this.dateRejet = LocalDateTime.now();
this.dateEvaluation = LocalDateTime.now();
marquerCommeModifie(nomEvaluateur);
}
/** Démarre l'aide */
public void demarrerAide(UUID aidantId, String nomAidant) {
this.statut = StatutAide.EN_COURS_TRAITEMENT;
this.membreAidantId = aidantId;
this.nomAidant = nomAidant;
this.dateDebutAide = LocalDate.now();
marquerCommeModifie(nomAidant);
}
/** Termine l'aide avec versement */
public void terminerAvecVersement(
BigDecimal montantVerse, String modeVersement, String numeroTransaction) {
this.statut = StatutAide.TERMINEE;
this.montantVerse = montantVerse;
this.modeVersement = modeVersement;
this.numeroTransaction = numeroTransaction;
this.dateVersement = LocalDateTime.now();
this.dateFinAide = LocalDate.now();
marquerCommeModifie("SYSTEM");
}
/** Incrémente le nombre de vues */
public void incrementerVues() {
if (nombreVues == null) {
nombreVues = 1;
} else {
nombreVues++;
}
}
/** Génère un numéro de référence unique */
public static String genererNumeroReference() {
return "DA-"
+ LocalDate.now().getYear()
+ "-"
+ String.format("%06d", (int) (Math.random() * 1000000));
}
// === GETTERS EXPLICITES POUR COMPATIBILITÉ ===
/** Retourne le type d'aide demandée */
public TypeAide getTypeAide() {
return typeAide;
}
/** Retourne le montant demandé */
public BigDecimal getMontantDemande() {
return montantDemande;
}
/** Marque comme modifié */
public void marquerCommeModifie(String utilisateur) {
LocalDateTime maintenant = LocalDateTime.now();
this.dateModification = maintenant;
super.marquerCommeModifie(utilisateur);
}
}

View File

@@ -1,18 +1,17 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour l'évaluation d'une aide reçue ou fournie
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -22,326 +21,236 @@ import java.util.Map;
@AllArgsConstructor
@Builder
public class EvaluationAideDTO {
/**
* Identifiant unique de l'évaluation
*/
private String id;
/**
* Identifiant de la demande d'aide évaluée
*/
@NotBlank(message = "L'identifiant de la demande d'aide est obligatoire")
private String demandeAideId;
/**
* Identifiant de la proposition d'aide évaluée (si applicable)
*/
private String propositionAideId;
/**
* Identifiant de l'évaluateur
*/
@NotBlank(message = "L'identifiant de l'évaluateur est obligatoire")
private String evaluateurId;
/**
* Nom de l'évaluateur
*/
private String evaluateurNom;
/**
* Rôle de l'évaluateur (beneficiaire, proposant, evaluateur_externe)
*/
@NotBlank(message = "Le rôle de l'évaluateur est obligatoire")
private String roleEvaluateur;
/**
* Type d'évaluation
*/
@NotNull(message = "Le type d'évaluation est obligatoire")
@Builder.Default
private TypeEvaluation typeEvaluation = TypeEvaluation.SATISFACTION_BENEFICIAIRE;
/**
* Note globale (1-5)
*/
@NotNull(message = "La note globale est obligatoire")
@DecimalMin(value = "1.0", message = "La note doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note ne peut pas dépasser 5")
private Double noteGlobale;
/**
* Notes détaillées par critère
*/
private Map<String, Double> notesDetaillees;
/**
* Commentaire principal
*/
@Size(min = 10, max = 1000, message = "Le commentaire doit contenir entre 10 et 1000 caractères")
private String commentairePrincipal;
/**
* Points positifs
*/
@Size(max = 500, message = "Les points positifs ne peuvent pas dépasser 500 caractères")
private String pointsPositifs;
/**
* Points d'amélioration
*/
@Size(max = 500, message = "Les points d'amélioration ne peuvent pas dépasser 500 caractères")
private String pointsAmelioration;
/**
* Recommandations
*/
@Size(max = 500, message = "Les recommandations ne peuvent pas dépasser 500 caractères")
private String recommandations;
/**
* Indique si l'évaluateur recommande cette aide/proposant
*/
@Builder.Default
private Boolean recommande = true;
/**
* Indique si l'aide a été utile
*/
@Builder.Default
private Boolean aideUtile = true;
/**
* Indique si l'aide a résolu le problème
*/
@Builder.Default
private Boolean problemeResolu = true;
/**
* Délai de réponse perçu (1=très lent, 5=très rapide)
*/
@DecimalMin(value = "1.0", message = "La note délai doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note délai ne peut pas dépasser 5")
private Double noteDelaiReponse;
/**
* Qualité de la communication (1=très mauvaise, 5=excellente)
*/
@DecimalMin(value = "1.0", message = "La note communication doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note communication ne peut pas dépasser 5")
private Double noteCommunication;
/**
* Professionnalisme (1=très mauvais, 5=excellent)
*/
@DecimalMin(value = "1.0", message = "La note professionnalisme doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note professionnalisme ne peut pas dépasser 5")
private Double noteProfessionnalisme;
/**
* Respect des engagements (1=très mauvais, 5=excellent)
*/
@DecimalMin(value = "1.0", message = "La note engagement doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note engagement ne peut pas dépasser 5")
private Double noteRespectEngagements;
/**
* Date de création de l'évaluation
*/
@NotNull(message = "La date de création est obligatoire")
@Builder.Default
private LocalDateTime dateCreation = LocalDateTime.now();
/**
* Date de dernière modification
*/
@Builder.Default
private LocalDateTime dateModification = LocalDateTime.now();
/**
* Indique si l'évaluation est publique
*/
@Builder.Default
private Boolean estPublique = true;
/**
* Indique si l'évaluation est anonyme
*/
@Builder.Default
private Boolean estAnonyme = false;
/**
* Indique si l'évaluation a été vérifiée
*/
@Builder.Default
private Boolean estVerifiee = false;
/**
* Date de vérification
*/
private LocalDateTime dateVerification;
/**
* Identifiant du vérificateur
*/
private String verificateurId;
/**
* Pièces jointes à l'évaluation (photos, documents)
*/
private List<PieceJustificativeDTO> piecesJointes;
/**
* Tags associés à l'évaluation
*/
private List<String> tags;
/**
* Données additionnelles
*/
private Map<String, Object> donneesAdditionnelles;
/**
* Nombre de personnes qui ont trouvé cette évaluation utile
*/
@Builder.Default
private Integer nombreUtile = 0;
/**
* Nombre de signalements de cette évaluation
*/
@Builder.Default
private Integer nombreSignalements = 0;
/**
* Statut de l'évaluation
*/
@NotNull(message = "Le statut est obligatoire")
@Builder.Default
private StatutEvaluation statut = StatutEvaluation.ACTIVE;
/**
* Énumération des types d'évaluation
*/
public enum TypeEvaluation {
SATISFACTION_BENEFICIAIRE("Satisfaction du bénéficiaire"),
EVALUATION_PROPOSANT("Évaluation du proposant"),
EVALUATION_PROCESSUS("Évaluation du processus"),
SUIVI_POST_AIDE("Suivi post-aide"),
EVALUATION_IMPACT("Évaluation d'impact"),
RETOUR_EXPERIENCE("Retour d'expérience");
private final String libelle;
TypeEvaluation(String libelle) {
this.libelle = libelle;
}
public String getLibelle() {
return libelle;
}
/** Identifiant unique de l'évaluation */
private String id;
/** Identifiant de la demande d'aide évaluée */
@NotBlank(message = "L'identifiant de la demande d'aide est obligatoire")
private String demandeAideId;
/** Identifiant de la proposition d'aide évaluée (si applicable) */
private String propositionAideId;
/** Identifiant de l'évaluateur */
@NotBlank(message = "L'identifiant de l'évaluateur est obligatoire")
private String evaluateurId;
/** Nom de l'évaluateur */
private String evaluateurNom;
/** Rôle de l'évaluateur (beneficiaire, proposant, evaluateur_externe) */
@NotBlank(message = "Le rôle de l'évaluateur est obligatoire")
private String roleEvaluateur;
/** Type d'évaluation */
@NotNull(message = "Le type d'évaluation est obligatoire")
@Builder.Default
private TypeEvaluation typeEvaluation = TypeEvaluation.SATISFACTION_BENEFICIAIRE;
/** Note globale (1-5) */
@NotNull(message = "La note globale est obligatoire")
@DecimalMin(value = "1.0", message = "La note doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note ne peut pas dépasser 5")
private Double noteGlobale;
/** Notes détaillées par critère */
private Map<String, Double> notesDetaillees;
/** Commentaire principal */
@Size(min = 10, max = 1000, message = "Le commentaire doit contenir entre 10 et 1000 caractères")
private String commentairePrincipal;
/** Points positifs */
@Size(max = 500, message = "Les points positifs ne peuvent pas dépasser 500 caractères")
private String pointsPositifs;
/** Points d'amélioration */
@Size(max = 500, message = "Les points d'amélioration ne peuvent pas dépasser 500 caractères")
private String pointsAmelioration;
/** Recommandations */
@Size(max = 500, message = "Les recommandations ne peuvent pas dépasser 500 caractères")
private String recommandations;
/** Indique si l'évaluateur recommande cette aide/proposant */
@Builder.Default private Boolean recommande = true;
/** Indique si l'aide a été utile */
@Builder.Default private Boolean aideUtile = true;
/** Indique si l'aide a résolu le problème */
@Builder.Default private Boolean problemeResolu = true;
/** Délai de réponse perçu (1=très lent, 5=très rapide) */
@DecimalMin(value = "1.0", message = "La note délai doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note délai ne peut pas dépasser 5")
private Double noteDelaiReponse;
/** Qualité de la communication (1=très mauvaise, 5=excellente) */
@DecimalMin(value = "1.0", message = "La note communication doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note communication ne peut pas dépasser 5")
private Double noteCommunication;
/** Professionnalisme (1=très mauvais, 5=excellent) */
@DecimalMin(value = "1.0", message = "La note professionnalisme doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note professionnalisme ne peut pas dépasser 5")
private Double noteProfessionnalisme;
/** Respect des engagements (1=très mauvais, 5=excellent) */
@DecimalMin(value = "1.0", message = "La note engagement doit être au moins 1")
@DecimalMax(value = "5.0", message = "La note engagement ne peut pas dépasser 5")
private Double noteRespectEngagements;
/** Date de création de l'évaluation */
@NotNull(message = "La date de création est obligatoire")
@Builder.Default
private LocalDateTime dateCreation = LocalDateTime.now();
/** Date de dernière modification */
@Builder.Default private LocalDateTime dateModification = LocalDateTime.now();
/** Indique si l'évaluation est publique */
@Builder.Default private Boolean estPublique = true;
/** Indique si l'évaluation est anonyme */
@Builder.Default private Boolean estAnonyme = false;
/** Indique si l'évaluation a été vérifiée */
@Builder.Default private Boolean estVerifiee = false;
/** Date de vérification */
private LocalDateTime dateVerification;
/** Identifiant du vérificateur */
private String verificateurId;
/** Pièces jointes à l'évaluation (photos, documents) */
private List<PieceJustificativeDTO> piecesJointes;
/** Tags associés à l'évaluation */
private List<String> tags;
/** Données additionnelles */
private Map<String, Object> donneesAdditionnelles;
/** Nombre de personnes qui ont trouvé cette évaluation utile */
@Builder.Default private Integer nombreUtile = 0;
/** Nombre de signalements de cette évaluation */
@Builder.Default private Integer nombreSignalements = 0;
/** Statut de l'évaluation */
@NotNull(message = "Le statut est obligatoire")
@Builder.Default
private StatutEvaluation statut = StatutEvaluation.ACTIVE;
/** Énumération des types d'évaluation */
public enum TypeEvaluation {
SATISFACTION_BENEFICIAIRE("Satisfaction du bénéficiaire"),
EVALUATION_PROPOSANT("Évaluation du proposant"),
EVALUATION_PROCESSUS("Évaluation du processus"),
SUIVI_POST_AIDE("Suivi post-aide"),
EVALUATION_IMPACT("Évaluation d'impact"),
RETOUR_EXPERIENCE("Retour d'expérience");
private final String libelle;
TypeEvaluation(String libelle) {
this.libelle = libelle;
}
/**
* Énumération des statuts d'évaluation
*/
public enum StatutEvaluation {
BROUILLON("Brouillon"),
ACTIVE("Active"),
MASQUEE("Masquée"),
SIGNALEE("Signalée"),
SUPPRIMEE("Supprimée");
private final String libelle;
StatutEvaluation(String libelle) {
this.libelle = libelle;
}
public String getLibelle() {
return libelle;
}
public String getLibelle() {
return libelle;
}
// === MÉTHODES UTILITAIRES ===
/**
* Calcule la note moyenne des critères détaillés
*/
public Double getNoteMoyenneDetaillees() {
if (notesDetaillees == null || notesDetaillees.isEmpty()) {
return noteGlobale;
}
return notesDetaillees.values().stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(noteGlobale);
}
/** Énumération des statuts d'évaluation */
public enum StatutEvaluation {
BROUILLON("Brouillon"),
ACTIVE("Active"),
MASQUEE("Masquée"),
SIGNALEE("Signalée"),
SUPPRIMEE("Supprimée");
private final String libelle;
StatutEvaluation(String libelle) {
this.libelle = libelle;
}
/**
* Vérifie si l'évaluation est positive (note >= 4)
*/
public boolean isPositive() {
return noteGlobale != null && noteGlobale >= 4.0;
public String getLibelle() {
return libelle;
}
/**
* Vérifie si l'évaluation est négative (note <= 2)
*/
public boolean isNegative() {
return noteGlobale != null && noteGlobale <= 2.0;
}
/**
* Calcule un score de qualité global
*/
public double getScoreQualite() {
double score = noteGlobale != null ? noteGlobale : 0.0;
// Bonus pour les notes détaillées
if (noteDelaiReponse != null) score += noteDelaiReponse * 0.1;
if (noteCommunication != null) score += noteCommunication * 0.1;
if (noteProfessionnalisme != null) score += noteProfessionnalisme * 0.1;
if (noteRespectEngagements != null) score += noteRespectEngagements * 0.1;
// Bonus pour recommandation
if (recommande != null && recommande) score += 0.2;
// Bonus pour résolution du problème
if (problemeResolu != null && problemeResolu) score += 0.3;
// Malus pour signalements
if (nombreSignalements > 0) score -= nombreSignalements * 0.1;
return Math.min(5.0, Math.max(0.0, score));
}
/**
* Vérifie si l'évaluation est complète
*/
public boolean isComplete() {
return noteGlobale != null &&
commentairePrincipal != null && !commentairePrincipal.trim().isEmpty() &&
recommande != null &&
aideUtile != null &&
problemeResolu != null;
}
/**
* Retourne le niveau de satisfaction
*/
public String getNiveauSatisfaction() {
if (noteGlobale == null) return "Non évalué";
return switch (noteGlobale.intValue()) {
case 5 -> "Excellent";
case 4 -> "Très bien";
case 3 -> "Bien";
case 2 -> "Passable";
case 1 -> "Insuffisant";
default -> "Non évalué";
};
}
// === MÉTHODES UTILITAIRES ===
/** Calcule la note moyenne des critères détaillés */
public Double getNoteMoyenneDetaillees() {
if (notesDetaillees == null || notesDetaillees.isEmpty()) {
return noteGlobale;
}
return notesDetaillees.values().stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(noteGlobale);
}
/** Vérifie si l'évaluation est positive (note >= 4) */
public boolean isPositive() {
return noteGlobale != null && noteGlobale >= 4.0;
}
/** Vérifie si l'évaluation est négative (note <= 2) */
public boolean isNegative() {
return noteGlobale != null && noteGlobale <= 2.0;
}
/** Calcule un score de qualité global */
public double getScoreQualite() {
double score = noteGlobale != null ? noteGlobale : 0.0;
// Bonus pour les notes détaillées
if (noteDelaiReponse != null) score += noteDelaiReponse * 0.1;
if (noteCommunication != null) score += noteCommunication * 0.1;
if (noteProfessionnalisme != null) score += noteProfessionnalisme * 0.1;
if (noteRespectEngagements != null) score += noteRespectEngagements * 0.1;
// Bonus pour recommandation
if (recommande != null && recommande) score += 0.2;
// Bonus pour résolution du problème
if (problemeResolu != null && problemeResolu) score += 0.3;
// Malus pour signalements
if (nombreSignalements > 0) score -= nombreSignalements * 0.1;
return Math.min(5.0, Math.max(0.0, score));
}
/** Vérifie si l'évaluation est complète */
public boolean isComplete() {
return noteGlobale != null
&& commentairePrincipal != null
&& !commentairePrincipal.trim().isEmpty()
&& recommande != null
&& aideUtile != null
&& problemeResolu != null;
}
/** Retourne le niveau de satisfaction */
public String getNiveauSatisfaction() {
if (noteGlobale == null) return "Non évalué";
return switch (noteGlobale.intValue()) {
case 5 -> "Excellent";
case 4 -> "Très bien";
case 3 -> "Bien";
case 2 -> "Passable";
case 1 -> "Insuffisant";
default -> "Non évalué";
};
}
}

View File

@@ -1,18 +1,16 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.time.LocalDateTime;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour l'historique des changements de statut d'une demande d'aide
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -22,66 +20,43 @@ import java.time.LocalDateTime;
@AllArgsConstructor
@Builder
public class HistoriqueStatutDTO {
/**
* Identifiant unique de l'entrée d'historique
*/
private String id;
/**
* Ancien statut
*/
private StatutAide ancienStatut;
/**
* Nouveau statut
*/
@NotNull(message = "Le nouveau statut est obligatoire")
private StatutAide nouveauStatut;
/**
* Date du changement de statut
*/
@NotNull(message = "La date de changement est obligatoire")
@Builder.Default
private LocalDateTime dateChangement = LocalDateTime.now();
/**
* Identifiant de la personne qui a effectué le changement
*/
@NotBlank(message = "L'identifiant de l'auteur est obligatoire")
private String auteurId;
/**
* Nom de la personne qui a effectué le changement
*/
private String auteurNom;
/**
* Motif du changement de statut
*/
@Size(max = 500, message = "Le motif ne peut pas dépasser 500 caractères")
private String motif;
/**
* Commentaires additionnels
*/
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
private String commentaires;
/**
* Indique si le changement est automatique (système)
*/
@Builder.Default
private Boolean estAutomatique = false;
/**
* Durée en minutes depuis le statut précédent
*/
private Long dureeDepuisPrecedent;
/**
* Données additionnelles liées au changement
*/
private java.util.Map<String, Object> donneesAdditionnelles;
/** Identifiant unique de l'entrée d'historique */
private String id;
/** Ancien statut */
private StatutAide ancienStatut;
/** Nouveau statut */
@NotNull(message = "Le nouveau statut est obligatoire")
private StatutAide nouveauStatut;
/** Date du changement de statut */
@NotNull(message = "La date de changement est obligatoire")
@Builder.Default
private LocalDateTime dateChangement = LocalDateTime.now();
/** Identifiant de la personne qui a effectué le changement */
@NotBlank(message = "L'identifiant de l'auteur est obligatoire")
private String auteurId;
/** Nom de la personne qui a effectué le changement */
private String auteurNom;
/** Motif du changement de statut */
@Size(max = 500, message = "Le motif ne peut pas dépasser 500 caractères")
private String motif;
/** Commentaires additionnels */
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
private String commentaires;
/** Indique si le changement est automatique (système) */
@Builder.Default private Boolean estAutomatique = false;
/** Durée en minutes depuis le statut précédent */
private Long dureeDepuisPrecedent;
/** Données additionnelles liées au changement */
private java.util.Map<String, Object> donneesAdditionnelles;
}

View File

@@ -1,14 +1,14 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les informations de géolocalisation
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -18,60 +18,41 @@ import lombok.Builder;
@AllArgsConstructor
@Builder
public class LocalisationDTO {
/**
* Latitude
*/
@DecimalMin(value = "-90.0", message = "La latitude doit être comprise entre -90 et 90")
@DecimalMax(value = "90.0", message = "La latitude doit être comprise entre -90 et 90")
private Double latitude;
/**
* Longitude
*/
@DecimalMin(value = "-180.0", message = "La longitude doit être comprise entre -180 et 180")
@DecimalMax(value = "180.0", message = "La longitude doit être comprise entre -180 et 180")
private Double longitude;
/**
* Adresse complète
*/
@Size(max = 300, message = "L'adresse ne peut pas dépasser 300 caractères")
private String adresseComplete;
/**
* Ville
*/
@Size(max = 100, message = "La ville ne peut pas dépasser 100 caractères")
private String ville;
/**
* Région/Province
*/
@Size(max = 100, message = "La région ne peut pas dépasser 100 caractères")
private String region;
/**
* Pays
*/
@Size(max = 100, message = "Le pays ne peut pas dépasser 100 caractères")
private String pays;
/**
* Code postal
*/
@Size(max = 20, message = "Le code postal ne peut pas dépasser 20 caractères")
private String codePostal;
/**
* Précision de la localisation en mètres
*/
@Min(value = 0, message = "La précision doit être positive")
private Double precision;
/**
* Indique si la localisation est approximative
*/
@Builder.Default
private Boolean estApproximative = false;
/** Latitude */
@DecimalMin(value = "-90.0", message = "La latitude doit être comprise entre -90 et 90")
@DecimalMax(value = "90.0", message = "La latitude doit être comprise entre -90 et 90")
private Double latitude;
/** Longitude */
@DecimalMin(value = "-180.0", message = "La longitude doit être comprise entre -180 et 180")
@DecimalMax(value = "180.0", message = "La longitude doit être comprise entre -180 et 180")
private Double longitude;
/** Adresse complète */
@Size(max = 300, message = "L'adresse ne peut pas dépasser 300 caractères")
private String adresseComplete;
/** Ville */
@Size(max = 100, message = "La ville ne peut pas dépasser 100 caractères")
private String ville;
/** Région/Province */
@Size(max = 100, message = "La région ne peut pas dépasser 100 caractères")
private String region;
/** Pays */
@Size(max = 100, message = "Le pays ne peut pas dépasser 100 caractères")
private String pays;
/** Code postal */
@Size(max = 20, message = "Le code postal ne peut pas dépasser 20 caractères")
private String codePostal;
/** Précision de la localisation en mètres */
@Min(value = 0, message = "La précision doit être positive")
private Double precision;
/** Indique si la localisation est approximative */
@Builder.Default private Boolean estApproximative = false;
}

View File

@@ -1,16 +1,15 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.time.LocalDateTime;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les pièces justificatives d'une demande d'aide
*
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -20,79 +19,50 @@ import java.time.LocalDateTime;
@AllArgsConstructor
@Builder
public class PieceJustificativeDTO {
/**
* Identifiant unique de la pièce justificative
*/
private String id;
/**
* Nom du fichier
*/
@NotBlank(message = "Le nom du fichier est obligatoire")
@Size(max = 255, message = "Le nom du fichier ne peut pas dépasser 255 caractères")
private String nomFichier;
/**
* Type de pièce justificative
*/
@NotBlank(message = "Le type de pièce est obligatoire")
private String typePiece;
/**
* Description de la pièce
*/
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
private String description;
/**
* URL ou chemin d'accès au fichier
*/
@NotBlank(message = "L'URL du fichier est obligatoire")
private String urlFichier;
/**
* Type MIME du fichier
*/
private String typeMime;
/**
* Taille du fichier en octets
*/
@Min(value = 1, message = "La taille du fichier doit être positive")
private Long tailleFichier;
/**
* Indique si la pièce est obligatoire
*/
@Builder.Default
private Boolean estObligatoire = false;
/**
* Indique si la pièce a été vérifiée
*/
@Builder.Default
private Boolean estVerifiee = false;
/**
* Date d'ajout de la pièce
*/
@Builder.Default
private LocalDateTime dateAjout = LocalDateTime.now();
/**
* Date de vérification
*/
private LocalDateTime dateVerification;
/**
* Identifiant de la personne qui a vérifié
*/
private String verificateurId;
/**
* Commentaires sur la vérification
*/
@Size(max = 500, message = "Les commentaires ne peuvent pas dépasser 500 caractères")
private String commentairesVerification;
/** Identifiant unique de la pièce justificative */
private String id;
/** Nom du fichier */
@NotBlank(message = "Le nom du fichier est obligatoire")
@Size(max = 255, message = "Le nom du fichier ne peut pas dépasser 255 caractères")
private String nomFichier;
/** Type de pièce justificative */
@NotBlank(message = "Le type de pièce est obligatoire")
private String typePiece;
/** Description de la pièce */
@Size(max = 500, message = "La description ne peut pas dépasser 500 caractères")
private String description;
/** URL ou chemin d'accès au fichier */
@NotBlank(message = "L'URL du fichier est obligatoire")
private String urlFichier;
/** Type MIME du fichier */
private String typeMime;
/** Taille du fichier en octets */
@Min(value = 1, message = "La taille du fichier doit être positive")
private Long tailleFichier;
/** Indique si la pièce est obligatoire */
@Builder.Default private Boolean estObligatoire = false;
/** Indique si la pièce a été vérifiée */
@Builder.Default private Boolean estVerifiee = false;
/** Date d'ajout de la pièce */
@Builder.Default private LocalDateTime dateAjout = LocalDateTime.now();
/** Date de vérification */
private LocalDateTime dateVerification;
/** Identifiant de la personne qui a vérifié */
private String verificateurId;
/** Commentaires sur la vérification */
@Size(max = 500, message = "Les commentaires ne peuvent pas dépasser 500 caractères")
private String commentairesVerification;
}

View File

@@ -1,23 +1,23 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.api.validation.ValidationConstants;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DTO pour les propositions d'aide dans le système de solidarité
*
* Ce DTO représente une proposition d'aide faite par un membre pour aider
* soit une demande spécifique, soit de manière générale.
*
*
* <p>Ce DTO représente une proposition d'aide faite par un membre pour aider soit une demande
* spécifique, soit de manière générale.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
@@ -27,362 +27,264 @@ import java.util.Map;
@AllArgsConstructor
@Builder
public class PropositionAideDTO {
// === IDENTIFICATION ===
/**
* Identifiant unique de la proposition d'aide
*/
private String id;
/**
* Numéro de référence de la proposition (généré automatiquement)
*/
@Pattern(regexp = "^PA-\\d{4}-\\d{6}$", message = "Le numéro de référence doit suivre le format PA-YYYY-NNNNNN")
private String numeroReference;
// === INFORMATIONS DE BASE ===
/**
* Type d'aide proposée
*/
@NotNull(message = "Le type d'aide proposée est obligatoire")
private TypeAide typeAide;
/**
* Titre de la proposition
*/
@NotBlank(message = "Le titre est obligatoire")
@Size(min = 10, max = 100, message = "Le titre doit contenir entre 10 et 100 caractères")
private String titre;
/**
* Description détaillée de l'aide proposée
*/
@NotBlank(message = "La description est obligatoire")
@Size(min = 20, max = 1000, message = "La description doit contenir entre 20 et 1000 caractères")
private String description;
/**
* Conditions ou critères pour bénéficier de l'aide
*/
@Size(max = 500, message = "Les conditions ne peuvent pas dépasser 500 caractères")
private String conditions;
// === MONTANT ET CAPACITÉ ===
/**
* Montant maximum que le proposant peut offrir (si applicable)
*/
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant doit être positif")
@DecimalMax(value = "1000000.0", message = "Le montant ne peut pas dépasser 1 000 000 FCFA")
private Double montantMaximum;
/**
* Nombre maximum de bénéficiaires
*/
@Min(value = 1, message = "Le nombre de bénéficiaires doit être au moins 1")
@Max(value = 100, message = "Le nombre de bénéficiaires ne peut pas dépasser 100")
@Builder.Default
private Integer nombreMaxBeneficiaires = 1;
/**
* Devise du montant
*/
@Builder.Default
private String devise = "FCFA";
// === ACTEURS ===
/**
* Identifiant du proposant
*/
@NotBlank(message = "L'identifiant du proposant est obligatoire")
private String proposantId;
/**
* Nom complet du proposant
*/
private String proposantNom;
/**
* Identifiant de l'organisation du proposant
*/
@NotBlank(message = "L'identifiant de l'organisation est obligatoire")
private String organisationId;
/**
* Identifiant de la demande d'aide liée (si proposition spécifique)
*/
private String demandeAideId;
// === STATUT ET DISPONIBILITÉ ===
/**
* Statut de la proposition
*/
@NotNull(message = "Le statut est obligatoire")
@Builder.Default
private StatutProposition statut = StatutProposition.ACTIVE;
/**
* Indique si la proposition est disponible
*/
@Builder.Default
private Boolean estDisponible = true;
/**
* Indique si la proposition est récurrente
*/
@Builder.Default
private Boolean estRecurrente = false;
/**
* Fréquence de récurrence (si applicable)
*/
private String frequenceRecurrence;
// === DATES ET DÉLAIS ===
/**
* Date de création de la proposition
*/
@NotNull(message = "La date de création est obligatoire")
@Builder.Default
private LocalDateTime dateCreation = LocalDateTime.now();
/**
* Date d'expiration de la proposition
*/
private LocalDateTime dateExpiration;
/**
* Date de dernière modification
*/
@Builder.Default
private LocalDateTime dateModification = LocalDateTime.now();
/**
* Délai de réponse souhaité en heures
*/
@Min(value = 1, message = "Le délai de réponse doit être au moins 1 heure")
@Max(value = 8760, message = "Le délai de réponse ne peut pas dépasser 1 an")
@Builder.Default
private Integer delaiReponseHeures = 72;
// === CRITÈRES ET PRÉFÉRENCES ===
/**
* Critères de sélection des bénéficiaires
*/
private List<CritereSelectionDTO> criteresSelection;
/**
* Zones géographiques couvertes
*/
private List<String> zonesGeographiques;
/**
* Groupes cibles (âge, situation, etc.)
*/
private List<String> groupesCibles;
/**
* Compétences ou ressources disponibles
*/
private List<String> competencesRessources;
// === CONTACT ET DISPONIBILITÉ ===
/**
* Informations de contact préférées
*/
private ContactProposantDTO contactProposant;
/**
* Créneaux de disponibilité
*/
private List<CreneauDisponibiliteDTO> creneauxDisponibilite;
/**
* Mode de contact préféré
*/
private String modeContactPrefere;
// === HISTORIQUE ET SUIVI ===
/**
* Nombre de demandes traitées avec cette proposition
*/
@Builder.Default
private Integer nombreDemandesTraitees = 0;
/**
* Nombre de bénéficiaires aidés
*/
@Builder.Default
private Integer nombreBeneficiairesAides = 0;
/**
* Montant total versé
*/
@Builder.Default
private Double montantTotalVerse = 0.0;
/**
* Note moyenne des bénéficiaires
*/
@DecimalMin(value = "0.0", message = "La note doit être positive")
@DecimalMax(value = "5.0", message = "La note ne peut pas dépasser 5")
private Double noteMoyenne;
/**
* Nombre d'évaluations reçues
*/
@Builder.Default
private Integer nombreEvaluations = 0;
// === MÉTADONNÉES ===
/**
* Tags pour catégorisation
*/
private List<String> tags;
/**
* Données personnalisées
*/
private Map<String, Object> donneesPersonnalisees;
/**
* Indique si la proposition est mise en avant
*/
@Builder.Default
private Boolean estMiseEnAvant = false;
/**
* Score de pertinence calculé automatiquement
*/
private Double scorePertinence;
/**
* Nombre de vues de la proposition
*/
@Builder.Default
private Integer nombreVues = 0;
/**
* Nombre de candidatures reçues
*/
@Builder.Default
private Integer nombreCandidatures = 0;
// === MÉTHODES UTILITAIRES ===
/**
* Vérifie si la proposition est active et disponible
*/
public boolean isActiveEtDisponible() {
return statut == StatutProposition.ACTIVE && estDisponible && !isExpiree();
// === IDENTIFICATION ===
/** Identifiant unique de la proposition d'aide */
private String id;
/** Numéro de référence de la proposition (généré automatiquement) */
@Pattern(
regexp = "^PA-\\d{4}-\\d{6}$",
message = "Le numéro de référence doit suivre le format PA-YYYY-NNNNNN")
private String numeroReference;
// === INFORMATIONS DE BASE ===
/** Type d'aide proposée */
@NotNull(message = "Le type d'aide proposée est obligatoire")
private TypeAide typeAide;
/** Titre de la proposition */
@NotBlank(message = "Le titre est obligatoire")
@Size(min = 10, max = 100, message = "Le titre doit contenir entre 10 et 100 caractères")
private String titre;
/** Description détaillée de l'aide proposée */
@NotBlank(message = "La description est obligatoire")
@Size(min = 20, max = 1000, message = "La description doit contenir entre 20 et 1000 caractères")
private String description;
/** Conditions ou critères pour bénéficier de l'aide */
@Size(max = 500, message = "Les conditions ne peuvent pas dépasser 500 caractères")
private String conditions;
// === MONTANT ET CAPACITÉ ===
/** Montant maximum que le proposant peut offrir (si applicable) */
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant doit être positif")
@DecimalMax(value = "1000000.0", message = "Le montant ne peut pas dépasser 1 000 000 FCFA")
@Digits(
integer = ValidationConstants.MONTANT_INTEGER_DIGITS,
fraction = ValidationConstants.MONTANT_FRACTION_DIGITS,
message = ValidationConstants.MONTANT_DIGITS_MESSAGE)
private BigDecimal montantMaximum;
/** Nombre maximum de bénéficiaires */
@Min(value = 1, message = "Le nombre de bénéficiaires doit être au moins 1")
@Max(value = 100, message = "Le nombre de bénéficiaires ne peut pas dépasser 100")
@Builder.Default
private Integer nombreMaxBeneficiaires = 1;
/** Devise du montant */
@Builder.Default private String devise = "FCFA";
// === ACTEURS ===
/** Identifiant du proposant */
@NotBlank(message = "L'identifiant du proposant est obligatoire")
private String proposantId;
/** Nom complet du proposant */
private String proposantNom;
/** Identifiant de l'organisation du proposant */
@NotBlank(message = "L'identifiant de l'organisation est obligatoire")
private String organisationId;
/** Identifiant de la demande d'aide liée (si proposition spécifique) */
private String demandeAideId;
// === STATUT ET DISPONIBILITÉ ===
/** Statut de la proposition */
@NotNull(message = "Le statut est obligatoire")
@Builder.Default
private StatutProposition statut = StatutProposition.ACTIVE;
/** Indique si la proposition est disponible */
@Builder.Default private Boolean estDisponible = true;
/** Indique si la proposition est récurrente */
@Builder.Default private Boolean estRecurrente = false;
/** Fréquence de récurrence (si applicable) */
private String frequenceRecurrence;
// === DATES ET DÉLAIS ===
/** Date de création de la proposition */
@NotNull(message = "La date de création est obligatoire")
@Builder.Default
private LocalDateTime dateCreation = LocalDateTime.now();
/** Date d'expiration de la proposition */
private LocalDateTime dateExpiration;
/** Date de dernière modification */
@Builder.Default private LocalDateTime dateModification = LocalDateTime.now();
/** Délai de réponse souhaité en heures */
@Min(value = 1, message = "Le délai de réponse doit être au moins 1 heure")
@Max(value = 8760, message = "Le délai de réponse ne peut pas dépasser 1 an")
@Builder.Default
private Integer delaiReponseHeures = 72;
// === CRITÈRES ET PRÉFÉRENCES ===
/** Critères de sélection des bénéficiaires */
private List<CritereSelectionDTO> criteresSelection;
/** Zones géographiques couvertes */
private List<String> zonesGeographiques;
/** Groupes cibles (âge, situation, etc.) */
private List<String> groupesCibles;
/** Compétences ou ressources disponibles */
private List<String> competencesRessources;
// === CONTACT ET DISPONIBILITÉ ===
/** Informations de contact préférées */
private ContactProposantDTO contactProposant;
/** Créneaux de disponibilité */
private List<CreneauDisponibiliteDTO> creneauxDisponibilite;
/** Mode de contact préféré */
private String modeContactPrefere;
// === HISTORIQUE ET SUIVI ===
/** Nombre de demandes traitées avec cette proposition */
@Builder.Default private Integer nombreDemandesTraitees = 0;
/** Nombre de bénéficiaires aidés */
@Builder.Default private Integer nombreBeneficiairesAides = 0;
/** Montant total versé */
@Builder.Default private Double montantTotalVerse = 0.0;
/** Note moyenne des bénéficiaires */
@DecimalMin(value = "0.0", message = "La note doit être positive")
@DecimalMax(value = "5.0", message = "La note ne peut pas dépasser 5")
private Double noteMoyenne;
/** Nombre d'évaluations reçues */
@Builder.Default private Integer nombreEvaluations = 0;
// === MÉTADONNÉES ===
/** Tags pour catégorisation */
private List<String> tags;
/** Données personnalisées */
private Map<String, Object> donneesPersonnalisees;
/** Indique si la proposition est mise en avant */
@Builder.Default private Boolean estMiseEnAvant = false;
/** Score de pertinence calculé automatiquement */
private Double scorePertinence;
/** Nombre de vues de la proposition */
@Builder.Default private Integer nombreVues = 0;
/** Nombre de candidatures reçues */
@Builder.Default private Integer nombreCandidatures = 0;
// === MÉTHODES UTILITAIRES ===
/** Vérifie si la proposition est active et disponible */
public boolean isActiveEtDisponible() {
return statut == StatutProposition.ACTIVE && estDisponible && !isExpiree();
}
/** Vérifie si la proposition est expirée */
public boolean isExpiree() {
return dateExpiration != null && LocalDateTime.now().isAfter(dateExpiration);
}
/** Vérifie si la proposition peut encore accepter des bénéficiaires */
public boolean peutAccepterBeneficiaires() {
return isActiveEtDisponible() && nombreBeneficiairesAides < nombreMaxBeneficiaires;
}
/** Calcule le pourcentage de capacité utilisée */
public double getPourcentageCapaciteUtilisee() {
if (nombreMaxBeneficiaires == 0) return 100.0;
return (nombreBeneficiairesAides * 100.0) / nombreMaxBeneficiaires;
}
/** Retourne le nombre de places restantes */
public int getPlacesRestantes() {
return Math.max(0, nombreMaxBeneficiaires - nombreBeneficiairesAides);
}
/** Vérifie si la proposition correspond à un type d'aide */
public boolean correspondAuType(TypeAide type) {
return typeAide == type
|| (typeAide.getCategorie().equals(type.getCategorie()) && typeAide != TypeAide.AUTRE);
}
/** Calcule le score de compatibilité avec une demande */
public double getScoreCompatibilite(DemandeAideDTO demande) {
double score = 0.0;
// Correspondance exacte du type
if (typeAide == demande.getTypeAide()) {
score += 50.0;
} else if (typeAide.getCategorie().equals(demande.getTypeAide().getCategorie())) {
score += 30.0;
}
/**
* Vérifie si la proposition est expirée
*/
public boolean isExpiree() {
return dateExpiration != null && LocalDateTime.now().isAfter(dateExpiration);
// Montant compatible
if (montantMaximum != null && demande.getMontantDemande() != null) {
if (demande.getMontantDemande().compareTo(montantMaximum) <= 0) {
score += 20.0;
} else {
score -= 10.0;
}
}
/**
* Vérifie si la proposition peut encore accepter des bénéficiaires
*/
public boolean peutAccepterBeneficiaires() {
return isActiveEtDisponible() && nombreBeneficiairesAides < nombreMaxBeneficiaires;
// Disponibilité
if (peutAccepterBeneficiaires()) {
score += 15.0;
}
/**
* Calcule le pourcentage de capacité utilisée
*/
public double getPourcentageCapaciteUtilisee() {
if (nombreMaxBeneficiaires == 0) return 100.0;
return (nombreBeneficiairesAides * 100.0) / nombreMaxBeneficiaires;
// Réputation
if (noteMoyenne != null && noteMoyenne >= 4.0) {
score += 10.0;
}
/**
* Retourne le nombre de places restantes
*/
public int getPlacesRestantes() {
return Math.max(0, nombreMaxBeneficiaires - nombreBeneficiairesAides);
// Récence
long joursDepuisCreation =
java.time.Duration.between(dateCreation, LocalDateTime.now()).toDays();
if (joursDepuisCreation <= 30) {
score += 5.0;
}
/**
* Vérifie si la proposition correspond à un type d'aide
*/
public boolean correspondAuType(TypeAide type) {
return typeAide == type ||
(typeAide.getCategorie().equals(type.getCategorie()) && typeAide != TypeAide.AUTRE);
return Math.min(100.0, Math.max(0.0, score));
}
/** Énumération des statuts de proposition */
public enum StatutProposition {
BROUILLON("Brouillon"),
ACTIVE("Active"),
SUSPENDUE("Suspendue"),
EXPIREE("Expirée"),
TERMINEE("Terminée"),
ANNULEE("Annulée");
private final String libelle;
StatutProposition(String libelle) {
this.libelle = libelle;
}
/**
* Calcule le score de compatibilité avec une demande
*/
public double getScoreCompatibilite(DemandeAideDTO demande) {
double score = 0.0;
// Correspondance exacte du type
if (typeAide == demande.getTypeAide()) {
score += 50.0;
} else if (typeAide.getCategorie().equals(demande.getTypeAide().getCategorie())) {
score += 30.0;
}
// Montant compatible
if (montantMaximum != null && demande.getMontantDemande() != null) {
if (demande.getMontantDemande() <= montantMaximum) {
score += 20.0;
} else {
score -= 10.0;
}
}
// Disponibilité
if (peutAccepterBeneficiaires()) {
score += 15.0;
}
// Réputation
if (noteMoyenne != null && noteMoyenne >= 4.0) {
score += 10.0;
}
// Récence
long joursDepuisCreation = java.time.Duration.between(dateCreation, LocalDateTime.now()).toDays();
if (joursDepuisCreation <= 30) {
score += 5.0;
}
return Math.min(100.0, Math.max(0.0, score));
}
/**
* Énumération des statuts de proposition
*/
public enum StatutProposition {
BROUILLON("Brouillon"),
ACTIVE("Active"),
SUSPENDUE("Suspendue"),
EXPIREE("Expirée"),
TERMINEE("Terminée"),
ANNULEE("Annulée");
private final String libelle;
StatutProposition(String libelle) {
this.libelle = libelle;
}
public String getLibelle() {
return libelle;
}
public String getLibelle() {
return libelle;
}
}
}

View File

@@ -1,849 +0,0 @@
package dev.lions.unionflow.server.api.dto.solidarite.aide;
import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* DTO pour la gestion des demandes d'aide et de solidarité Représente les demandes d'assistance
* mutuelle entre membres
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-10
*/
public class AideDTO extends BaseDTO {
private static final long serialVersionUID = 1L;
/** Numéro de référence unique de la demande */
@NotBlank(message = "Le numéro de référence est obligatoire")
@Pattern(
regexp = "^AIDE-\\d{4}-[A-Z0-9]{6}$",
message = "Format de référence invalide (AIDE-YYYY-XXXXXX)")
private String numeroReference;
/** Identifiant du membre demandeur */
@NotNull(message = "L'identifiant du demandeur est obligatoire")
private UUID membreDemandeurId;
/** Nom complet du membre demandeur */
private String nomDemandeur;
/** Numéro de membre du demandeur */
private String numeroMembreDemandeur;
/** Identifiant de l'association */
@NotNull(message = "L'identifiant de l'association est obligatoire")
private UUID associationId;
/** Nom de l'association */
private String nomAssociation;
/**
* Type d'aide demandée FINANCIERE, MATERIELLE, MEDICALE, JURIDIQUE, LOGEMENT, EDUCATION, AUTRE
*/
@NotBlank(message = "Le type d'aide est obligatoire")
@Pattern(
regexp = "^(FINANCIERE|MATERIELLE|MEDICALE|JURIDIQUE|LOGEMENT|EDUCATION|AUTRE)$",
message =
"Le type d'aide doit être FINANCIERE, MATERIELLE, MEDICALE, JURIDIQUE, LOGEMENT,"
+ " EDUCATION ou AUTRE")
private String typeAide;
/** Titre de la demande d'aide */
@NotBlank(message = "Le titre est obligatoire")
@Size(min = 5, max = 200, message = "Le titre doit contenir entre 5 et 200 caractères")
private String titre;
/** Description détaillée de la demande */
@NotBlank(message = "La description est obligatoire")
@Size(min = 20, max = 2000, message = "La description doit contenir entre 20 et 2000 caractères")
private String description;
/** Montant demandé (pour les aides financières) */
@DecimalMin(value = "0.0", inclusive = false, message = "Le montant demandé doit être positif")
@Digits(
integer = 10,
fraction = 2,
message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales")
private BigDecimal montantDemande;
/** Devise du montant */
@Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
private String devise = "XOF";
/**
* Statut de la demande EN_ATTENTE, EN_COURS_EVALUATION, APPROUVEE, REJETEE, EN_COURS_AIDE,
* TERMINEE, ANNULEE
*/
@NotBlank(message = "Le statut est obligatoire")
@Pattern(
regexp =
"^(EN_ATTENTE|EN_COURS_EVALUATION|APPROUVEE|REJETEE|EN_COURS_AIDE|TERMINEE|ANNULEE)$",
message = "Statut invalide")
private String statut;
/** Priorité de la demande BASSE, NORMALE, HAUTE, URGENTE */
@Pattern(
regexp = "^(BASSE|NORMALE|HAUTE|URGENTE)$",
message = "La priorité doit être BASSE, NORMALE, HAUTE ou URGENTE")
private String priorite;
/** Date limite pour l'aide */
@Future(message = "La date limite doit être dans le futur")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateLimite;
/** Justificatifs fournis */
private Boolean justificatifsFournis;
/** Liste des documents joints (noms de fichiers) */
@Size(max = 1000, message = "La liste des documents ne peut pas dépasser 1000 caractères")
private String documentsJoints;
/** Identifiant du membre évaluateur */
private UUID membreEvaluateurId;
/** Nom de l'évaluateur */
private String nomEvaluateur;
/** Date d'évaluation */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateEvaluation;
/** Commentaires de l'évaluateur */
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
private String commentairesEvaluateur;
/** Montant approuvé (peut être différent du montant demandé) */
@DecimalMin(value = "0.0", message = "Le montant approuvé doit être positif")
@Digits(
integer = 10,
fraction = 2,
message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales")
private BigDecimal montantApprouve;
/** Date d'approbation */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateApprobation;
/** Identifiant du membre qui fournit l'aide */
private UUID membreAidantId;
/** Nom du membre aidant */
private String nomAidant;
/** Date de début de l'aide */
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateDebutAide;
/** Date de fin de l'aide */
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateFinAide;
/** Montant effectivement versé */
@DecimalMin(value = "0.0", message = "Le montant versé doit être positif")
@Digits(
integer = 10,
fraction = 2,
message = "Le montant ne peut avoir plus de 10 chiffres entiers et 2 décimales")
private BigDecimal montantVerse;
/** Mode de versement */
@Pattern(
regexp = "^(WAVE_MONEY|ORANGE_MONEY|FREE_MONEY|VIREMENT|CHEQUE|ESPECES|NATURE)$",
message = "Mode de versement invalide")
private String modeVersement;
/** Numéro de transaction (pour les paiements mobiles) */
@Size(max = 50, message = "Le numéro de transaction ne peut pas dépasser 50 caractères")
private String numeroTransaction;
/** Date de versement */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateVersement;
/** Commentaires du bénéficiaire */
@Size(max = 1000, message = "Les commentaires ne peuvent pas dépasser 1000 caractères")
private String commentairesBeneficiaire;
/** Note de satisfaction (1-5) */
private Integer noteSatisfaction;
/** Aide publique (visible par tous les membres) */
private Boolean aidePublique;
/** Aide anonyme (demandeur anonyme) */
private Boolean aideAnonyme;
/** Nombre de vues de la demande */
private Integer nombreVues;
/** Raison du rejet (si applicable) */
@Size(max = 500, message = "La raison du rejet ne peut pas dépasser 500 caractères")
private String raisonRejet;
/** Date de rejet */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateRejet;
/** Identifiant de celui qui a rejeté */
private UUID rejeteParId;
/** Nom de celui qui a rejeté */
private String rejetePar;
// Constructeurs
public AideDTO() {
super();
this.statut = "EN_ATTENTE";
this.priorite = "NORMALE";
this.devise = "XOF";
this.justificatifsFournis = false;
this.aidePublique = true;
this.aideAnonyme = false;
this.nombreVues = 0;
this.numeroReference = genererNumeroReference();
}
public AideDTO(UUID membreDemandeurId, UUID associationId, String typeAide, String titre) {
this();
this.membreDemandeurId = membreDemandeurId;
this.associationId = associationId;
this.typeAide = typeAide;
this.titre = titre;
}
// Getters et Setters
public String getNumeroReference() {
return numeroReference;
}
public void setNumeroReference(String numeroReference) {
this.numeroReference = numeroReference;
}
public UUID getMembreDemandeurId() {
return membreDemandeurId;
}
public void setMembreDemandeurId(UUID membreDemandeurId) {
this.membreDemandeurId = membreDemandeurId;
}
public String getNomDemandeur() {
return nomDemandeur;
}
public void setNomDemandeur(String nomDemandeur) {
this.nomDemandeur = nomDemandeur;
}
public String getNumeroMembreDemandeur() {
return numeroMembreDemandeur;
}
public void setNumeroMembreDemandeur(String numeroMembreDemandeur) {
this.numeroMembreDemandeur = numeroMembreDemandeur;
}
public UUID getAssociationId() {
return associationId;
}
public void setAssociationId(UUID associationId) {
this.associationId = associationId;
}
public String getNomAssociation() {
return nomAssociation;
}
public void setNomAssociation(String nomAssociation) {
this.nomAssociation = nomAssociation;
}
public String getTypeAide() {
return typeAide;
}
public void setTypeAide(String typeAide) {
this.typeAide = typeAide;
}
public String getTitre() {
return titre;
}
public void setTitre(String titre) {
this.titre = titre;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public BigDecimal getMontantDemande() {
return montantDemande;
}
public void setMontantDemande(BigDecimal montantDemande) {
this.montantDemande = montantDemande;
}
public String getDevise() {
return devise;
}
public void setDevise(String devise) {
this.devise = devise;
}
public String getStatut() {
return statut;
}
public void setStatut(String statut) {
this.statut = statut;
}
public String getPriorite() {
return priorite;
}
public void setPriorite(String priorite) {
this.priorite = priorite;
}
public LocalDate getDateLimite() {
return dateLimite;
}
public void setDateLimite(LocalDate dateLimite) {
this.dateLimite = dateLimite;
}
public Boolean getJustificatifsFournis() {
return justificatifsFournis;
}
public void setJustificatifsFournis(Boolean justificatifsFournis) {
this.justificatifsFournis = justificatifsFournis;
}
public String getDocumentsJoints() {
return documentsJoints;
}
public void setDocumentsJoints(String documentsJoints) {
this.documentsJoints = documentsJoints;
}
// Getters et setters restants (suite)
public UUID getMembreEvaluateurId() {
return membreEvaluateurId;
}
public void setMembreEvaluateurId(UUID membreEvaluateurId) {
this.membreEvaluateurId = membreEvaluateurId;
}
public String getNomEvaluateur() {
return nomEvaluateur;
}
public void setNomEvaluateur(String nomEvaluateur) {
this.nomEvaluateur = nomEvaluateur;
}
public LocalDateTime getDateEvaluation() {
return dateEvaluation;
}
public void setDateEvaluation(LocalDateTime dateEvaluation) {
this.dateEvaluation = dateEvaluation;
}
public String getCommentairesEvaluateur() {
return commentairesEvaluateur;
}
public void setCommentairesEvaluateur(String commentairesEvaluateur) {
this.commentairesEvaluateur = commentairesEvaluateur;
}
public BigDecimal getMontantApprouve() {
return montantApprouve;
}
public void setMontantApprouve(BigDecimal montantApprouve) {
this.montantApprouve = montantApprouve;
}
public LocalDateTime getDateApprobation() {
return dateApprobation;
}
public void setDateApprobation(LocalDateTime dateApprobation) {
this.dateApprobation = dateApprobation;
}
public UUID getMembreAidantId() {
return membreAidantId;
}
public void setMembreAidantId(UUID membreAidantId) {
this.membreAidantId = membreAidantId;
}
public String getNomAidant() {
return nomAidant;
}
public void setNomAidant(String nomAidant) {
this.nomAidant = nomAidant;
}
public LocalDate getDateDebutAide() {
return dateDebutAide;
}
public void setDateDebutAide(LocalDate dateDebutAide) {
this.dateDebutAide = dateDebutAide;
}
public LocalDate getDateFinAide() {
return dateFinAide;
}
public void setDateFinAide(LocalDate dateFinAide) {
this.dateFinAide = dateFinAide;
}
public BigDecimal getMontantVerse() {
return montantVerse;
}
public void setMontantVerse(BigDecimal montantVerse) {
this.montantVerse = montantVerse;
}
public String getModeVersement() {
return modeVersement;
}
public void setModeVersement(String modeVersement) {
this.modeVersement = modeVersement;
}
public String getNumeroTransaction() {
return numeroTransaction;
}
public void setNumeroTransaction(String numeroTransaction) {
this.numeroTransaction = numeroTransaction;
}
public LocalDateTime getDateVersement() {
return dateVersement;
}
public void setDateVersement(LocalDateTime dateVersement) {
this.dateVersement = dateVersement;
}
public String getCommentairesBeneficiaire() {
return commentairesBeneficiaire;
}
public void setCommentairesBeneficiaire(String commentairesBeneficiaire) {
this.commentairesBeneficiaire = commentairesBeneficiaire;
}
public Integer getNoteSatisfaction() {
return noteSatisfaction;
}
public void setNoteSatisfaction(Integer noteSatisfaction) {
this.noteSatisfaction = noteSatisfaction;
}
public Boolean getAidePublique() {
return aidePublique;
}
public void setAidePublique(Boolean aidePublique) {
this.aidePublique = aidePublique;
}
public Boolean getAideAnonyme() {
return aideAnonyme;
}
public void setAideAnonyme(Boolean aideAnonyme) {
this.aideAnonyme = aideAnonyme;
}
public Integer getNombreVues() {
return nombreVues;
}
public void setNombreVues(Integer nombreVues) {
this.nombreVues = nombreVues;
}
public String getRaisonRejet() {
return raisonRejet;
}
public void setRaisonRejet(String raisonRejet) {
this.raisonRejet = raisonRejet;
}
public LocalDateTime getDateRejet() {
return dateRejet;
}
public void setDateRejet(LocalDateTime dateRejet) {
this.dateRejet = dateRejet;
}
public UUID getRejeteParId() {
return rejeteParId;
}
public void setRejeteParId(UUID rejeteParId) {
this.rejeteParId = rejeteParId;
}
public String getRejetePar() {
return rejetePar;
}
public void setRejetePar(String rejetePar) {
this.rejetePar = rejetePar;
}
// Méthodes utilitaires
/**
* Vérifie si la demande est en attente
*
* @return true si la demande est en attente
*/
public boolean isEnAttente() {
return "EN_ATTENTE".equals(statut);
}
/**
* Vérifie si la demande est en cours d'évaluation
*
* @return true si la demande est en cours d'évaluation
*/
public boolean isEnCoursEvaluation() {
return "EN_COURS_EVALUATION".equals(statut);
}
/**
* Vérifie si la demande est approuvée
*
* @return true si la demande est approuvée
*/
public boolean isApprouvee() {
return "APPROUVEE".equals(statut);
}
/**
* Vérifie si la demande est rejetée
*
* @return true si la demande est rejetée
*/
public boolean isRejetee() {
return "REJETEE".equals(statut);
}
/**
* Vérifie si l'aide est en cours
*
* @return true si l'aide est en cours
*/
public boolean isEnCoursAide() {
return "EN_COURS_AIDE".equals(statut);
}
/**
* Vérifie si l'aide est terminée
*
* @return true si l'aide est terminée
*/
public boolean isTerminee() {
return "TERMINEE".equals(statut);
}
/**
* Vérifie si la demande est annulée
*
* @return true si la demande est annulée
*/
public boolean isAnnulee() {
return "ANNULEE".equals(statut);
}
/**
* Vérifie si la demande est urgente
*
* @return true si la priorité est urgente
*/
public boolean isUrgente() {
return "URGENTE".equals(priorite);
}
/**
* Vérifie si la date limite est dépassée
*
* @return true si la date limite est dépassée
*/
public boolean isDateLimiteDepassee() {
return dateLimite != null && LocalDate.now().isAfter(dateLimite);
}
/**
* Calcule le nombre de jours restants avant la date limite
*
* @return Le nombre de jours restants, ou 0 si dépassé
*/
public long getJoursRestants() {
if (dateLimite == null) return 0;
LocalDate aujourd = LocalDate.now();
return aujourd.isBefore(dateLimite) ? aujourd.until(dateLimite).getDays() : 0;
}
/**
* Vérifie si l'aide concerne un montant financier
*
* @return true si c'est une aide financière
*/
public boolean isAideFinanciere() {
return "FINANCIERE".equals(typeAide) && montantDemande != null;
}
/**
* Calcule l'écart entre le montant demandé et approuvé
*
* @return La différence (positif = réduction, négatif = augmentation)
*/
public BigDecimal getEcartMontant() {
if (montantDemande == null || montantApprouve == null) {
return BigDecimal.ZERO;
}
return montantDemande.subtract(montantApprouve);
}
/**
* Calcule le pourcentage d'approbation du montant
*
* @return Le pourcentage du montant approuvé par rapport au demandé
*/
public int getPourcentageApprobation() {
if (montantDemande == null
|| montantApprouve == null
|| montantDemande.compareTo(BigDecimal.ZERO) == 0) {
return 0;
}
return montantApprouve
.multiply(BigDecimal.valueOf(100))
.divide(montantDemande, 0, java.math.RoundingMode.HALF_UP)
.intValue();
}
/**
* Retourne le libellé du type d'aide
*
* @return Le libellé du type d'aide
*/
public String getTypeAideLibelle() {
if (typeAide == null) return "Non défini";
return switch (typeAide) {
case "FINANCIERE" -> "Aide Financière";
case "MATERIELLE" -> "Aide Matérielle";
case "MEDICALE" -> "Aide Médicale";
case "JURIDIQUE" -> "Aide Juridique";
case "LOGEMENT" -> "Aide au Logement";
case "EDUCATION" -> "Aide à l'Éducation";
case "AUTRE" -> "Autre";
default -> typeAide;
};
}
/**
* Retourne le libellé du statut
*
* @return Le libellé du statut
*/
public String getStatutLibelle() {
if (statut == null) return "Non défini";
return switch (statut) {
case "EN_ATTENTE" -> "En Attente";
case "EN_COURS_EVALUATION" -> "En Cours d'Évaluation";
case "APPROUVEE" -> "Approuvée";
case "REJETEE" -> "Rejetée";
case "EN_COURS_AIDE" -> "En Cours d'Aide";
case "TERMINEE" -> "Terminée";
case "ANNULEE" -> "Annulée";
default -> statut;
};
}
/**
* Retourne le libellé de la priorité
*
* @return Le libellé de la priorité
*/
public String getPrioriteLibelle() {
if (priorite == null) return "Normale";
return switch (priorite) {
case "BASSE" -> "Basse";
case "NORMALE" -> "Normale";
case "HAUTE" -> "Haute";
case "URGENTE" -> "Urgente";
default -> priorite;
};
}
/**
* Approuve la demande d'aide
*
* @param evaluateurId ID de l'évaluateur
* @param nomEvaluateur Nom de l'évaluateur
* @param montantApprouve Montant approuvé
* @param commentaires Commentaires de l'évaluateur
*/
public void approuver(
UUID evaluateurId, String nomEvaluateur, BigDecimal montantApprouve, String commentaires) {
this.statut = "APPROUVEE";
this.membreEvaluateurId = evaluateurId;
this.nomEvaluateur = nomEvaluateur;
this.montantApprouve = montantApprouve;
this.commentairesEvaluateur = commentaires;
this.dateEvaluation = LocalDateTime.now();
this.dateApprobation = LocalDateTime.now();
marquerCommeModifie(nomEvaluateur);
}
/**
* Rejette la demande d'aide
*
* @param evaluateurId ID de l'évaluateur
* @param nomEvaluateur Nom de l'évaluateur
* @param raison Raison du rejet
*/
public void rejeter(UUID evaluateurId, String nomEvaluateur, String raison) {
this.statut = "REJETEE";
this.rejeteParId = evaluateurId;
this.rejetePar = nomEvaluateur;
this.raisonRejet = raison;
this.dateRejet = LocalDateTime.now();
this.dateEvaluation = LocalDateTime.now();
marquerCommeModifie(nomEvaluateur);
}
/**
* Démarre l'aide
*
* @param aidantId ID du membre aidant
* @param nomAidant Nom du membre aidant
*/
public void demarrerAide(UUID aidantId, String nomAidant) {
this.statut = "EN_COURS_AIDE";
this.membreAidantId = aidantId;
this.nomAidant = nomAidant;
this.dateDebutAide = LocalDate.now();
marquerCommeModifie(nomAidant);
}
/**
* Termine l'aide avec versement
*
* @param montantVerse Montant effectivement versé
* @param modeVersement Mode de versement
* @param numeroTransaction Numéro de transaction
*/
public void terminerAvecVersement(
BigDecimal montantVerse, String modeVersement, String numeroTransaction) {
this.statut = "TERMINEE";
this.montantVerse = montantVerse;
this.modeVersement = modeVersement;
this.numeroTransaction = numeroTransaction;
this.dateVersement = LocalDateTime.now();
this.dateFinAide = LocalDate.now();
marquerCommeModifie("SYSTEM");
}
/** Incrémente le nombre de vues */
public void incrementerVues() {
if (nombreVues == null) {
nombreVues = 1;
} else {
nombreVues++;
}
}
/**
* Génère un numéro de référence unique
*
* @return Le numéro de référence généré
*/
private String genererNumeroReference() {
return "AIDE-"
+ LocalDate.now().getYear()
+ "-"
+ String.format("%06d", (int) (Math.random() * 1000000));
}
@Override
public String toString() {
return "AideDTO{"
+ "numeroReference='"
+ numeroReference
+ '\''
+ ", typeAide='"
+ typeAide
+ '\''
+ ", titre='"
+ titre
+ '\''
+ ", statut='"
+ statut
+ '\''
+ ", priorite='"
+ priorite
+ '\''
+ ", montantDemande="
+ montantDemande
+ ", montantApprouve="
+ montantApprouve
+ ", devise='"
+ devise
+ '\''
+ "} "
+ super.toString();
}
}

View File

@@ -2,232 +2,256 @@ package dev.lions.unionflow.server.api.enums.analytics;
/**
* Énumération des formats d'export disponibles pour les rapports et données analytics
*
* Cette énumération définit les différents formats dans lesquels les données
* peuvent être exportées depuis l'application UnionFlow.
*
*
* <p>Cette énumération définit les différents formats dans lesquels les données peuvent être
* exportées depuis l'application UnionFlow.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
public enum FormatExport {
// === FORMATS DOCUMENTS ===
PDF("PDF", "pdf", "application/pdf", "Portable Document Format", true, true),
WORD("Word", "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Microsoft Word", true, false),
// === FORMATS TABLEURS ===
EXCEL("Excel", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Microsoft Excel", true, true),
CSV("CSV", "csv", "text/csv", "Comma Separated Values", false, true),
// === FORMATS DONNÉES ===
JSON("JSON", "json", "application/json", "JavaScript Object Notation", false, true),
XML("XML", "xml", "application/xml", "eXtensible Markup Language", false, false),
// === FORMATS IMAGES ===
PNG("PNG", "png", "image/png", "Portable Network Graphics", true, false),
JPEG("JPEG", "jpg", "image/jpeg", "Joint Photographic Experts Group", true, false),
SVG("SVG", "svg", "image/svg+xml", "Scalable Vector Graphics", true, false),
// === FORMATS SPÉCIALISÉS ===
POWERPOINT("PowerPoint", "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "Microsoft PowerPoint", true, false),
HTML("HTML", "html", "text/html", "HyperText Markup Language", true, false);
private final String libelle;
private final String extension;
private final String mimeType;
private final String description;
private final boolean supporteGraphiques;
private final boolean supporteGrandesQuantitesDonnees;
/**
* Constructeur de l'énumération FormatExport
*
* @param libelle Le libellé affiché à l'utilisateur
* @param extension L'extension de fichier
* @param mimeType Le type MIME du format
* @param description La description du format
* @param supporteGraphiques true si le format supporte les graphiques
* @param supporteGrandesQuantitesDonnees true si le format supporte de grandes quantités de données
*/
FormatExport(String libelle, String extension, String mimeType, String description,
boolean supporteGraphiques, boolean supporteGrandesQuantitesDonnees) {
this.libelle = libelle;
this.extension = extension;
this.mimeType = mimeType;
this.description = description;
this.supporteGraphiques = supporteGraphiques;
this.supporteGrandesQuantitesDonnees = supporteGrandesQuantitesDonnees;
}
/**
* Retourne le libellé du format
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne l'extension de fichier
*
* @return L'extension sans le point (ex: "pdf", "xlsx")
*/
public String getExtension() {
return extension;
}
/**
* Retourne le type MIME du format
*
* @return Le type MIME complet
*/
public String getMimeType() {
return mimeType;
}
/**
* Retourne la description du format
*
* @return La description complète du format
*/
public String getDescription() {
return description;
}
/**
* Vérifie si le format supporte les graphiques
*
* @return true si le format peut inclure des graphiques
*/
public boolean supporteGraphiques() {
return supporteGraphiques;
}
/**
* Vérifie si le format supporte de grandes quantités de données
*
* @return true si le format peut gérer de gros volumes de données
*/
public boolean supporteGrandesQuantitesDonnees() {
return supporteGrandesQuantitesDonnees;
}
/**
* Vérifie si le format est adapté aux rapports exécutifs
*
* @return true si le format convient aux rapports de direction
*/
public boolean isFormatExecutif() {
return this == PDF || this == POWERPOINT || this == WORD;
}
/**
* Vérifie si le format est adapté à l'analyse de données
*
* @return true si le format convient à l'analyse de données
*/
public boolean isFormatAnalyse() {
return this == EXCEL || this == CSV || this == JSON;
}
/**
* Vérifie si le format est adapté au partage web
*
* @return true si le format convient au partage sur le web
*/
public boolean isFormatWeb() {
return this == HTML || this == PNG || this == SVG || this == JSON;
}
/**
* Retourne l'icône appropriée pour le format
*
* @return L'icône Material Design
*/
public String getIcone() {
return switch (this) {
case PDF -> "picture_as_pdf";
case WORD -> "description";
case EXCEL -> "table_chart";
case CSV -> "grid_on";
case JSON -> "code";
case XML -> "code";
case PNG, JPEG -> "image";
case SVG -> "vector_image";
case POWERPOINT -> "slideshow";
case HTML -> "web";
};
}
/**
* Retourne la couleur appropriée pour le format
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return switch (this) {
case PDF -> "#FF5722"; // Rouge-orange
case WORD -> "#2196F3"; // Bleu
case EXCEL -> "#4CAF50"; // Vert
case CSV -> "#607D8B"; // Bleu gris
case JSON -> "#FF9800"; // Orange
case XML -> "#795548"; // Marron
case PNG, JPEG -> "#E91E63"; // Rose
case SVG -> "#9C27B0"; // Violet
case POWERPOINT -> "#FF5722"; // Rouge-orange
case HTML -> "#00BCD4"; // Cyan
};
}
/**
* Génère un nom de fichier avec l'extension appropriée
*
* @param nomBase Le nom de base du fichier
* @return Le nom de fichier complet avec extension
*/
public String genererNomFichier(String nomBase) {
return nomBase + "." + extension;
}
/**
* Retourne la taille maximale recommandée pour ce format (en MB)
*
* @return La taille maximale en mégaoctets
*/
public int getTailleMaximaleRecommandee() {
return switch (this) {
case PDF, WORD, POWERPOINT -> 50; // 50 MB pour les documents
case EXCEL -> 100; // 100 MB pour Excel
case CSV, JSON, XML -> 200; // 200 MB pour les données
case PNG, JPEG -> 10; // 10 MB pour les images
case SVG, HTML -> 5; // 5 MB pour les formats légers
};
}
/**
* Vérifie si le format nécessite un traitement spécial
*
* @return true si le format nécessite un traitement particulier
*/
public boolean necessiteTraitementSpecial() {
return this == PDF || this == EXCEL || this == POWERPOINT || this == WORD;
}
/**
* Retourne les formats recommandés pour un type de rapport donné
*
* @param typeRapport Le type de rapport (executif, analytique, technique)
* @return Un tableau des formats recommandés
*/
public static FormatExport[] getFormatsRecommandes(String typeRapport) {
return switch (typeRapport.toLowerCase()) {
case "executif" -> new FormatExport[]{PDF, POWERPOINT, WORD};
case "analytique" -> new FormatExport[]{EXCEL, CSV, JSON, PDF};
case "technique" -> new FormatExport[]{JSON, XML, CSV, HTML};
case "partage" -> new FormatExport[]{PDF, PNG, HTML};
default -> new FormatExport[]{PDF, EXCEL, CSV};
};
}
// === FORMATS DOCUMENTS ===
PDF("PDF", "pdf", "application/pdf", "Portable Document Format", true, true),
WORD(
"Word",
"docx",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"Microsoft Word",
true,
false),
// === FORMATS TABLEURS ===
EXCEL(
"Excel",
"xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Microsoft Excel",
true,
true),
CSV("CSV", "csv", "text/csv", "Comma Separated Values", false, true),
// === FORMATS DONNÉES ===
JSON("JSON", "json", "application/json", "JavaScript Object Notation", false, true),
XML("XML", "xml", "application/xml", "eXtensible Markup Language", false, false),
// === FORMATS IMAGES ===
PNG("PNG", "png", "image/png", "Portable Network Graphics", true, false),
JPEG("JPEG", "jpg", "image/jpeg", "Joint Photographic Experts Group", true, false),
SVG("SVG", "svg", "image/svg+xml", "Scalable Vector Graphics", true, false),
// === FORMATS SPÉCIALISÉS ===
POWERPOINT(
"PowerPoint",
"pptx",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"Microsoft PowerPoint",
true,
false),
HTML("HTML", "html", "text/html", "HyperText Markup Language", true, false);
private final String libelle;
private final String extension;
private final String mimeType;
private final String description;
private final boolean supporteGraphiques;
private final boolean supporteGrandesQuantitesDonnees;
/**
* Constructeur de l'énumération FormatExport
*
* @param libelle Le libellé affiché à l'utilisateur
* @param extension L'extension de fichier
* @param mimeType Le type MIME du format
* @param description La description du format
* @param supporteGraphiques true si le format supporte les graphiques
* @param supporteGrandesQuantitesDonnees true si le format supporte de grandes quantités de
* données
*/
FormatExport(
String libelle,
String extension,
String mimeType,
String description,
boolean supporteGraphiques,
boolean supporteGrandesQuantitesDonnees) {
this.libelle = libelle;
this.extension = extension;
this.mimeType = mimeType;
this.description = description;
this.supporteGraphiques = supporteGraphiques;
this.supporteGrandesQuantitesDonnees = supporteGrandesQuantitesDonnees;
}
/**
* Retourne le libellé du format
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne l'extension de fichier
*
* @return L'extension sans le point (ex: "pdf", "xlsx")
*/
public String getExtension() {
return extension;
}
/**
* Retourne le type MIME du format
*
* @return Le type MIME complet
*/
public String getMimeType() {
return mimeType;
}
/**
* Retourne la description du format
*
* @return La description complète du format
*/
public String getDescription() {
return description;
}
/**
* Vérifie si le format supporte les graphiques
*
* @return true si le format peut inclure des graphiques
*/
public boolean supporteGraphiques() {
return supporteGraphiques;
}
/**
* Vérifie si le format supporte de grandes quantités de données
*
* @return true si le format peut gérer de gros volumes de données
*/
public boolean supporteGrandesQuantitesDonnees() {
return supporteGrandesQuantitesDonnees;
}
/**
* Vérifie si le format est adapté aux rapports exécutifs
*
* @return true si le format convient aux rapports de direction
*/
public boolean isFormatExecutif() {
return this == PDF || this == POWERPOINT || this == WORD;
}
/**
* Vérifie si le format est adapté à l'analyse de données
*
* @return true si le format convient à l'analyse de données
*/
public boolean isFormatAnalyse() {
return this == EXCEL || this == CSV || this == JSON;
}
/**
* Vérifie si le format est adapté au partage web
*
* @return true si le format convient au partage sur le web
*/
public boolean isFormatWeb() {
return this == HTML || this == PNG || this == SVG || this == JSON;
}
/**
* Retourne l'icône appropriée pour le format
*
* @return L'icône Material Design
*/
public String getIcone() {
return switch (this) {
case PDF -> "picture_as_pdf";
case WORD -> "description";
case EXCEL -> "table_chart";
case CSV -> "grid_on";
case JSON -> "code";
case XML -> "code";
case PNG, JPEG -> "image";
case SVG -> "vector_image";
case POWERPOINT -> "slideshow";
case HTML -> "web";
};
}
/**
* Retourne la couleur appropriée pour le format
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return switch (this) {
case PDF -> "#FF5722"; // Rouge-orange
case WORD -> "#2196F3"; // Bleu
case EXCEL -> "#4CAF50"; // Vert
case CSV -> "#607D8B"; // Bleu gris
case JSON -> "#FF9800"; // Orange
case XML -> "#795548"; // Marron
case PNG, JPEG -> "#E91E63"; // Rose
case SVG -> "#9C27B0"; // Violet
case POWERPOINT -> "#FF5722"; // Rouge-orange
case HTML -> "#00BCD4"; // Cyan
};
}
/**
* Génère un nom de fichier avec l'extension appropriée
*
* @param nomBase Le nom de base du fichier
* @return Le nom de fichier complet avec extension
*/
public String genererNomFichier(String nomBase) {
return nomBase + "." + extension;
}
/**
* Retourne la taille maximale recommandée pour ce format (en MB)
*
* @return La taille maximale en mégaoctets
*/
public int getTailleMaximaleRecommandee() {
return switch (this) {
case PDF, WORD, POWERPOINT -> 50; // 50 MB pour les documents
case EXCEL -> 100; // 100 MB pour Excel
case CSV, JSON, XML -> 200; // 200 MB pour les données
case PNG, JPEG -> 10; // 10 MB pour les images
case SVG, HTML -> 5; // 5 MB pour les formats légers
};
}
/**
* Vérifie si le format nécessite un traitement spécial
*
* @return true si le format nécessite un traitement particulier
*/
public boolean necessiteTraitementSpecial() {
return this == PDF || this == EXCEL || this == POWERPOINT || this == WORD;
}
/**
* Retourne les formats recommandés pour un type de rapport donné
*
* @param typeRapport Le type de rapport (executif, analytique, technique)
* @return Un tableau des formats recommandés
*/
public static FormatExport[] getFormatsRecommandes(String typeRapport) {
return switch (typeRapport.toLowerCase()) {
case "executif" -> new FormatExport[] {PDF, POWERPOINT, WORD};
case "analytique" -> new FormatExport[] {EXCEL, CSV, JSON, PDF};
case "technique" -> new FormatExport[] {JSON, XML, CSV, HTML};
case "partage" -> new FormatExport[] {PDF, PNG, HTML};
default -> new FormatExport[] {PDF, EXCEL, CSV};
};
}
}

View File

@@ -5,203 +5,222 @@ import java.time.temporal.ChronoUnit;
/**
* Énumération des périodes d'analyse disponibles pour les métriques et rapports
*
* Cette énumération définit les différentes périodes temporelles qui peuvent être
* utilisées pour analyser les données et générer des rapports.
*
*
* <p>Cette énumération définit les différentes périodes temporelles qui peuvent être utilisées pour
* analyser les données et générer des rapports.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
public enum PeriodeAnalyse {
// === PÉRIODES COURTES ===
AUJOURD_HUI("Aujourd'hui", "today", 1, ChronoUnit.DAYS),
HIER("Hier", "yesterday", 1, ChronoUnit.DAYS),
CETTE_SEMAINE("Cette semaine", "this_week", 7, ChronoUnit.DAYS),
SEMAINE_DERNIERE("Semaine dernière", "last_week", 7, ChronoUnit.DAYS),
// === PÉRIODES MENSUELLES ===
CE_MOIS("Ce mois", "this_month", 1, ChronoUnit.MONTHS),
MOIS_DERNIER("Mois dernier", "last_month", 1, ChronoUnit.MONTHS),
TROIS_DERNIERS_MOIS("3 derniers mois", "last_3_months", 3, ChronoUnit.MONTHS),
SIX_DERNIERS_MOIS("6 derniers mois", "last_6_months", 6, ChronoUnit.MONTHS),
// === PÉRIODES ANNUELLES ===
CETTE_ANNEE("Cette année", "this_year", 1, ChronoUnit.YEARS),
ANNEE_DERNIERE("Année dernière", "last_year", 1, ChronoUnit.YEARS),
DEUX_DERNIERES_ANNEES("2 dernières années", "last_2_years", 2, ChronoUnit.YEARS),
// === PÉRIODES PERSONNALISÉES ===
SEPT_DERNIERS_JOURS("7 derniers jours", "last_7_days", 7, ChronoUnit.DAYS),
TRENTE_DERNIERS_JOURS("30 derniers jours", "last_30_days", 30, ChronoUnit.DAYS),
QUATRE_VINGT_DIX_DERNIERS_JOURS("90 derniers jours", "last_90_days", 90, ChronoUnit.DAYS),
// === PÉRIODES SPÉCIALES ===
DEPUIS_CREATION("Depuis la création", "since_creation", 0, ChronoUnit.FOREVER),
PERIODE_PERSONNALISEE("Période personnalisée", "custom", 0, ChronoUnit.DAYS);
private final String libelle;
private final String code;
private final int duree;
private final ChronoUnit unite;
/**
* Constructeur de l'énumération PeriodeAnalyse
*
* @param libelle Le libellé affiché à l'utilisateur
* @param code Le code technique de la période
* @param duree La durée de la période
* @param unite L'unité de temps (jours, mois, années)
*/
PeriodeAnalyse(String libelle, String code, int duree, ChronoUnit unite) {
this.libelle = libelle;
this.code = code;
this.duree = duree;
this.unite = unite;
}
/**
* Retourne le libellé de la période
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne le code technique de la période
*
* @return Le code technique
*/
public String getCode() {
return code;
}
/**
* Retourne la durée de la période
*
* @return La durée numérique
*/
public int getDuree() {
return duree;
}
/**
* Retourne l'unité de temps de la période
*
* @return L'unité de temps (ChronoUnit)
*/
public ChronoUnit getUnite() {
return unite;
}
/**
* Calcule la date de début pour cette période
*
* @return La date de début de la période
*/
public LocalDateTime getDateDebut() {
LocalDateTime maintenant = LocalDateTime.now();
return switch (this) {
case AUJOURD_HUI -> maintenant.toLocalDate().atStartOfDay();
case HIER -> maintenant.minusDays(1).toLocalDate().atStartOfDay();
case CETTE_SEMAINE -> maintenant.minusDays(maintenant.getDayOfWeek().getValue() - 1).toLocalDate().atStartOfDay();
case SEMAINE_DERNIERE -> maintenant.minusDays(maintenant.getDayOfWeek().getValue() + 6).toLocalDate().atStartOfDay();
case CE_MOIS -> maintenant.withDayOfMonth(1).toLocalDate().atStartOfDay();
case MOIS_DERNIER -> maintenant.minusMonths(1).withDayOfMonth(1).toLocalDate().atStartOfDay();
case CETTE_ANNEE -> maintenant.withDayOfYear(1).toLocalDate().atStartOfDay();
case ANNEE_DERNIERE -> maintenant.minusYears(1).withDayOfYear(1).toLocalDate().atStartOfDay();
case DEPUIS_CREATION -> LocalDateTime.of(2020, 1, 1, 0, 0); // Date de création d'UnionFlow
case PERIODE_PERSONNALISEE -> maintenant; // À définir par l'utilisateur
default -> maintenant.minus(duree, unite).toLocalDate().atStartOfDay();
};
}
/**
* Calcule la date de fin pour cette période
*
* @return La date de fin de la période
*/
public LocalDateTime getDateFin() {
LocalDateTime maintenant = LocalDateTime.now();
return switch (this) {
case AUJOURD_HUI -> maintenant.toLocalDate().atTime(23, 59, 59);
case HIER -> maintenant.minusDays(1).toLocalDate().atTime(23, 59, 59);
case CETTE_SEMAINE -> maintenant.toLocalDate().atTime(23, 59, 59);
case SEMAINE_DERNIERE -> maintenant.minusDays(maintenant.getDayOfWeek().getValue()).toLocalDate().atTime(23, 59, 59);
case CE_MOIS -> maintenant.toLocalDate().atTime(23, 59, 59);
case MOIS_DERNIER -> maintenant.withDayOfMonth(1).minusDays(1).toLocalDate().atTime(23, 59, 59);
case CETTE_ANNEE -> maintenant.toLocalDate().atTime(23, 59, 59);
case ANNEE_DERNIERE -> maintenant.withDayOfYear(1).minusDays(1).toLocalDate().atTime(23, 59, 59);
case DEPUIS_CREATION, PERIODE_PERSONNALISEE -> maintenant;
default -> maintenant.toLocalDate().atTime(23, 59, 59);
};
}
/**
* Vérifie si la période est une période courte (moins d'un mois)
*
* @return true si la période est courte
*/
public boolean isPeriodeCourte() {
return this == AUJOURD_HUI || this == HIER || this == CETTE_SEMAINE ||
this == SEMAINE_DERNIERE || this == SEPT_DERNIERS_JOURS;
}
/**
* Vérifie si la période est une période longue (plus d'un an)
*
* @return true si la période est longue
*/
public boolean isPeriodeLongue() {
return this == CETTE_ANNEE || this == ANNEE_DERNIERE ||
this == DEUX_DERNIERES_ANNEES || this == DEPUIS_CREATION;
}
/**
* Vérifie si la période est personnalisable
*
* @return true si la période peut être personnalisée
*/
public boolean isPersonnalisable() {
return this == PERIODE_PERSONNALISEE;
}
/**
* Retourne l'intervalle de regroupement recommandé pour cette période
*
* @return L'intervalle de regroupement (jour, semaine, mois)
*/
public String getIntervalleRegroupement() {
return switch (this) {
case AUJOURD_HUI, HIER -> "heure";
case CETTE_SEMAINE, SEMAINE_DERNIERE, SEPT_DERNIERS_JOURS -> "jour";
case CE_MOIS, MOIS_DERNIER, TRENTE_DERNIERS_JOURS -> "jour";
case TROIS_DERNIERS_MOIS, SIX_DERNIERS_MOIS, QUATRE_VINGT_DIX_DERNIERS_JOURS -> "semaine";
case CETTE_ANNEE, ANNEE_DERNIERE, DEUX_DERNIERES_ANNEES -> "mois";
case DEPUIS_CREATION -> "annee";
default -> "jour";
};
}
/**
* Retourne le format de date approprié pour cette période
*
* @return Le format de date (dd/MM, MM/yyyy, etc.)
*/
public String getFormatDate() {
return switch (this) {
case AUJOURD_HUI, HIER -> "HH:mm";
case CETTE_SEMAINE, SEMAINE_DERNIERE, SEPT_DERNIERS_JOURS -> "dd/MM";
case CE_MOIS, MOIS_DERNIER, TRENTE_DERNIERS_JOURS -> "dd/MM";
case TROIS_DERNIERS_MOIS, SIX_DERNIERS_MOIS, QUATRE_VINGT_DIX_DERNIERS_JOURS -> "dd/MM";
case CETTE_ANNEE, ANNEE_DERNIERE -> "MM/yyyy";
case DEUX_DERNIERES_ANNEES, DEPUIS_CREATION -> "yyyy";
default -> "dd/MM/yyyy";
};
}
// === PÉRIODES COURTES ===
AUJOURD_HUI("Aujourd'hui", "today", 1, ChronoUnit.DAYS),
HIER("Hier", "yesterday", 1, ChronoUnit.DAYS),
CETTE_SEMAINE("Cette semaine", "this_week", 7, ChronoUnit.DAYS),
SEMAINE_DERNIERE("Semaine dernière", "last_week", 7, ChronoUnit.DAYS),
// === PÉRIODES MENSUELLES ===
CE_MOIS("Ce mois", "this_month", 1, ChronoUnit.MONTHS),
MOIS_DERNIER("Mois dernier", "last_month", 1, ChronoUnit.MONTHS),
TROIS_DERNIERS_MOIS("3 derniers mois", "last_3_months", 3, ChronoUnit.MONTHS),
SIX_DERNIERS_MOIS("6 derniers mois", "last_6_months", 6, ChronoUnit.MONTHS),
// === PÉRIODES ANNUELLES ===
CETTE_ANNEE("Cette année", "this_year", 1, ChronoUnit.YEARS),
ANNEE_DERNIERE("Année dernière", "last_year", 1, ChronoUnit.YEARS),
DEUX_DERNIERES_ANNEES("2 dernières années", "last_2_years", 2, ChronoUnit.YEARS),
// === PÉRIODES PERSONNALISÉES ===
SEPT_DERNIERS_JOURS("7 derniers jours", "last_7_days", 7, ChronoUnit.DAYS),
TRENTE_DERNIERS_JOURS("30 derniers jours", "last_30_days", 30, ChronoUnit.DAYS),
QUATRE_VINGT_DIX_DERNIERS_JOURS("90 derniers jours", "last_90_days", 90, ChronoUnit.DAYS),
// === PÉRIODES SPÉCIALES ===
DEPUIS_CREATION("Depuis la création", "since_creation", 0, ChronoUnit.FOREVER),
PERIODE_PERSONNALISEE("Période personnalisée", "custom", 0, ChronoUnit.DAYS);
private final String libelle;
private final String code;
private final int duree;
private final ChronoUnit unite;
/**
* Constructeur de l'énumération PeriodeAnalyse
*
* @param libelle Le libellé affiché à l'utilisateur
* @param code Le code technique de la période
* @param duree La durée de la période
* @param unite L'unité de temps (jours, mois, années)
*/
PeriodeAnalyse(String libelle, String code, int duree, ChronoUnit unite) {
this.libelle = libelle;
this.code = code;
this.duree = duree;
this.unite = unite;
}
/**
* Retourne le libellé de la période
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne le code technique de la période
*
* @return Le code technique
*/
public String getCode() {
return code;
}
/**
* Retourne la durée de la période
*
* @return La durée numérique
*/
public int getDuree() {
return duree;
}
/**
* Retourne l'unité de temps de la période
*
* @return L'unité de temps (ChronoUnit)
*/
public ChronoUnit getUnite() {
return unite;
}
/**
* Calcule la date de début pour cette période
*
* @return La date de début de la période
*/
public LocalDateTime getDateDebut() {
LocalDateTime maintenant = LocalDateTime.now();
return switch (this) {
case AUJOURD_HUI -> maintenant.toLocalDate().atStartOfDay();
case HIER -> maintenant.minusDays(1).toLocalDate().atStartOfDay();
case CETTE_SEMAINE ->
maintenant
.minusDays(maintenant.getDayOfWeek().getValue() - 1)
.toLocalDate()
.atStartOfDay();
case SEMAINE_DERNIERE ->
maintenant
.minusDays(maintenant.getDayOfWeek().getValue() + 6)
.toLocalDate()
.atStartOfDay();
case CE_MOIS -> maintenant.withDayOfMonth(1).toLocalDate().atStartOfDay();
case MOIS_DERNIER -> maintenant.minusMonths(1).withDayOfMonth(1).toLocalDate().atStartOfDay();
case CETTE_ANNEE -> maintenant.withDayOfYear(1).toLocalDate().atStartOfDay();
case ANNEE_DERNIERE -> maintenant.minusYears(1).withDayOfYear(1).toLocalDate().atStartOfDay();
case DEPUIS_CREATION -> LocalDateTime.of(2020, 1, 1, 0, 0); // Date de création d'UnionFlow
case PERIODE_PERSONNALISEE -> maintenant; // À définir par l'utilisateur
default -> maintenant.minus(duree, unite).toLocalDate().atStartOfDay();
};
}
/**
* Calcule la date de fin pour cette période
*
* @return La date de fin de la période
*/
public LocalDateTime getDateFin() {
LocalDateTime maintenant = LocalDateTime.now();
return switch (this) {
case AUJOURD_HUI -> maintenant.toLocalDate().atTime(23, 59, 59);
case HIER -> maintenant.minusDays(1).toLocalDate().atTime(23, 59, 59);
case CETTE_SEMAINE -> maintenant.toLocalDate().atTime(23, 59, 59);
case SEMAINE_DERNIERE ->
maintenant
.minusDays(maintenant.getDayOfWeek().getValue())
.toLocalDate()
.atTime(23, 59, 59);
case CE_MOIS -> maintenant.toLocalDate().atTime(23, 59, 59);
case MOIS_DERNIER ->
maintenant.withDayOfMonth(1).minusDays(1).toLocalDate().atTime(23, 59, 59);
case CETTE_ANNEE -> maintenant.toLocalDate().atTime(23, 59, 59);
case ANNEE_DERNIERE ->
maintenant.withDayOfYear(1).minusDays(1).toLocalDate().atTime(23, 59, 59);
case DEPUIS_CREATION, PERIODE_PERSONNALISEE -> maintenant;
default -> maintenant.toLocalDate().atTime(23, 59, 59);
};
}
/**
* Vérifie si la période est une période courte (moins d'un mois)
*
* @return true si la période est courte
*/
public boolean isPeriodeCourte() {
return this == AUJOURD_HUI
|| this == HIER
|| this == CETTE_SEMAINE
|| this == SEMAINE_DERNIERE
|| this == SEPT_DERNIERS_JOURS;
}
/**
* Vérifie si la période est une période longue (plus d'un an)
*
* @return true si la période est longue
*/
public boolean isPeriodeLongue() {
return this == CETTE_ANNEE
|| this == ANNEE_DERNIERE
|| this == DEUX_DERNIERES_ANNEES
|| this == DEPUIS_CREATION;
}
/**
* Vérifie si la période est personnalisable
*
* @return true si la période peut être personnalisée
*/
public boolean isPersonnalisable() {
return this == PERIODE_PERSONNALISEE;
}
/**
* Retourne l'intervalle de regroupement recommandé pour cette période
*
* @return L'intervalle de regroupement (jour, semaine, mois)
*/
public String getIntervalleRegroupement() {
return switch (this) {
case AUJOURD_HUI, HIER -> "heure";
case CETTE_SEMAINE, SEMAINE_DERNIERE, SEPT_DERNIERS_JOURS -> "jour";
case CE_MOIS, MOIS_DERNIER, TRENTE_DERNIERS_JOURS -> "jour";
case TROIS_DERNIERS_MOIS, SIX_DERNIERS_MOIS, QUATRE_VINGT_DIX_DERNIERS_JOURS -> "semaine";
case CETTE_ANNEE, ANNEE_DERNIERE, DEUX_DERNIERES_ANNEES -> "mois";
case DEPUIS_CREATION -> "annee";
default -> "jour";
};
}
/**
* Retourne le format de date approprié pour cette période
*
* @return Le format de date (dd/MM, MM/yyyy, etc.)
*/
public String getFormatDate() {
return switch (this) {
case AUJOURD_HUI, HIER -> "HH:mm";
case CETTE_SEMAINE, SEMAINE_DERNIERE, SEPT_DERNIERS_JOURS -> "dd/MM";
case CE_MOIS, MOIS_DERNIER, TRENTE_DERNIERS_JOURS -> "dd/MM";
case TROIS_DERNIERS_MOIS, SIX_DERNIERS_MOIS, QUATRE_VINGT_DIX_DERNIERS_JOURS -> "dd/MM";
case CETTE_ANNEE, ANNEE_DERNIERE -> "MM/yyyy";
case DEUX_DERNIERES_ANNEES, DEPUIS_CREATION -> "yyyy";
default -> "dd/MM/yyyy";
};
}
}

View File

@@ -2,186 +2,186 @@ package dev.lions.unionflow.server.api.enums.analytics;
/**
* Énumération des types de métriques disponibles dans le système analytics UnionFlow
*
* Cette énumération définit les différents types de métriques qui peuvent être
* calculées et affichées dans les tableaux de bord et rapports.
*
*
* <p>Cette énumération définit les différents types de métriques qui peuvent être calculées et
* affichées dans les tableaux de bord et rapports.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
public enum TypeMetrique {
// === MÉTRIQUES MEMBRES ===
NOMBRE_MEMBRES_ACTIFS("Nombre de membres actifs", "membres", "count"),
NOMBRE_MEMBRES_INACTIFS("Nombre de membres inactifs", "membres", "count"),
TAUX_CROISSANCE_MEMBRES("Taux de croissance des membres", "membres", "percentage"),
MOYENNE_AGE_MEMBRES("Âge moyen des membres", "membres", "average"),
REPARTITION_GENRE_MEMBRES("Répartition par genre", "membres", "distribution"),
// === MÉTRIQUES FINANCIÈRES ===
TOTAL_COTISATIONS_COLLECTEES("Total des cotisations collectées", "finance", "amount"),
COTISATIONS_EN_ATTENTE("Cotisations en attente", "finance", "amount"),
TAUX_RECOUVREMENT_COTISATIONS("Taux de recouvrement", "finance", "percentage"),
MOYENNE_COTISATION_MEMBRE("Cotisation moyenne par membre", "finance", "average"),
EVOLUTION_REVENUS_MENSUELLE("Évolution des revenus mensuels", "finance", "trend"),
// === MÉTRIQUES ÉVÉNEMENTS ===
NOMBRE_EVENEMENTS_ORGANISES("Nombre d'événements organisés", "evenements", "count"),
TAUX_PARTICIPATION_EVENEMENTS("Taux de participation aux événements", "evenements", "percentage"),
MOYENNE_PARTICIPANTS_EVENEMENT("Moyenne de participants par événement", "evenements", "average"),
EVENEMENTS_ANNULES("Événements annulés", "evenements", "count"),
SATISFACTION_EVENEMENTS("Satisfaction des événements", "evenements", "rating"),
// === MÉTRIQUES SOLIDARITÉ ===
NOMBRE_DEMANDES_AIDE("Nombre de demandes d'aide", "solidarite", "count"),
MONTANT_AIDES_ACCORDEES("Montant des aides accordées", "solidarite", "amount"),
TAUX_APPROBATION_AIDES("Taux d'approbation des aides", "solidarite", "percentage"),
DELAI_TRAITEMENT_DEMANDES("Délai moyen de traitement", "solidarite", "duration"),
IMPACT_SOCIAL_MESURE("Impact social mesuré", "solidarite", "score"),
// === MÉTRIQUES ENGAGEMENT ===
TAUX_CONNEXION_MOBILE("Taux de connexion mobile", "engagement", "percentage"),
FREQUENCE_UTILISATION_APP("Fréquence d'utilisation de l'app", "engagement", "frequency"),
ACTIONS_UTILISATEUR_JOUR("Actions utilisateur par jour", "engagement", "count"),
RETENTION_UTILISATEURS("Rétention des utilisateurs", "engagement", "percentage"),
NPS_SATISFACTION("Net Promoter Score", "engagement", "score"),
// === MÉTRIQUES ORGANISATIONNELLES ===
NOMBRE_ORGANISATIONS_ACTIVES("Organisations actives", "organisation", "count"),
TAUX_CROISSANCE_ORGANISATIONS("Croissance des organisations", "organisation", "percentage"),
MOYENNE_MEMBRES_PAR_ORGANISATION("Membres moyens par organisation", "organisation", "average"),
ORGANISATIONS_PREMIUM("Organisations premium", "organisation", "count"),
CHURN_RATE_ORGANISATIONS("Taux de désabonnement", "organisation", "percentage"),
// === MÉTRIQUES TECHNIQUES ===
TEMPS_REPONSE_API("Temps de réponse API", "technique", "duration"),
TAUX_DISPONIBILITE_SYSTEME("Taux de disponibilité", "technique", "percentage"),
NOMBRE_ERREURS_SYSTEME("Nombre d'erreurs système", "technique", "count"),
UTILISATION_STOCKAGE("Utilisation du stockage", "technique", "size"),
PERFORMANCE_MOBILE("Performance mobile", "technique", "score");
private final String libelle;
private final String categorie;
private final String typeValeur;
/**
* Constructeur de l'énumération TypeMetrique
*
* @param libelle Le libellé affiché à l'utilisateur
* @param categorie La catégorie de la métrique
* @param typeValeur Le type de valeur (count, percentage, amount, etc.)
*/
TypeMetrique(String libelle, String categorie, String typeValeur) {
this.libelle = libelle;
this.categorie = categorie;
this.typeValeur = typeValeur;
}
/**
* Retourne le libellé de la métrique
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne la catégorie de la métrique
*
* @return La catégorie (membres, finance, evenements, etc.)
*/
public String getCategorie() {
return categorie;
}
/**
* Retourne le type de valeur de la métrique
*
* @return Le type de valeur (count, percentage, amount, etc.)
*/
public String getTypeValeur() {
return typeValeur;
}
/**
* Vérifie si la métrique est de type financier
*
* @return true si la métrique concerne les finances
*/
public boolean isFinanciere() {
return "finance".equals(this.categorie);
}
/**
* Vérifie si la métrique est de type pourcentage
*
* @return true si la métrique est un pourcentage
*/
public boolean isPourcentage() {
return "percentage".equals(this.typeValeur);
}
/**
* Vérifie si la métrique est de type compteur
*
* @return true si la métrique est un compteur
*/
public boolean isCompteur() {
return "count".equals(this.typeValeur);
}
/**
* Retourne l'unité de mesure appropriée pour la métrique
*
* @return L'unité de mesure (%, XOF, jours, etc.)
*/
public String getUnite() {
return switch (this.typeValeur) {
case "percentage" -> "%";
case "amount" -> "XOF";
case "duration" -> "jours";
case "size" -> "MB";
case "frequency" -> "/jour";
case "rating", "score" -> "/10";
default -> "";
};
}
/**
* Retourne l'icône appropriée pour la métrique
*
* @return L'icône Material Design
*/
public String getIcone() {
return switch (this.categorie) {
case "membres" -> "people";
case "finance" -> "attach_money";
case "evenements" -> "event";
case "solidarite" -> "favorite";
case "engagement" -> "trending_up";
case "organisation" -> "business";
case "technique" -> "settings";
default -> "analytics";
};
}
/**
* Retourne la couleur appropriée pour la métrique
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return switch (this.categorie) {
case "membres" -> "#2196F3"; // Bleu
case "finance" -> "#4CAF50"; // Vert
case "evenements" -> "#FF9800"; // Orange
case "solidarite" -> "#E91E63"; // Rose
case "engagement" -> "#9C27B0"; // Violet
case "organisation" -> "#607D8B"; // Bleu gris
case "technique" -> "#795548"; // Marron
default -> "#757575"; // Gris
};
}
// === MÉTRIQUES MEMBRES ===
NOMBRE_MEMBRES_ACTIFS("Nombre de membres actifs", "membres", "count"),
NOMBRE_MEMBRES_INACTIFS("Nombre de membres inactifs", "membres", "count"),
TAUX_CROISSANCE_MEMBRES("Taux de croissance des membres", "membres", "percentage"),
MOYENNE_AGE_MEMBRES("Âge moyen des membres", "membres", "average"),
REPARTITION_GENRE_MEMBRES("Répartition par genre", "membres", "distribution"),
// === MÉTRIQUES FINANCIÈRES ===
TOTAL_COTISATIONS_COLLECTEES("Total des cotisations collectées", "finance", "amount"),
COTISATIONS_EN_ATTENTE("Cotisations en attente", "finance", "amount"),
TAUX_RECOUVREMENT_COTISATIONS("Taux de recouvrement", "finance", "percentage"),
MOYENNE_COTISATION_MEMBRE("Cotisation moyenne par membre", "finance", "average"),
EVOLUTION_REVENUS_MENSUELLE("Évolution des revenus mensuels", "finance", "trend"),
// === MÉTRIQUES ÉVÉNEMENTS ===
NOMBRE_EVENEMENTS_ORGANISES("Nombre d'événements organisés", "evenements", "count"),
TAUX_PARTICIPATION_EVENEMENTS("Taux de participation aux événements", "evenements", "percentage"),
MOYENNE_PARTICIPANTS_EVENEMENT("Moyenne de participants par événement", "evenements", "average"),
EVENEMENTS_ANNULES("Événements annulés", "evenements", "count"),
SATISFACTION_EVENEMENTS("Satisfaction des événements", "evenements", "rating"),
// === MÉTRIQUES SOLIDARITÉ ===
NOMBRE_DEMANDES_AIDE("Nombre de demandes d'aide", "solidarite", "count"),
MONTANT_AIDES_ACCORDEES("Montant des aides accordées", "solidarite", "amount"),
TAUX_APPROBATION_AIDES("Taux d'approbation des aides", "solidarite", "percentage"),
DELAI_TRAITEMENT_DEMANDES("Délai moyen de traitement", "solidarite", "duration"),
IMPACT_SOCIAL_MESURE("Impact social mesuré", "solidarite", "score"),
// === MÉTRIQUES ENGAGEMENT ===
TAUX_CONNEXION_MOBILE("Taux de connexion mobile", "engagement", "percentage"),
FREQUENCE_UTILISATION_APP("Fréquence d'utilisation de l'app", "engagement", "frequency"),
ACTIONS_UTILISATEUR_JOUR("Actions utilisateur par jour", "engagement", "count"),
RETENTION_UTILISATEURS("Rétention des utilisateurs", "engagement", "percentage"),
NPS_SATISFACTION("Net Promoter Score", "engagement", "score"),
// === MÉTRIQUES ORGANISATIONNELLES ===
NOMBRE_ORGANISATIONS_ACTIVES("Organisations actives", "organisation", "count"),
TAUX_CROISSANCE_ORGANISATIONS("Croissance des organisations", "organisation", "percentage"),
MOYENNE_MEMBRES_PAR_ORGANISATION("Membres moyens par organisation", "organisation", "average"),
ORGANISATIONS_PREMIUM("Organisations premium", "organisation", "count"),
CHURN_RATE_ORGANISATIONS("Taux de désabonnement", "organisation", "percentage"),
// === MÉTRIQUES TECHNIQUES ===
TEMPS_REPONSE_API("Temps de réponse API", "technique", "duration"),
TAUX_DISPONIBILITE_SYSTEME("Taux de disponibilité", "technique", "percentage"),
NOMBRE_ERREURS_SYSTEME("Nombre d'erreurs système", "technique", "count"),
UTILISATION_STOCKAGE("Utilisation du stockage", "technique", "size"),
PERFORMANCE_MOBILE("Performance mobile", "technique", "score");
private final String libelle;
private final String categorie;
private final String typeValeur;
/**
* Constructeur de l'énumération TypeMetrique
*
* @param libelle Le libellé affiché à l'utilisateur
* @param categorie La catégorie de la métrique
* @param typeValeur Le type de valeur (count, percentage, amount, etc.)
*/
TypeMetrique(String libelle, String categorie, String typeValeur) {
this.libelle = libelle;
this.categorie = categorie;
this.typeValeur = typeValeur;
}
/**
* Retourne le libellé de la métrique
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne la catégorie de la métrique
*
* @return La catégorie (membres, finance, evenements, etc.)
*/
public String getCategorie() {
return categorie;
}
/**
* Retourne le type de valeur de la métrique
*
* @return Le type de valeur (count, percentage, amount, etc.)
*/
public String getTypeValeur() {
return typeValeur;
}
/**
* Vérifie si la métrique est de type financier
*
* @return true si la métrique concerne les finances
*/
public boolean isFinanciere() {
return "finance".equals(this.categorie);
}
/**
* Vérifie si la métrique est de type pourcentage
*
* @return true si la métrique est un pourcentage
*/
public boolean isPourcentage() {
return "percentage".equals(this.typeValeur);
}
/**
* Vérifie si la métrique est de type compteur
*
* @return true si la métrique est un compteur
*/
public boolean isCompteur() {
return "count".equals(this.typeValeur);
}
/**
* Retourne l'unité de mesure appropriée pour la métrique
*
* @return L'unité de mesure (%, XOF, jours, etc.)
*/
public String getUnite() {
return switch (this.typeValeur) {
case "percentage" -> "%";
case "amount" -> "XOF";
case "duration" -> "jours";
case "size" -> "MB";
case "frequency" -> "/jour";
case "rating", "score" -> "/10";
default -> "";
};
}
/**
* Retourne l'icône appropriée pour la métrique
*
* @return L'icône Material Design
*/
public String getIcone() {
return switch (this.categorie) {
case "membres" -> "people";
case "finance" -> "attach_money";
case "evenements" -> "event";
case "solidarite" -> "favorite";
case "engagement" -> "trending_up";
case "organisation" -> "business";
case "technique" -> "settings";
default -> "analytics";
};
}
/**
* Retourne la couleur appropriée pour la métrique
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return switch (this.categorie) {
case "membres" -> "#2196F3"; // Bleu
case "finance" -> "#4CAF50"; // Vert
case "evenements" -> "#FF9800"; // Orange
case "solidarite" -> "#E91E63"; // Rose
case "engagement" -> "#9C27B0"; // Violet
case "organisation" -> "#607D8B"; // Bleu gris
case "technique" -> "#795548"; // Marron
default -> "#757575"; // Gris
};
}
}

View File

@@ -0,0 +1,159 @@
package dev.lions.unionflow.server.api.enums.evenement;
/**
* Énumération des priorités d'événements dans UnionFlow
*
* <p>Cette énumération définit les niveaux de priorité pour les événements, permettant de prioriser
* l'affichage et les notifications selon l'importance.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-09-21
*/
public enum PrioriteEvenement {
CRITIQUE(
"Critique",
"critical",
1,
"Événement critique nécessitant une attention immédiate",
"#F44336",
"priority_high",
true,
true),
HAUTE(
"Haute",
"high",
2,
"Événement de haute priorité",
"#FF9800",
"keyboard_arrow_up",
true,
false),
NORMALE(
"Normale", "normal", 3, "Événement de priorité normale", "#2196F3", "remove", false, false),
BASSE(
"Basse",
"low",
4,
"Événement de priorité basse",
"#4CAF50",
"keyboard_arrow_down",
false,
false);
private final String libelle;
private final String code;
private final int niveau;
private final String description;
private final String couleur;
private final String icone;
private final boolean notificationImmediate;
private final boolean escaladeAutomatique;
PrioriteEvenement(
String libelle,
String code,
int niveau,
String description,
String couleur,
String icone,
boolean notificationImmediate,
boolean escaladeAutomatique) {
this.libelle = libelle;
this.code = code;
this.niveau = niveau;
this.description = description;
this.couleur = couleur;
this.icone = icone;
this.notificationImmediate = notificationImmediate;
this.escaladeAutomatique = escaladeAutomatique;
}
// === GETTERS ===
public String getLibelle() {
return libelle;
}
public String getCode() {
return code;
}
public int getNiveau() {
return niveau;
}
public String getDescription() {
return description;
}
public String getCouleur() {
return couleur;
}
public String getIcone() {
return icone;
}
public boolean isNotificationImmediate() {
return notificationImmediate;
}
public boolean isEscaladeAutomatique() {
return escaladeAutomatique;
}
// === MÉTHODES UTILITAIRES ===
/** Vérifie si la priorité est élevée (critique ou haute) */
public boolean isElevee() {
return this == CRITIQUE || this == HAUTE;
}
/** Vérifie si la priorité nécessite une attention immédiate */
public boolean isUrgente() {
return this == CRITIQUE || this == HAUTE;
}
/** Compare deux priorités */
public boolean isSuperieurA(PrioriteEvenement autre) {
return this.niveau < autre.niveau; // Plus le niveau est bas, plus la priorité est haute
}
/** Retourne les priorités élevées */
public static java.util.List<PrioriteEvenement> getPrioritesElevees() {
return java.util.Arrays.stream(values())
.filter(PrioriteEvenement::isElevee)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les priorités urgentes */
public static java.util.List<PrioriteEvenement> getPrioritesUrgentes() {
return java.util.Arrays.stream(values())
.filter(PrioriteEvenement::isUrgente)
.collect(java.util.stream.Collectors.toList());
}
/** Détermine la priorité basée sur le type d'événement */
public static PrioriteEvenement determinerPriorite(TypeEvenementMetier typeEvenement) {
return switch (typeEvenement) {
case ASSEMBLEE_GENERALE -> HAUTE;
case REUNION_BUREAU -> HAUTE;
case ACTION_CARITATIVE -> NORMALE;
case FORMATION -> NORMALE;
case CONFERENCE -> NORMALE;
case ACTIVITE_SOCIALE -> BASSE;
case ATELIER -> BASSE;
case CEREMONIE -> NORMALE;
case AUTRE -> NORMALE;
};
}
/** Retourne la priorité par défaut */
public static PrioriteEvenement getDefaut() {
return NORMALE;
}
}

View File

@@ -0,0 +1,233 @@
package dev.lions.unionflow.server.api.enums.evenement;
/**
* Énumération des statuts d'événements dans UnionFlow
*
* <p>Cette énumération définit les différents états qu'un événement peut avoir tout au long de son
* cycle de vie, de la planification à la clôture.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-09-21
*/
public enum StatutEvenement {
// === STATUTS DE PLANIFICATION ===
PLANIFIE(
"Planifié",
"planned",
"L'événement est planifié et en préparation",
"#2196F3",
"event",
false,
false),
CONFIRME(
"Confirmé",
"confirmed",
"L'événement est confirmé et les inscriptions sont ouvertes",
"#4CAF50",
"event_available",
false,
false),
// === STATUTS D'EXÉCUTION ===
EN_COURS(
"En cours",
"ongoing",
"L'événement est actuellement en cours",
"#FF9800",
"play_circle",
false,
false),
// === STATUTS FINAUX ===
TERMINE(
"Terminé",
"completed",
"L'événement s'est terminé avec succès",
"#4CAF50",
"check_circle",
true,
false),
ANNULE("Annulé", "cancelled", "L'événement a été annulé", "#F44336", "cancel", true, true),
REPORTE(
"Reporté",
"postponed",
"L'événement a été reporté à une date ultérieure",
"#FF5722",
"schedule",
false,
false);
private final String libelle;
private final String code;
private final String description;
private final String couleur;
private final String icone;
private final boolean estFinal;
private final boolean estEchec;
StatutEvenement(
String libelle,
String code,
String description,
String couleur,
String icone,
boolean estFinal,
boolean estEchec) {
this.libelle = libelle;
this.code = code;
this.description = description;
this.couleur = couleur;
this.icone = icone;
this.estFinal = estFinal;
this.estEchec = estEchec;
}
// === GETTERS ===
public String getLibelle() {
return libelle;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
public String getCouleur() {
return couleur;
}
public String getIcone() {
return icone;
}
public boolean isEstFinal() {
return estFinal;
}
public boolean isEstEchec() {
return estEchec;
}
// === MÉTHODES UTILITAIRES ===
/** Vérifie si l'événement peut être modifié */
public boolean permetModification() {
return switch (this) {
case PLANIFIE, CONFIRME, REPORTE -> true;
case EN_COURS, TERMINE, ANNULE -> false;
};
}
/** Vérifie si l'événement peut être annulé */
public boolean permetAnnulation() {
return switch (this) {
case PLANIFIE, CONFIRME, EN_COURS, REPORTE -> true;
case TERMINE, ANNULE -> false;
};
}
/** Vérifie si l'événement est en cours d'exécution */
public boolean isEnCours() {
return this == EN_COURS;
}
/** Vérifie si l'événement est terminé avec succès */
public boolean isSucces() {
return this == TERMINE;
}
/** Retourne les statuts finaux */
public static java.util.List<StatutEvenement> getStatutsFinaux() {
return java.util.Arrays.stream(values())
.filter(StatutEvenement::isEstFinal)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les statuts d'échec */
public static java.util.List<StatutEvenement> getStatutsEchec() {
return java.util.Arrays.stream(values())
.filter(StatutEvenement::isEstEchec)
.collect(java.util.stream.Collectors.toList());
}
/** Vérifie si la transition vers un autre statut est valide */
public boolean peutTransitionnerVers(StatutEvenement nouveauStatut) {
if (this == nouveauStatut) return false;
if (estFinal && nouveauStatut != REPORTE) return false;
return switch (this) {
case PLANIFIE ->
nouveauStatut == CONFIRME || nouveauStatut == ANNULE || nouveauStatut == REPORTE;
case CONFIRME ->
nouveauStatut == EN_COURS || nouveauStatut == ANNULE || nouveauStatut == REPORTE;
case EN_COURS -> nouveauStatut == TERMINE || nouveauStatut == ANNULE;
case REPORTE -> nouveauStatut == PLANIFIE || nouveauStatut == ANNULE;
default -> false;
};
}
/** Retourne le niveau de priorité pour l'affichage */
public int getNiveauPriorite() {
return switch (this) {
case EN_COURS -> 1;
case CONFIRME -> 2;
case PLANIFIE -> 3;
case REPORTE -> 4;
case TERMINE -> 5;
case ANNULE -> 6;
};
}
// === MÉTHODES STATIQUES ===
/** Retourne les statuts actifs (non finaux) */
public static StatutEvenement[] getStatutsActifs() {
return new StatutEvenement[] {PLANIFIE, CONFIRME, EN_COURS, REPORTE};
}
/** Trouve un statut par son code */
public static StatutEvenement fromCode(String code) {
if (code == null || code.trim().isEmpty()) {
return null;
}
for (StatutEvenement statut : values()) {
if (statut.code.equals(code)) {
return statut;
}
}
return null;
}
/** Trouve un statut par son libellé */
public static StatutEvenement fromLibelle(String libelle) {
if (libelle == null || libelle.trim().isEmpty()) {
return null;
}
for (StatutEvenement statut : values()) {
if (statut.libelle.equals(libelle)) {
return statut;
}
}
return null;
}
/** Retourne les transitions possibles depuis ce statut */
public StatutEvenement[] getTransitionsPossibles() {
return switch (this) {
case PLANIFIE -> new StatutEvenement[] {CONFIRME, ANNULE, REPORTE};
case CONFIRME -> new StatutEvenement[] {EN_COURS, ANNULE, REPORTE};
case EN_COURS -> new StatutEvenement[] {TERMINE, ANNULE};
case REPORTE -> new StatutEvenement[] {PLANIFIE, CONFIRME, ANNULE};
case TERMINE, ANNULE -> new StatutEvenement[] {}; // Aucune transition possible
};
}
}

View File

@@ -2,320 +2,464 @@ package dev.lions.unionflow.server.api.enums.notification;
/**
* Énumération des canaux de notification pour Android et iOS
*
* Cette énumération définit les différents canaux de notification utilisés
* pour organiser et prioriser les notifications push dans UnionFlow.
*
*
* <p>Cette énumération définit les différents canaux de notification utilisés pour organiser et
* prioriser les notifications push dans UnionFlow.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
public enum CanalNotification {
// === CANAUX PAR PRIORITÉ ===
URGENT_CHANNEL("urgent", "Notifications urgentes", "Alertes critiques nécessitant une action immédiate",
5, true, true, true, "urgent", "#F44336"),
ERROR_CHANNEL("error", "Erreurs système", "Notifications d'erreurs et de problèmes techniques",
4, true, true, false, "error", "#F44336"),
WARNING_CHANNEL("warning", "Avertissements", "Notifications d'avertissement et d'attention",
4, true, true, false, "warning", "#FF9800"),
IMPORTANT_CHANNEL("important", "Notifications importantes", "Informations importantes à ne pas manquer",
4, true, true, false, "important", "#FF5722"),
REMINDER_CHANNEL("reminder", "Rappels", "Rappels d'événements, cotisations et échéances",
3, true, true, false, "reminder", "#2196F3"),
SUCCESS_CHANNEL("success", "Confirmations", "Notifications de succès et confirmations",
2, false, false, false, "success", "#4CAF50"),
CELEBRATION_CHANNEL("celebration", "Célébrations", "Anniversaires, félicitations et événements joyeux",
2, false, false, false, "celebration", "#FF9800"),
DEFAULT_CHANNEL("default", "Notifications générales", "Notifications d'information générale",
2, false, false, false, "info", "#2196F3"),
// === CANAUX PAR CATÉGORIE ===
EVENTS_CHANNEL("events", "Événements", "Notifications liées aux événements et activités",
3, true, false, false, "event", "#2196F3"),
PAYMENTS_CHANNEL("payments", "Paiements", "Notifications de cotisations et paiements",
4, true, true, false, "payment", "#4CAF50"),
SOLIDARITY_CHANNEL("solidarity", "Solidarité", "Notifications d'aide et de solidarité",
3, true, false, false, "help", "#E91E63"),
MEMBERS_CHANNEL("members", "Membres", "Notifications concernant les membres",
2, false, false, false, "people", "#2196F3"),
ORGANIZATION_CHANNEL("organization", "Organisation", "Annonces et informations organisationnelles",
3, true, false, false, "business", "#2196F3"),
SYSTEM_CHANNEL("system", "Système", "Notifications système et maintenance",
2, false, false, false, "settings", "#607D8B"),
MESSAGES_CHANNEL("messages", "Messages", "Messages privés et communications",
3, true, false, false, "message", "#2196F3"),
LOCATION_CHANNEL("location", "Géolocalisation", "Notifications basées sur la localisation",
2, false, false, false, "location_on", "#4CAF50");
private final String id;
private final String nom;
private final String description;
private final int importance;
private final boolean sonActive;
private final boolean vibrationActive;
private final boolean lumiereLED;
private final String typeDefaut;
private final String couleur;
/**
* Constructeur de l'énumération CanalNotification
*
* @param id L'identifiant unique du canal
* @param nom Le nom affiché du canal
* @param description La description du canal
* @param importance Le niveau d'importance (1=Min, 2=Low, 3=Default, 4=High, 5=Max)
* @param sonActive true si le son est activé par défaut
* @param vibrationActive true si la vibration est activée par défaut
* @param lumiereLED true si la lumière LED est activée par défaut
* @param typeDefaut Le type de notification par défaut pour ce canal
* @param couleur La couleur hexadécimale du canal
*/
CanalNotification(String id, String nom, String description, int importance,
boolean sonActive, boolean vibrationActive, boolean lumiereLED,
String typeDefaut, String couleur) {
this.id = id;
this.nom = nom;
this.description = description;
this.importance = importance;
this.sonActive = sonActive;
this.vibrationActive = vibrationActive;
this.lumiereLED = lumiereLED;
this.typeDefaut = typeDefaut;
this.couleur = couleur;
}
/**
* Retourne l'identifiant du canal
*
* @return L'ID unique du canal
*/
public String getId() {
return id;
}
/**
* Retourne le nom du canal
*
* @return Le nom affiché du canal
*/
public String getNom() {
return nom;
}
/**
* Retourne la description du canal
*
* @return La description détaillée du canal
*/
public String getDescription() {
return description;
}
/**
* Retourne le niveau d'importance
*
* @return Le niveau d'importance (1-5)
*/
public int getImportance() {
return importance;
}
/**
* Vérifie si le son est activé par défaut
*
* @return true si le son est activé
*/
public boolean isSonActive() {
return sonActive;
}
/**
* Vérifie si la vibration est activée par défaut
*
* @return true si la vibration est activée
*/
public boolean isVibrationActive() {
return vibrationActive;
}
/**
* Vérifie si la lumière LED est activée par défaut
*
* @return true si la lumière LED est activée
*/
public boolean isLumiereLED() {
return lumiereLED;
}
/**
* Retourne le type de notification par défaut
*
* @return Le type par défaut pour ce canal
*/
public String getTypeDefaut() {
return typeDefaut;
}
/**
* Retourne la couleur du canal
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return couleur;
}
/**
* Vérifie si le canal est critique
*
* @return true si le canal a une importance élevée (4-5)
*/
public boolean isCritique() {
return importance >= 4;
}
/**
* Vérifie si le canal est silencieux par défaut
*
* @return true si le canal n'émet ni son ni vibration
*/
public boolean isSilencieux() {
return !sonActive && !vibrationActive;
}
/**
* Retourne le niveau d'importance Android
*
* @return Le niveau d'importance pour Android (IMPORTANCE_MIN à IMPORTANCE_MAX)
*/
public String getImportanceAndroid() {
return switch (importance) {
case 1 -> "IMPORTANCE_MIN";
case 2 -> "IMPORTANCE_LOW";
case 3 -> "IMPORTANCE_DEFAULT";
case 4 -> "IMPORTANCE_HIGH";
case 5 -> "IMPORTANCE_MAX";
default -> "IMPORTANCE_DEFAULT";
};
}
/**
* Retourne la priorité iOS
*
* @return La priorité pour iOS (low ou high)
*/
public String getPrioriteIOS() {
return importance >= 4 ? "high" : "low";
}
/**
* Retourne le son par défaut pour le canal
*
* @return Le nom du fichier son ou "default"
*/
public String getSonDefaut() {
return switch (this) {
case URGENT_CHANNEL -> "urgent_sound.mp3";
case ERROR_CHANNEL -> "error_sound.mp3";
case WARNING_CHANNEL -> "warning_sound.mp3";
case IMPORTANT_CHANNEL -> "important_sound.mp3";
case REMINDER_CHANNEL -> "reminder_sound.mp3";
case SUCCESS_CHANNEL -> "success_sound.mp3";
case CELEBRATION_CHANNEL -> "celebration_sound.mp3";
default -> "default";
};
}
/**
* Retourne le pattern de vibration
*
* @return Le pattern de vibration en millisecondes
*/
public long[] getPatternVibration() {
return switch (this) {
case URGENT_CHANNEL -> new long[]{0, 500, 200, 500, 200, 500}; // Triple vibration
case ERROR_CHANNEL -> new long[]{0, 1000, 500, 1000}; // Double vibration longue
case WARNING_CHANNEL -> new long[]{0, 300, 200, 300}; // Double vibration courte
case IMPORTANT_CHANNEL -> new long[]{0, 500, 100, 200}; // Vibration distinctive
case REMINDER_CHANNEL -> new long[]{0, 200, 100, 200}; // Vibration douce
default -> new long[]{0, 250}; // Vibration simple
};
}
/**
* Vérifie si le canal peut être désactivé par l'utilisateur
*
* @return true si l'utilisateur peut désactiver ce canal
*/
public boolean peutEtreDesactive() {
return this != URGENT_CHANNEL && this != ERROR_CHANNEL;
}
/**
* Retourne la durée de vie par défaut des notifications de ce canal
*
* @return La durée de vie en millisecondes
*/
public long getDureeVieMs() {
return switch (this) {
case URGENT_CHANNEL -> 3600000L; // 1 heure
case ERROR_CHANNEL -> 86400000L; // 24 heures
case WARNING_CHANNEL -> 172800000L; // 48 heures
case IMPORTANT_CHANNEL -> 259200000L; // 72 heures
case REMINDER_CHANNEL -> 86400000L; // 24 heures
case SUCCESS_CHANNEL -> 172800000L; // 48 heures
case CELEBRATION_CHANNEL -> 259200000L; // 72 heures
default -> 604800000L; // 1 semaine
};
}
/**
* Trouve un canal par son ID
*
* @param id L'identifiant du canal
* @return Le canal correspondant ou DEFAULT_CHANNEL si non trouvé
*/
public static CanalNotification parId(String id) {
for (CanalNotification canal : values()) {
if (canal.getId().equals(id)) {
return canal;
}
}
return DEFAULT_CHANNEL;
}
/**
* Retourne tous les canaux critiques
*
* @return Un tableau des canaux critiques
*/
public static CanalNotification[] getCanauxCritiques() {
return new CanalNotification[]{URGENT_CHANNEL, ERROR_CHANNEL, WARNING_CHANNEL, IMPORTANT_CHANNEL};
}
/**
* Retourne tous les canaux par catégorie
*
* @return Un tableau des canaux catégoriels
*/
public static CanalNotification[] getCanauxCategories() {
return new CanalNotification[]{EVENTS_CHANNEL, PAYMENTS_CHANNEL, SOLIDARITY_CHANNEL,
MEMBERS_CHANNEL, ORGANIZATION_CHANNEL, SYSTEM_CHANNEL,
MESSAGES_CHANNEL, LOCATION_CHANNEL};
// === CANAUX PAR PRIORITÉ ===
URGENT_CHANNEL(
"urgent",
"Notifications urgentes",
"Alertes critiques nécessitant une action immédiate",
5,
true,
true,
true,
"urgent",
"#F44336"),
ERROR_CHANNEL(
"error",
"Erreurs système",
"Notifications d'erreurs et de problèmes techniques",
4,
true,
true,
false,
"error",
"#F44336"),
WARNING_CHANNEL(
"warning",
"Avertissements",
"Notifications d'avertissement et d'attention",
4,
true,
true,
false,
"warning",
"#FF9800"),
IMPORTANT_CHANNEL(
"important",
"Notifications importantes",
"Informations importantes à ne pas manquer",
4,
true,
true,
false,
"important",
"#FF5722"),
REMINDER_CHANNEL(
"reminder",
"Rappels",
"Rappels d'événements, cotisations et échéances",
3,
true,
true,
false,
"reminder",
"#2196F3"),
SUCCESS_CHANNEL(
"success",
"Confirmations",
"Notifications de succès et confirmations",
2,
false,
false,
false,
"success",
"#4CAF50"),
CELEBRATION_CHANNEL(
"celebration",
"Célébrations",
"Anniversaires, félicitations et événements joyeux",
2,
false,
false,
false,
"celebration",
"#FF9800"),
DEFAULT_CHANNEL(
"default",
"Notifications générales",
"Notifications d'information générale",
2,
false,
false,
false,
"info",
"#2196F3"),
// === CANAUX PAR CATÉGORIE ===
EVENTS_CHANNEL(
"events",
"Événements",
"Notifications liées aux événements et activités",
3,
true,
false,
false,
"event",
"#2196F3"),
PAYMENTS_CHANNEL(
"payments",
"Paiements",
"Notifications de cotisations et paiements",
4,
true,
true,
false,
"payment",
"#4CAF50"),
SOLIDARITY_CHANNEL(
"solidarity",
"Solidarité",
"Notifications d'aide et de solidarité",
3,
true,
false,
false,
"help",
"#E91E63"),
MEMBERS_CHANNEL(
"members",
"Membres",
"Notifications concernant les membres",
2,
false,
false,
false,
"people",
"#2196F3"),
ORGANIZATION_CHANNEL(
"organization",
"Organisation",
"Annonces et informations organisationnelles",
3,
true,
false,
false,
"business",
"#2196F3"),
SYSTEM_CHANNEL(
"system",
"Système",
"Notifications système et maintenance",
2,
false,
false,
false,
"settings",
"#607D8B"),
MESSAGES_CHANNEL(
"messages",
"Messages",
"Messages privés et communications",
3,
true,
false,
false,
"message",
"#2196F3"),
LOCATION_CHANNEL(
"location",
"Géolocalisation",
"Notifications basées sur la localisation",
2,
false,
false,
false,
"location_on",
"#4CAF50");
private final String id;
private final String nom;
private final String description;
private final int importance;
private final boolean sonActive;
private final boolean vibrationActive;
private final boolean lumiereLED;
private final String typeDefaut;
private final String couleur;
/**
* Constructeur de l'énumération CanalNotification
*
* @param id L'identifiant unique du canal
* @param nom Le nom affiché du canal
* @param description La description du canal
* @param importance Le niveau d'importance (1=Min, 2=Low, 3=Default, 4=High, 5=Max)
* @param sonActive true si le son est activé par défaut
* @param vibrationActive true si la vibration est activée par défaut
* @param lumiereLED true si la lumière LED est activée par défaut
* @param typeDefaut Le type de notification par défaut pour ce canal
* @param couleur La couleur hexadécimale du canal
*/
CanalNotification(
String id,
String nom,
String description,
int importance,
boolean sonActive,
boolean vibrationActive,
boolean lumiereLED,
String typeDefaut,
String couleur) {
this.id = id;
this.nom = nom;
this.description = description;
this.importance = importance;
this.sonActive = sonActive;
this.vibrationActive = vibrationActive;
this.lumiereLED = lumiereLED;
this.typeDefaut = typeDefaut;
this.couleur = couleur;
}
/**
* Retourne l'identifiant du canal
*
* @return L'ID unique du canal
*/
public String getId() {
return id;
}
/**
* Retourne le nom du canal
*
* @return Le nom affiché du canal
*/
public String getNom() {
return nom;
}
/**
* Retourne la description du canal
*
* @return La description détaillée du canal
*/
public String getDescription() {
return description;
}
/**
* Retourne le niveau d'importance
*
* @return Le niveau d'importance (1-5)
*/
public int getImportance() {
return importance;
}
/**
* Vérifie si le son est activé par défaut
*
* @return true si le son est activé
*/
public boolean isSonActive() {
return sonActive;
}
/**
* Vérifie si la vibration est activée par défaut
*
* @return true si la vibration est activée
*/
public boolean isVibrationActive() {
return vibrationActive;
}
/**
* Vérifie si la lumière LED est activée par défaut
*
* @return true si la lumière LED est activée
*/
public boolean isLumiereLED() {
return lumiereLED;
}
/**
* Retourne le type de notification par défaut
*
* @return Le type par défaut pour ce canal
*/
public String getTypeDefaut() {
return typeDefaut;
}
/**
* Retourne la couleur du canal
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return couleur;
}
/**
* Vérifie si le canal est critique
*
* @return true si le canal a une importance élevée (4-5)
*/
public boolean isCritique() {
return importance >= 4;
}
/**
* Vérifie si le canal est silencieux par défaut
*
* @return true si le canal n'émet ni son ni vibration
*/
public boolean isSilencieux() {
return !sonActive && !vibrationActive;
}
/**
* Retourne le niveau d'importance Android
*
* @return Le niveau d'importance pour Android (IMPORTANCE_MIN à IMPORTANCE_MAX)
*/
public String getImportanceAndroid() {
return switch (importance) {
case 1 -> "IMPORTANCE_MIN";
case 2 -> "IMPORTANCE_LOW";
case 3 -> "IMPORTANCE_DEFAULT";
case 4 -> "IMPORTANCE_HIGH";
case 5 -> "IMPORTANCE_MAX";
default -> "IMPORTANCE_DEFAULT";
};
}
/**
* Retourne la priorité iOS
*
* @return La priorité pour iOS (low ou high)
*/
public String getPrioriteIOS() {
return importance >= 4 ? "high" : "low";
}
/**
* Retourne le son par défaut pour le canal
*
* @return Le nom du fichier son ou "default"
*/
public String getSonDefaut() {
return switch (this) {
case URGENT_CHANNEL -> "urgent_sound.mp3";
case ERROR_CHANNEL -> "error_sound.mp3";
case WARNING_CHANNEL -> "warning_sound.mp3";
case IMPORTANT_CHANNEL -> "important_sound.mp3";
case REMINDER_CHANNEL -> "reminder_sound.mp3";
case SUCCESS_CHANNEL -> "success_sound.mp3";
case CELEBRATION_CHANNEL -> "celebration_sound.mp3";
default -> "default";
};
}
/**
* Retourne le pattern de vibration
*
* @return Le pattern de vibration en millisecondes
*/
public long[] getPatternVibration() {
return switch (this) {
case URGENT_CHANNEL -> new long[] {0, 500, 200, 500, 200, 500}; // Triple vibration
case ERROR_CHANNEL -> new long[] {0, 1000, 500, 1000}; // Double vibration longue
case WARNING_CHANNEL -> new long[] {0, 300, 200, 300}; // Double vibration courte
case IMPORTANT_CHANNEL -> new long[] {0, 500, 100, 200}; // Vibration distinctive
case REMINDER_CHANNEL -> new long[] {0, 200, 100, 200}; // Vibration douce
default -> new long[] {0, 250}; // Vibration simple
};
}
/**
* Vérifie si le canal peut être désactivé par l'utilisateur
*
* @return true si l'utilisateur peut désactiver ce canal
*/
public boolean peutEtreDesactive() {
return this != URGENT_CHANNEL && this != ERROR_CHANNEL;
}
/**
* Retourne la durée de vie par défaut des notifications de ce canal
*
* @return La durée de vie en millisecondes
*/
public long getDureeVieMs() {
return switch (this) {
case URGENT_CHANNEL -> 3600000L; // 1 heure
case ERROR_CHANNEL -> 86400000L; // 24 heures
case WARNING_CHANNEL -> 172800000L; // 48 heures
case IMPORTANT_CHANNEL -> 259200000L; // 72 heures
case REMINDER_CHANNEL -> 86400000L; // 24 heures
case SUCCESS_CHANNEL -> 172800000L; // 48 heures
case CELEBRATION_CHANNEL -> 259200000L; // 72 heures
default -> 604800000L; // 1 semaine
};
}
/**
* Trouve un canal par son ID
*
* @param id L'identifiant du canal
* @return Le canal correspondant ou DEFAULT_CHANNEL si non trouvé
*/
public static CanalNotification parId(String id) {
for (CanalNotification canal : values()) {
if (canal.getId().equals(id)) {
return canal;
}
}
return DEFAULT_CHANNEL;
}
/**
* Retourne tous les canaux critiques
*
* @return Un tableau des canaux critiques
*/
public static CanalNotification[] getCanauxCritiques() {
return new CanalNotification[] {
URGENT_CHANNEL, ERROR_CHANNEL, WARNING_CHANNEL, IMPORTANT_CHANNEL
};
}
/**
* Retourne tous les canaux par catégorie
*
* @return Un tableau des canaux catégoriels
*/
public static CanalNotification[] getCanauxCategories() {
return new CanalNotification[] {
EVENTS_CHANNEL,
PAYMENTS_CHANNEL,
SOLIDARITY_CHANNEL,
MEMBERS_CHANNEL,
ORGANIZATION_CHANNEL,
SYSTEM_CHANNEL,
MESSAGES_CHANNEL,
LOCATION_CHANNEL
};
}
}

View File

@@ -2,309 +2,458 @@ package dev.lions.unionflow.server.api.enums.notification;
/**
* Énumération des statuts de notification dans UnionFlow
*
* Cette énumération définit les différents états qu'une notification peut avoir
* tout au long de son cycle de vie, de la création à l'archivage.
*
*
* <p>Cette énumération définit les différents états qu'une notification peut avoir tout au long de
* son cycle de vie, de la création à l'archivage.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
public enum StatutNotification {
// === STATUTS DE CRÉATION ===
BROUILLON("Brouillon", "draft", "La notification est en cours de création",
"edit", "#9E9E9E", false, false),
PROGRAMMEE("Programmée", "scheduled", "La notification est programmée pour envoi ultérieur",
"schedule", "#FF9800", false, false),
EN_ATTENTE("En attente", "pending", "La notification est en attente d'envoi",
"hourglass_empty", "#FF9800", false, false),
// === STATUTS D'ENVOI ===
EN_COURS_ENVOI("En cours d'envoi", "sending", "La notification est en cours d'envoi",
"send", "#2196F3", false, false),
ENVOYEE("Envoyée", "sent", "La notification a été envoyée avec succès",
"check_circle", "#4CAF50", true, false),
ECHEC_ENVOI("Échec d'envoi", "failed", "L'envoi de la notification a échoué",
"error", "#F44336", true, true),
PARTIELLEMENT_ENVOYEE("Partiellement envoyée", "partial", "La notification a été envoyée à certains destinataires seulement",
"warning", "#FF9800", true, true),
// === STATUTS DE RÉCEPTION ===
RECUE("Reçue", "received", "La notification a été reçue par l'appareil",
"download_done", "#4CAF50", true, false),
AFFICHEE("Affichée", "displayed", "La notification a été affichée à l'utilisateur",
"visibility", "#2196F3", true, false),
OUVERTE("Ouverte", "opened", "L'utilisateur a ouvert la notification",
"open_in_new", "#4CAF50", true, false),
IGNOREE("Ignorée", "ignored", "La notification a été ignorée par l'utilisateur",
"visibility_off", "#9E9E9E", true, false),
// === STATUTS D'INTERACTION ===
LUE("Lue", "read", "La notification a été lue par l'utilisateur",
"mark_email_read", "#4CAF50", true, false),
NON_LUE("Non lue", "unread", "La notification n'a pas encore été lue",
"mark_email_unread", "#FF9800", true, false),
MARQUEE_IMPORTANTE("Marquée importante", "starred", "L'utilisateur a marqué la notification comme importante",
"star", "#FF9800", true, false),
ACTION_EXECUTEE("Action exécutée", "action_done", "L'utilisateur a exécuté l'action demandée",
"task_alt", "#4CAF50", true, false),
// === STATUTS DE GESTION ===
SUPPRIMEE("Supprimée", "deleted", "La notification a été supprimée par l'utilisateur",
"delete", "#F44336", false, false),
ARCHIVEE("Archivée", "archived", "La notification a été archivée",
"archive", "#9E9E9E", false, false),
EXPIREE("Expirée", "expired", "La notification a dépassé sa durée de vie",
"schedule", "#9E9E9E", false, false),
ANNULEE("Annulée", "cancelled", "L'envoi de la notification a été annulé",
"cancel", "#F44336", false, true),
// === STATUTS D'ERREUR ===
ERREUR_TECHNIQUE("Erreur technique", "error", "Une erreur technique a empêché le traitement",
"bug_report", "#F44336", false, true),
DESTINATAIRE_INVALIDE("Destinataire invalide", "invalid_recipient", "Le destinataire n'est pas valide",
"person_off", "#F44336", false, true),
TOKEN_INVALIDE("Token invalide", "invalid_token", "Le token FCM du destinataire est invalide",
"key_off", "#F44336", false, true),
QUOTA_DEPASSE("Quota dépassé", "quota_exceeded", "Le quota d'envoi a été dépassé",
"block", "#F44336", false, true);
private final String libelle;
private final String code;
private final String description;
private final String icone;
private final String couleur;
private final boolean visibleUtilisateur;
private final boolean necessiteAttention;
/**
* Constructeur de l'énumération StatutNotification
*
* @param libelle Le libellé affiché à l'utilisateur
* @param code Le code technique du statut
* @param description La description détaillée du statut
* @param icone L'icône Material Design
* @param couleur La couleur hexadécimale
* @param visibleUtilisateur true si visible à l'utilisateur final
* @param necessiteAttention true si le statut nécessite une attention particulière
*/
StatutNotification(String libelle, String code, String description, String icone, String couleur,
boolean visibleUtilisateur, boolean necessiteAttention) {
this.libelle = libelle;
this.code = code;
this.description = description;
this.icone = icone;
this.couleur = couleur;
this.visibleUtilisateur = visibleUtilisateur;
this.necessiteAttention = necessiteAttention;
}
/**
* Retourne le libellé du statut
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne le code technique du statut
*
* @return Le code technique
*/
public String getCode() {
return code;
}
/**
* Retourne la description du statut
*
* @return La description détaillée
*/
public String getDescription() {
return description;
}
/**
* Retourne l'icône du statut
*
* @return L'icône Material Design
*/
public String getIcone() {
return icone;
}
/**
* Retourne la couleur du statut
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return couleur;
}
/**
* Vérifie si le statut est visible à l'utilisateur final
*
* @return true si visible à l'utilisateur
*/
public boolean isVisibleUtilisateur() {
return visibleUtilisateur;
}
/**
* Vérifie si le statut nécessite une attention particulière
*
* @return true si le statut nécessite attention
*/
public boolean isNecessiteAttention() {
return necessiteAttention;
}
/**
* Vérifie si le statut indique un succès
*
* @return true si le statut indique un succès
*/
public boolean isSucces() {
return this == ENVOYEE || this == RECUE || this == AFFICHEE ||
this == OUVERTE || this == LUE || this == ACTION_EXECUTEE;
}
/**
* Vérifie si le statut indique une erreur
*
* @return true si le statut indique une erreur
*/
public boolean isErreur() {
return this == ECHEC_ENVOI || this == ERREUR_TECHNIQUE ||
this == DESTINATAIRE_INVALIDE || this == TOKEN_INVALIDE || this == QUOTA_DEPASSE;
}
/**
* Vérifie si le statut indique un état en cours
*
* @return true si le statut indique un traitement en cours
*/
public boolean isEnCours() {
return this == PROGRAMMEE || this == EN_ATTENTE || this == EN_COURS_ENVOI;
}
/**
* Vérifie si le statut indique un état final
*
* @return true si le statut est final (pas de transition possible)
*/
public boolean isFinal() {
return this == SUPPRIMEE || this == ARCHIVEE || this == EXPIREE ||
this == ANNULEE || isErreur();
}
/**
* Vérifie si le statut permet la modification
*
* @return true si la notification peut encore être modifiée
*/
public boolean permetModification() {
return this == BROUILLON || this == PROGRAMMEE;
}
/**
* Vérifie si le statut permet l'annulation
*
* @return true si la notification peut être annulée
*/
public boolean permetAnnulation() {
return this == PROGRAMMEE || this == EN_ATTENTE;
}
/**
* Retourne la priorité d'affichage du statut
*
* @return La priorité (1=haute, 5=basse)
*/
public int getPrioriteAffichage() {
if (isErreur()) return 1;
if (necessiteAttention) return 2;
if (isEnCours()) return 3;
if (isSucces()) return 4;
return 5;
}
/**
* Retourne les statuts suivants possibles
*
* @return Un tableau des statuts de transition possibles
*/
public StatutNotification[] getStatutsSuivantsPossibles() {
return switch (this) {
case BROUILLON -> new StatutNotification[]{PROGRAMMEE, EN_ATTENTE, ANNULEE};
case PROGRAMMEE -> new StatutNotification[]{EN_ATTENTE, EN_COURS_ENVOI, ANNULEE};
case EN_ATTENTE -> new StatutNotification[]{EN_COURS_ENVOI, ECHEC_ENVOI, ANNULEE};
case EN_COURS_ENVOI -> new StatutNotification[]{ENVOYEE, PARTIELLEMENT_ENVOYEE, ECHEC_ENVOI};
case ENVOYEE -> new StatutNotification[]{RECUE, ECHEC_ENVOI};
case RECUE -> new StatutNotification[]{AFFICHEE, IGNOREE};
case AFFICHEE -> new StatutNotification[]{OUVERTE, LUE, NON_LUE, IGNOREE};
case OUVERTE -> new StatutNotification[]{LUE, ACTION_EXECUTEE, MARQUEE_IMPORTANTE};
case NON_LUE -> new StatutNotification[]{LUE, OUVERTE, SUPPRIMEE, ARCHIVEE};
case LUE -> new StatutNotification[]{ACTION_EXECUTEE, MARQUEE_IMPORTANTE, SUPPRIMEE, ARCHIVEE};
default -> new StatutNotification[]{};
};
}
/**
* Trouve un statut par son code
*
* @param code Le code du statut
* @return Le statut correspondant ou null si non trouvé
*/
public static StatutNotification parCode(String code) {
for (StatutNotification statut : values()) {
if (statut.getCode().equals(code)) {
return statut;
}
}
return null;
}
/**
* Retourne tous les statuts visibles à l'utilisateur
*
* @return Un tableau des statuts visibles
*/
public static StatutNotification[] getStatutsVisibles() {
return java.util.Arrays.stream(values())
.filter(StatutNotification::isVisibleUtilisateur)
.toArray(StatutNotification[]::new);
}
/**
* Retourne tous les statuts d'erreur
*
* @return Un tableau des statuts d'erreur
*/
public static StatutNotification[] getStatutsErreur() {
return java.util.Arrays.stream(values())
.filter(StatutNotification::isErreur)
.toArray(StatutNotification[]::new);
// === STATUTS DE CRÉATION ===
BROUILLON(
"Brouillon",
"draft",
"La notification est en cours de création",
"edit",
"#9E9E9E",
false,
false),
PROGRAMMEE(
"Programmée",
"scheduled",
"La notification est programmée pour envoi ultérieur",
"schedule",
"#FF9800",
false,
false),
EN_ATTENTE(
"En attente",
"pending",
"La notification est en attente d'envoi",
"hourglass_empty",
"#FF9800",
false,
false),
// === STATUTS D'ENVOI ===
EN_COURS_ENVOI(
"En cours d'envoi",
"sending",
"La notification est en cours d'envoi",
"send",
"#2196F3",
false,
false),
ENVOYEE(
"Envoyée",
"sent",
"La notification a été envoyée avec succès",
"check_circle",
"#4CAF50",
true,
false),
ECHEC_ENVOI(
"Échec d'envoi",
"failed",
"L'envoi de la notification a échoué",
"error",
"#F44336",
true,
true),
PARTIELLEMENT_ENVOYEE(
"Partiellement envoyée",
"partial",
"La notification a été envoyée à certains destinataires seulement",
"warning",
"#FF9800",
true,
true),
// === STATUTS DE RÉCEPTION ===
RECUE(
"Reçue",
"received",
"La notification a été reçue par l'appareil",
"download_done",
"#4CAF50",
true,
false),
AFFICHEE(
"Affichée",
"displayed",
"La notification a été affichée à l'utilisateur",
"visibility",
"#2196F3",
true,
false),
OUVERTE(
"Ouverte",
"opened",
"L'utilisateur a ouvert la notification",
"open_in_new",
"#4CAF50",
true,
false),
IGNOREE(
"Ignorée",
"ignored",
"La notification a été ignorée par l'utilisateur",
"visibility_off",
"#9E9E9E",
true,
false),
// === STATUTS D'INTERACTION ===
LUE(
"Lue",
"read",
"La notification a été lue par l'utilisateur",
"mark_email_read",
"#4CAF50",
true,
false),
NON_LUE(
"Non lue",
"unread",
"La notification n'a pas encore été lue",
"mark_email_unread",
"#FF9800",
true,
false),
MARQUEE_IMPORTANTE(
"Marquée importante",
"starred",
"L'utilisateur a marqué la notification comme importante",
"star",
"#FF9800",
true,
false),
ACTION_EXECUTEE(
"Action exécutée",
"action_done",
"L'utilisateur a exécuté l'action demandée",
"task_alt",
"#4CAF50",
true,
false),
// === STATUTS DE GESTION ===
SUPPRIMEE(
"Supprimée",
"deleted",
"La notification a été supprimée par l'utilisateur",
"delete",
"#F44336",
false,
false),
ARCHIVEE(
"Archivée", "archived", "La notification a été archivée", "archive", "#9E9E9E", false, false),
EXPIREE(
"Expirée",
"expired",
"La notification a dépassé sa durée de vie",
"schedule",
"#9E9E9E",
false,
false),
ANNULEE(
"Annulée",
"cancelled",
"L'envoi de la notification a été annulé",
"cancel",
"#F44336",
false,
true),
// === STATUTS D'ERREUR ===
ERREUR_TECHNIQUE(
"Erreur technique",
"error",
"Une erreur technique a empêché le traitement",
"bug_report",
"#F44336",
false,
true),
DESTINATAIRE_INVALIDE(
"Destinataire invalide",
"invalid_recipient",
"Le destinataire n'est pas valide",
"person_off",
"#F44336",
false,
true),
TOKEN_INVALIDE(
"Token invalide",
"invalid_token",
"Le token FCM du destinataire est invalide",
"key_off",
"#F44336",
false,
true),
QUOTA_DEPASSE(
"Quota dépassé",
"quota_exceeded",
"Le quota d'envoi a été dépassé",
"block",
"#F44336",
false,
true);
private final String libelle;
private final String code;
private final String description;
private final String icone;
private final String couleur;
private final boolean visibleUtilisateur;
private final boolean necessiteAttention;
/**
* Constructeur de l'énumération StatutNotification
*
* @param libelle Le libellé affiché à l'utilisateur
* @param code Le code technique du statut
* @param description La description détaillée du statut
* @param icone L'icône Material Design
* @param couleur La couleur hexadécimale
* @param visibleUtilisateur true si visible à l'utilisateur final
* @param necessiteAttention true si le statut nécessite une attention particulière
*/
StatutNotification(
String libelle,
String code,
String description,
String icone,
String couleur,
boolean visibleUtilisateur,
boolean necessiteAttention) {
this.libelle = libelle;
this.code = code;
this.description = description;
this.icone = icone;
this.couleur = couleur;
this.visibleUtilisateur = visibleUtilisateur;
this.necessiteAttention = necessiteAttention;
}
/**
* Retourne le libellé du statut
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne le code technique du statut
*
* @return Le code technique
*/
public String getCode() {
return code;
}
/**
* Retourne la description du statut
*
* @return La description détaillée
*/
public String getDescription() {
return description;
}
/**
* Retourne l'icône du statut
*
* @return L'icône Material Design
*/
public String getIcone() {
return icone;
}
/**
* Retourne la couleur du statut
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return couleur;
}
/**
* Vérifie si le statut est visible à l'utilisateur final
*
* @return true si visible à l'utilisateur
*/
public boolean isVisibleUtilisateur() {
return visibleUtilisateur;
}
/**
* Vérifie si le statut nécessite une attention particulière
*
* @return true si le statut nécessite attention
*/
public boolean isNecessiteAttention() {
return necessiteAttention;
}
/**
* Vérifie si le statut indique un succès
*
* @return true si le statut indique un succès
*/
public boolean isSucces() {
return this == ENVOYEE
|| this == RECUE
|| this == AFFICHEE
|| this == OUVERTE
|| this == LUE
|| this == ACTION_EXECUTEE;
}
/**
* Vérifie si le statut indique une erreur
*
* @return true si le statut indique une erreur
*/
public boolean isErreur() {
return this == ECHEC_ENVOI
|| this == ERREUR_TECHNIQUE
|| this == DESTINATAIRE_INVALIDE
|| this == TOKEN_INVALIDE
|| this == QUOTA_DEPASSE;
}
/**
* Vérifie si le statut indique un état en cours
*
* @return true si le statut indique un traitement en cours
*/
public boolean isEnCours() {
return this == PROGRAMMEE || this == EN_ATTENTE || this == EN_COURS_ENVOI;
}
/**
* Vérifie si le statut indique un état final
*
* @return true si le statut est final (pas de transition possible)
*/
public boolean isFinal() {
return this == SUPPRIMEE
|| this == ARCHIVEE
|| this == EXPIREE
|| this == ANNULEE
|| isErreur();
}
/**
* Vérifie si le statut permet la modification
*
* @return true si la notification peut encore être modifiée
*/
public boolean permetModification() {
return this == BROUILLON || this == PROGRAMMEE;
}
/**
* Vérifie si le statut permet l'annulation
*
* @return true si la notification peut être annulée
*/
public boolean permetAnnulation() {
return this == PROGRAMMEE || this == EN_ATTENTE;
}
/**
* Retourne la priorité d'affichage du statut
*
* @return La priorité (1=haute, 5=basse)
*/
public int getPrioriteAffichage() {
if (isErreur()) return 1;
if (necessiteAttention) return 2;
if (isEnCours()) return 3;
if (isSucces()) return 4;
return 5;
}
/**
* Retourne les statuts suivants possibles
*
* @return Un tableau des statuts de transition possibles
*/
public StatutNotification[] getStatutsSuivantsPossibles() {
return switch (this) {
case BROUILLON -> new StatutNotification[] {PROGRAMMEE, EN_ATTENTE, ANNULEE};
case PROGRAMMEE -> new StatutNotification[] {EN_ATTENTE, EN_COURS_ENVOI, ANNULEE};
case EN_ATTENTE -> new StatutNotification[] {EN_COURS_ENVOI, ECHEC_ENVOI, ANNULEE};
case EN_COURS_ENVOI -> new StatutNotification[] {ENVOYEE, PARTIELLEMENT_ENVOYEE, ECHEC_ENVOI};
case ENVOYEE -> new StatutNotification[] {RECUE, ECHEC_ENVOI};
case RECUE -> new StatutNotification[] {AFFICHEE, IGNOREE};
case AFFICHEE -> new StatutNotification[] {OUVERTE, LUE, NON_LUE, IGNOREE};
case OUVERTE -> new StatutNotification[] {LUE, ACTION_EXECUTEE, MARQUEE_IMPORTANTE};
case NON_LUE -> new StatutNotification[] {LUE, OUVERTE, SUPPRIMEE, ARCHIVEE};
case LUE ->
new StatutNotification[] {ACTION_EXECUTEE, MARQUEE_IMPORTANTE, SUPPRIMEE, ARCHIVEE};
default -> new StatutNotification[] {};
};
}
/**
* Trouve un statut par son code
*
* @param code Le code du statut
* @return Le statut correspondant ou null si non trouvé
*/
public static StatutNotification parCode(String code) {
for (StatutNotification statut : values()) {
if (statut.getCode().equals(code)) {
return statut;
}
}
return null;
}
/**
* Retourne tous les statuts visibles à l'utilisateur
*
* @return Un tableau des statuts visibles
*/
public static StatutNotification[] getStatutsVisibles() {
return java.util.Arrays.stream(values())
.filter(StatutNotification::isVisibleUtilisateur)
.toArray(StatutNotification[]::new);
}
/**
* Retourne tous les statuts d'erreur
*
* @return Un tableau des statuts d'erreur
*/
public static StatutNotification[] getStatutsErreur() {
return java.util.Arrays.stream(values())
.filter(StatutNotification::isErreur)
.toArray(StatutNotification[]::new);
}
}

View File

@@ -2,260 +2,289 @@ package dev.lions.unionflow.server.api.enums.notification;
/**
* Énumération des types de notifications disponibles dans UnionFlow
*
* Cette énumération définit les différents types de notifications qui peuvent être
* envoyées aux utilisateurs de l'application UnionFlow.
*
*
* <p>Cette énumération définit les différents types de notifications qui peuvent être envoyées aux
* utilisateurs de l'application UnionFlow.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
public enum TypeNotification {
// === NOTIFICATIONS ÉVÉNEMENTS ===
NOUVEL_EVENEMENT("Nouvel événement", "evenements", "info", "event", "#FF9800", true, true),
RAPPEL_EVENEMENT("Rappel d'événement", "evenements", "reminder", "schedule", "#2196F3", true, true),
EVENEMENT_ANNULE("Événement annulé", "evenements", "warning", "event_busy", "#F44336", true, true),
EVENEMENT_MODIFIE("Événement modifié", "evenements", "info", "edit", "#FF9800", true, false),
INSCRIPTION_CONFIRMEE("Inscription confirmée", "evenements", "success", "check_circle", "#4CAF50", true, false),
INSCRIPTION_REFUSEE("Inscription refusée", "evenements", "error", "cancel", "#F44336", true, false),
LISTE_ATTENTE("Mis en liste d'attente", "evenements", "info", "hourglass_empty", "#FF9800", true, false),
// === NOTIFICATIONS COTISATIONS ===
COTISATION_DUE("Cotisation due", "cotisations", "reminder", "payment", "#FF5722", true, true),
COTISATION_PAYEE("Cotisation payée", "cotisations", "success", "paid", "#4CAF50", true, false),
COTISATION_RETARD("Cotisation en retard", "cotisations", "warning", "schedule", "#F44336", true, true),
RAPPEL_COTISATION("Rappel de cotisation", "cotisations", "reminder", "notifications", "#FF9800", true, true),
PAIEMENT_CONFIRME("Paiement confirmé", "cotisations", "success", "check_circle", "#4CAF50", true, false),
PAIEMENT_ECHOUE("Paiement échoué", "cotisations", "error", "error", "#F44336", true, true),
// === NOTIFICATIONS SOLIDARITÉ ===
NOUVELLE_DEMANDE_AIDE("Nouvelle demande d'aide", "solidarite", "info", "help", "#E91E63", false, true),
DEMANDE_AIDE_APPROUVEE("Demande d'aide approuvée", "solidarite", "success", "thumb_up", "#4CAF50", true, false),
DEMANDE_AIDE_REFUSEE("Demande d'aide refusée", "solidarite", "error", "thumb_down", "#F44336", true, false),
AIDE_DISPONIBLE("Aide disponible", "solidarite", "info", "volunteer_activism", "#E91E63", true, false),
APPEL_SOLIDARITE("Appel à la solidarité", "solidarite", "urgent", "campaign", "#E91E63", true, true),
// === NOTIFICATIONS MEMBRES ===
NOUVEAU_MEMBRE("Nouveau membre", "membres", "info", "person_add", "#2196F3", false, false),
ANNIVERSAIRE_MEMBRE("Anniversaire de membre", "membres", "celebration", "cake", "#FF9800", true, false),
MEMBRE_INACTIF("Membre inactif", "membres", "warning", "person_off", "#FF5722", false, false),
REACTIVATION_MEMBRE("Réactivation de membre", "membres", "success", "person", "#4CAF50", false, false),
// === NOTIFICATIONS ORGANISATION ===
ANNONCE_GENERALE("Annonce générale", "organisation", "info", "campaign", "#2196F3", true, true),
REUNION_PROGRAMMEE("Réunion programmée", "organisation", "info", "groups", "#2196F3", true, true),
CHANGEMENT_REGLEMENT("Changement de règlement", "organisation", "important", "gavel", "#FF5722", true, true),
ELECTION_OUVERTE("Élection ouverte", "organisation", "info", "how_to_vote", "#2196F3", true, true),
RESULTAT_ELECTION("Résultat d'élection", "organisation", "info", "poll", "#4CAF50", true, false),
// === NOTIFICATIONS SYSTÈME ===
MISE_A_JOUR_APP("Mise à jour disponible", "systeme", "info", "system_update", "#2196F3", true, false),
MAINTENANCE_PROGRAMMEE("Maintenance programmée", "systeme", "warning", "build", "#FF9800", true, true),
PROBLEME_TECHNIQUE("Problème technique", "systeme", "error", "error", "#F44336", true, true),
SAUVEGARDE_REUSSIE("Sauvegarde réussie", "systeme", "success", "backup", "#4CAF50", false, false),
// === NOTIFICATIONS PERSONNALISÉES ===
MESSAGE_PRIVE("Message privé", "messages", "info", "mail", "#2196F3", true, false),
MENTION("Mention", "messages", "info", "alternate_email", "#FF9800", true, false),
COMMENTAIRE("Nouveau commentaire", "messages", "info", "comment", "#2196F3", true, false),
// === NOTIFICATIONS GÉOLOCALISÉES ===
EVENEMENT_PROXIMITE("Événement à proximité", "geolocalisation", "info", "location_on", "#4CAF50", true, false),
MEMBRE_PROXIMITE("Membre à proximité", "geolocalisation", "info", "people", "#2196F3", true, false),
URGENCE_LOCALE("Urgence locale", "geolocalisation", "urgent", "warning", "#F44336", true, true);
private final String libelle;
private final String categorie;
private final String priorite;
private final String icone;
private final String couleur;
private final boolean visibleUtilisateur;
private final boolean activeeParDefaut;
/**
* Constructeur de l'énumération TypeNotification
*
* @param libelle Le libellé affiché à l'utilisateur
* @param categorie La catégorie de la notification
* @param priorite Le niveau de priorité (info, reminder, warning, error, success, urgent, important, celebration)
* @param icone L'icône Material Design
* @param couleur La couleur hexadécimale
* @param visibleUtilisateur true si visible dans les préférences utilisateur
* @param activeeParDefaut true si activée par défaut
*/
TypeNotification(String libelle, String categorie, String priorite, String icone, String couleur,
boolean visibleUtilisateur, boolean activeeParDefaut) {
this.libelle = libelle;
this.categorie = categorie;
this.priorite = priorite;
this.icone = icone;
this.couleur = couleur;
this.visibleUtilisateur = visibleUtilisateur;
this.activeeParDefaut = activeeParDefaut;
}
/**
* Retourne le libellé de la notification
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne la catégorie de la notification
*
* @return La catégorie (evenements, cotisations, solidarite, etc.)
*/
public String getCategorie() {
return categorie;
}
/**
* Retourne la priorité de la notification
*
* @return Le niveau de priorité
*/
public String getPriorite() {
return priorite;
}
/**
* Retourne l'icône de la notification
*
* @return L'icône Material Design
*/
public String getIcone() {
return icone;
}
/**
* Retourne la couleur de la notification
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return couleur;
}
/**
* Vérifie si la notification est visible dans les préférences utilisateur
*
* @return true si visible dans les préférences
*/
public boolean isVisibleUtilisateur() {
return visibleUtilisateur;
}
/**
* Vérifie si la notification est activée par défaut
*
* @return true si activée par défaut
*/
public boolean isActiveeParDefaut() {
return activeeParDefaut;
}
/**
* Vérifie si la notification est critique (urgent ou error)
*
* @return true si la notification est critique
*/
public boolean isCritique() {
return "urgent".equals(priorite) || "error".equals(priorite);
}
/**
* Vérifie si la notification est un rappel
*
* @return true si c'est un rappel
*/
public boolean isRappel() {
return "reminder".equals(priorite);
}
/**
* Vérifie si la notification est positive (success ou celebration)
*
* @return true si la notification est positive
*/
public boolean isPositive() {
return "success".equals(priorite) || "celebration".equals(priorite);
}
/**
* Retourne le niveau de priorité numérique pour le tri
*
* @return Niveau de priorité (1=urgent, 2=error, 3=warning, 4=important, 5=reminder, 6=info, 7=success, 8=celebration)
*/
public int getNiveauPriorite() {
return switch (priorite) {
case "urgent" -> 1;
case "error" -> 2;
case "warning" -> 3;
case "important" -> 4;
case "reminder" -> 5;
case "info" -> 6;
case "success" -> 7;
case "celebration" -> 8;
default -> 6;
};
}
/**
* Retourne le délai d'expiration par défaut en heures
*
* @return Délai d'expiration en heures
*/
public int getDelaiExpirationHeures() {
return switch (priorite) {
case "urgent" -> 1; // 1 heure
case "error" -> 24; // 24 heures
case "warning" -> 48; // 48 heures
case "important" -> 72; // 72 heures
case "reminder" -> 24; // 24 heures
case "info" -> 168; // 1 semaine
case "success" -> 48; // 48 heures
case "celebration" -> 72; // 72 heures
default -> 168;
};
}
/**
* Vérifie si la notification doit vibrer
*
* @return true si la notification doit faire vibrer l'appareil
*/
public boolean doitVibrer() {
return isCritique() || isRappel();
}
/**
* Vérifie si la notification doit émettre un son
*
* @return true si la notification doit émettre un son
*/
public boolean doitEmettreSon() {
return isCritique() || isRappel() || "important".equals(priorite);
}
/**
* Retourne le canal de notification Android approprié
*
* @return L'ID du canal de notification
*/
public String getCanalNotification() {
return switch (priorite) {
case "urgent" -> "URGENT_CHANNEL";
case "error" -> "ERROR_CHANNEL";
case "warning" -> "WARNING_CHANNEL";
case "important" -> "IMPORTANT_CHANNEL";
case "reminder" -> "REMINDER_CHANNEL";
case "success" -> "SUCCESS_CHANNEL";
case "celebration" -> "CELEBRATION_CHANNEL";
default -> "DEFAULT_CHANNEL";
};
}
// === NOTIFICATIONS ÉVÉNEMENTS ===
NOUVEL_EVENEMENT("Nouvel événement", "evenements", "info", "event", "#FF9800", true, true),
RAPPEL_EVENEMENT(
"Rappel d'événement", "evenements", "reminder", "schedule", "#2196F3", true, true),
EVENEMENT_ANNULE(
"Événement annulé", "evenements", "warning", "event_busy", "#F44336", true, true),
EVENEMENT_MODIFIE("Événement modifié", "evenements", "info", "edit", "#FF9800", true, false),
INSCRIPTION_CONFIRMEE(
"Inscription confirmée", "evenements", "success", "check_circle", "#4CAF50", true, false),
INSCRIPTION_REFUSEE(
"Inscription refusée", "evenements", "error", "cancel", "#F44336", true, false),
LISTE_ATTENTE(
"Mis en liste d'attente", "evenements", "info", "hourglass_empty", "#FF9800", true, false),
// === NOTIFICATIONS COTISATIONS ===
COTISATION_DUE("Cotisation due", "cotisations", "reminder", "payment", "#FF5722", true, true),
COTISATION_PAYEE("Cotisation payée", "cotisations", "success", "paid", "#4CAF50", true, false),
COTISATION_RETARD(
"Cotisation en retard", "cotisations", "warning", "schedule", "#F44336", true, true),
RAPPEL_COTISATION(
"Rappel de cotisation", "cotisations", "reminder", "notifications", "#FF9800", true, true),
PAIEMENT_CONFIRME(
"Paiement confirmé", "cotisations", "success", "check_circle", "#4CAF50", true, false),
PAIEMENT_ECHOUE("Paiement échoué", "cotisations", "error", "error", "#F44336", true, true),
// === NOTIFICATIONS SOLIDARITÉ ===
NOUVELLE_DEMANDE_AIDE(
"Nouvelle demande d'aide", "solidarite", "info", "help", "#E91E63", false, true),
DEMANDE_AIDE_APPROUVEE(
"Demande d'aide approuvée", "solidarite", "success", "thumb_up", "#4CAF50", true, false),
DEMANDE_AIDE_REFUSEE(
"Demande d'aide refusée", "solidarite", "error", "thumb_down", "#F44336", true, false),
AIDE_DISPONIBLE(
"Aide disponible", "solidarite", "info", "volunteer_activism", "#E91E63", true, false),
APPEL_SOLIDARITE(
"Appel à la solidarité", "solidarite", "urgent", "campaign", "#E91E63", true, true),
// === NOTIFICATIONS MEMBRES ===
NOUVEAU_MEMBRE("Nouveau membre", "membres", "info", "person_add", "#2196F3", false, false),
ANNIVERSAIRE_MEMBRE(
"Anniversaire de membre", "membres", "celebration", "cake", "#FF9800", true, false),
MEMBRE_INACTIF("Membre inactif", "membres", "warning", "person_off", "#FF5722", false, false),
REACTIVATION_MEMBRE(
"Réactivation de membre", "membres", "success", "person", "#4CAF50", false, false),
// === NOTIFICATIONS ORGANISATION ===
ANNONCE_GENERALE("Annonce générale", "organisation", "info", "campaign", "#2196F3", true, true),
REUNION_PROGRAMMEE("Réunion programmée", "organisation", "info", "groups", "#2196F3", true, true),
CHANGEMENT_REGLEMENT(
"Changement de règlement", "organisation", "important", "gavel", "#FF5722", true, true),
ELECTION_OUVERTE(
"Élection ouverte", "organisation", "info", "how_to_vote", "#2196F3", true, true),
RESULTAT_ELECTION("Résultat d'élection", "organisation", "info", "poll", "#4CAF50", true, false),
// === NOTIFICATIONS SYSTÈME ===
MISE_A_JOUR_APP(
"Mise à jour disponible", "systeme", "info", "system_update", "#2196F3", true, false),
MAINTENANCE_PROGRAMMEE(
"Maintenance programmée", "systeme", "warning", "build", "#FF9800", true, true),
PROBLEME_TECHNIQUE("Problème technique", "systeme", "error", "error", "#F44336", true, true),
SAUVEGARDE_REUSSIE("Sauvegarde réussie", "systeme", "success", "backup", "#4CAF50", false, false),
// === NOTIFICATIONS PERSONNALISÉES ===
MESSAGE_PRIVE("Message privé", "messages", "info", "mail", "#2196F3", true, false),
MENTION("Mention", "messages", "info", "alternate_email", "#FF9800", true, false),
COMMENTAIRE("Nouveau commentaire", "messages", "info", "comment", "#2196F3", true, false),
// === NOTIFICATIONS GÉOLOCALISÉES ===
EVENEMENT_PROXIMITE(
"Événement à proximité", "geolocalisation", "info", "location_on", "#4CAF50", true, false),
MEMBRE_PROXIMITE(
"Membre à proximité", "geolocalisation", "info", "people", "#2196F3", true, false),
URGENCE_LOCALE("Urgence locale", "geolocalisation", "urgent", "warning", "#F44336", true, true);
private final String libelle;
private final String categorie;
private final String priorite;
private final String icone;
private final String couleur;
private final boolean visibleUtilisateur;
private final boolean activeeParDefaut;
/**
* Constructeur de l'énumération TypeNotification
*
* @param libelle Le libellé affiché à l'utilisateur
* @param categorie La catégorie de la notification
* @param priorite Le niveau de priorité (info, reminder, warning, error, success, urgent,
* important, celebration)
* @param icone L'icône Material Design
* @param couleur La couleur hexadécimale
* @param visibleUtilisateur true si visible dans les préférences utilisateur
* @param activeeParDefaut true si activée par défaut
*/
TypeNotification(
String libelle,
String categorie,
String priorite,
String icone,
String couleur,
boolean visibleUtilisateur,
boolean activeeParDefaut) {
this.libelle = libelle;
this.categorie = categorie;
this.priorite = priorite;
this.icone = icone;
this.couleur = couleur;
this.visibleUtilisateur = visibleUtilisateur;
this.activeeParDefaut = activeeParDefaut;
}
/**
* Retourne le libellé de la notification
*
* @return Le libellé affiché à l'utilisateur
*/
public String getLibelle() {
return libelle;
}
/**
* Retourne la catégorie de la notification
*
* @return La catégorie (evenements, cotisations, solidarite, etc.)
*/
public String getCategorie() {
return categorie;
}
/**
* Retourne la priorité de la notification
*
* @return Le niveau de priorité
*/
public String getPriorite() {
return priorite;
}
/**
* Retourne l'icône de la notification
*
* @return L'icône Material Design
*/
public String getIcone() {
return icone;
}
/**
* Retourne la couleur de la notification
*
* @return Le code couleur hexadécimal
*/
public String getCouleur() {
return couleur;
}
/**
* Vérifie si la notification est visible dans les préférences utilisateur
*
* @return true si visible dans les préférences
*/
public boolean isVisibleUtilisateur() {
return visibleUtilisateur;
}
/**
* Vérifie si la notification est activée par défaut
*
* @return true si activée par défaut
*/
public boolean isActiveeParDefaut() {
return activeeParDefaut;
}
/**
* Vérifie si la notification est critique (urgent ou error)
*
* @return true si la notification est critique
*/
public boolean isCritique() {
return "urgent".equals(priorite) || "error".equals(priorite);
}
/**
* Vérifie si la notification est un rappel
*
* @return true si c'est un rappel
*/
public boolean isRappel() {
return "reminder".equals(priorite);
}
/**
* Vérifie si la notification est positive (success ou celebration)
*
* @return true si la notification est positive
*/
public boolean isPositive() {
return "success".equals(priorite) || "celebration".equals(priorite);
}
/**
* Retourne le niveau de priorité numérique pour le tri
*
* @return Niveau de priorité (1=urgent, 2=error, 3=warning, 4=important, 5=reminder, 6=info,
* 7=success, 8=celebration)
*/
public int getNiveauPriorite() {
return switch (priorite) {
case "urgent" -> 1;
case "error" -> 2;
case "warning" -> 3;
case "important" -> 4;
case "reminder" -> 5;
case "info" -> 6;
case "success" -> 7;
case "celebration" -> 8;
default -> 6;
};
}
/**
* Retourne le délai d'expiration par défaut en heures
*
* @return Délai d'expiration en heures
*/
public int getDelaiExpirationHeures() {
return switch (priorite) {
case "urgent" -> 1; // 1 heure
case "error" -> 24; // 24 heures
case "warning" -> 48; // 48 heures
case "important" -> 72; // 72 heures
case "reminder" -> 24; // 24 heures
case "info" -> 168; // 1 semaine
case "success" -> 48; // 48 heures
case "celebration" -> 72; // 72 heures
default -> 168;
};
}
/**
* Vérifie si la notification doit vibrer
*
* @return true si la notification doit faire vibrer l'appareil
*/
public boolean doitVibrer() {
return isCritique() || isRappel();
}
/**
* Vérifie si la notification doit émettre un son
*
* @return true si la notification doit émettre un son
*/
public boolean doitEmettreSon() {
return isCritique() || isRappel() || "important".equals(priorite);
}
/**
* Retourne le canal de notification Android approprié
*
* @return L'ID du canal de notification
*/
public String getCanalNotification() {
return switch (priorite) {
case "urgent" -> "URGENT_CHANNEL";
case "error" -> "ERROR_CHANNEL";
case "warning" -> "WARNING_CHANNEL";
case "important" -> "IMPORTANT_CHANNEL";
case "reminder" -> "REMINDER_CHANNEL";
case "success" -> "SUCCESS_CHANNEL";
case "celebration" -> "CELEBRATION_CHANNEL";
default -> "DEFAULT_CHANNEL";
};
}
}

View File

@@ -2,214 +2,260 @@ package dev.lions.unionflow.server.api.enums.solidarite;
/**
* Énumération des priorités d'aide dans le système de solidarité
*
* Cette énumération définit les niveaux de priorité pour les demandes d'aide,
* permettant de prioriser le traitement selon l'urgence de la situation.
*
*
* <p>Cette énumération définit les niveaux de priorité pour les demandes d'aide, permettant de
* prioriser le traitement selon l'urgence de la situation.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
public enum PrioriteAide {
CRITIQUE("Critique", "critical", 1, "Situation critique nécessitant une intervention immédiate",
"#F44336", "emergency", 24, true, true),
URGENTE("Urgente", "urgent", 2, "Situation urgente nécessitant une réponse rapide",
"#FF5722", "priority_high", 72, true, false),
ELEVEE("Élevée", "high", 3, "Priorité élevée, traitement dans les meilleurs délais",
"#FF9800", "keyboard_arrow_up", 168, false, false),
NORMALE("Normale", "normal", 4, "Priorité normale, traitement selon les délais standards",
"#2196F3", "remove", 336, false, false),
FAIBLE("Faible", "low", 5, "Priorité faible, traitement quand les ressources le permettent",
"#4CAF50", "keyboard_arrow_down", 720, false, false);
CRITIQUE(
"Critique",
"critical",
1,
"Situation critique nécessitant une intervention immédiate",
"#F44336",
"emergency",
24,
true,
true),
private final String libelle;
private final String code;
private final int niveau;
private final String description;
private final String couleur;
private final String icone;
private final int delaiTraitementHeures;
private final boolean notificationImmediate;
private final boolean escaladeAutomatique;
URGENTE(
"Urgente",
"urgent",
2,
"Situation urgente nécessitant une réponse rapide",
"#FF5722",
"priority_high",
72,
true,
false),
PrioriteAide(String libelle, String code, int niveau, String description, String couleur,
String icone, int delaiTraitementHeures, boolean notificationImmediate,
boolean escaladeAutomatique) {
this.libelle = libelle;
this.code = code;
this.niveau = niveau;
this.description = description;
this.couleur = couleur;
this.icone = icone;
this.delaiTraitementHeures = delaiTraitementHeures;
this.notificationImmediate = notificationImmediate;
this.escaladeAutomatique = escaladeAutomatique;
ELEVEE(
"Élevée",
"high",
3,
"Priorité élevée, traitement dans les meilleurs délais",
"#FF9800",
"keyboard_arrow_up",
168,
false,
false),
NORMALE(
"Normale",
"normal",
4,
"Priorité normale, traitement selon les délais standards",
"#2196F3",
"remove",
336,
false,
false),
FAIBLE(
"Faible",
"low",
5,
"Priorité faible, traitement quand les ressources le permettent",
"#4CAF50",
"keyboard_arrow_down",
720,
false,
false);
private final String libelle;
private final String code;
private final int niveau;
private final String description;
private final String couleur;
private final String icone;
private final int delaiTraitementHeures;
private final boolean notificationImmediate;
private final boolean escaladeAutomatique;
PrioriteAide(
String libelle,
String code,
int niveau,
String description,
String couleur,
String icone,
int delaiTraitementHeures,
boolean notificationImmediate,
boolean escaladeAutomatique) {
this.libelle = libelle;
this.code = code;
this.niveau = niveau;
this.description = description;
this.couleur = couleur;
this.icone = icone;
this.delaiTraitementHeures = delaiTraitementHeures;
this.notificationImmediate = notificationImmediate;
this.escaladeAutomatique = escaladeAutomatique;
}
// === GETTERS ===
public String getLibelle() {
return libelle;
}
public String getCode() {
return code;
}
public int getNiveau() {
return niveau;
}
public String getDescription() {
return description;
}
public String getCouleur() {
return couleur;
}
public String getIcone() {
return icone;
}
public int getDelaiTraitementHeures() {
return delaiTraitementHeures;
}
public boolean isNotificationImmediate() {
return notificationImmediate;
}
public boolean isEscaladeAutomatique() {
return escaladeAutomatique;
}
// === MÉTHODES UTILITAIRES ===
/** Vérifie si la priorité est critique ou urgente */
public boolean isUrgente() {
return this == CRITIQUE || this == URGENTE;
}
/** Vérifie si la priorité nécessite un traitement immédiat */
public boolean necessiteTraitementImmediat() {
return niveau <= 2;
}
/** Retourne la date limite de traitement */
public java.time.LocalDateTime getDateLimiteTraitement() {
return java.time.LocalDateTime.now().plusHours(delaiTraitementHeures);
}
/** Retourne la priorité suivante (escalade) */
public PrioriteAide getPrioriteEscalade() {
return switch (this) {
case FAIBLE -> NORMALE;
case NORMALE -> ELEVEE;
case ELEVEE -> URGENTE;
case URGENTE -> CRITIQUE;
case CRITIQUE -> CRITIQUE; // Déjà au maximum
};
}
/** Détermine la priorité basée sur le type d'aide */
public static PrioriteAide determinerPriorite(TypeAide typeAide) {
if (typeAide.isUrgent()) {
return switch (typeAide) {
case AIDE_FINANCIERE_URGENTE, AIDE_FRAIS_MEDICAUX -> CRITIQUE;
case HEBERGEMENT_URGENCE, AIDE_ALIMENTAIRE -> URGENTE;
default -> ELEVEE;
};
}
// === GETTERS ===
public String getLibelle() { return libelle; }
public String getCode() { return code; }
public int getNiveau() { return niveau; }
public String getDescription() { return description; }
public String getCouleur() { return couleur; }
public String getIcone() { return icone; }
public int getDelaiTraitementHeures() { return delaiTraitementHeures; }
public boolean isNotificationImmediate() { return notificationImmediate; }
public boolean isEscaladeAutomatique() { return escaladeAutomatique; }
if (typeAide.getPriorite().equals("important")) {
return ELEVEE;
}
// === MÉTHODES UTILITAIRES ===
/**
* Vérifie si la priorité est critique ou urgente
*/
public boolean isUrgente() {
return this == CRITIQUE || this == URGENTE;
}
/**
* Vérifie si la priorité nécessite un traitement immédiat
*/
public boolean necessiteTraitementImmediat() {
return niveau <= 2;
}
/**
* Retourne la date limite de traitement
*/
public java.time.LocalDateTime getDateLimiteTraitement() {
return java.time.LocalDateTime.now().plusHours(delaiTraitementHeures);
}
/**
* Retourne la priorité suivante (escalade)
*/
public PrioriteAide getPrioriteEscalade() {
return switch (this) {
case FAIBLE -> NORMALE;
case NORMALE -> ELEVEE;
case ELEVEE -> URGENTE;
case URGENTE -> CRITIQUE;
case CRITIQUE -> CRITIQUE; // Déjà au maximum
};
}
/**
* Détermine la priorité basée sur le type d'aide
*/
public static PrioriteAide determinerPriorite(TypeAide typeAide) {
if (typeAide.isUrgent()) {
return switch (typeAide) {
case AIDE_FINANCIERE_URGENTE, AIDE_FRAIS_MEDICAUX -> CRITIQUE;
case HEBERGEMENT_URGENCE, AIDE_ALIMENTAIRE -> URGENTE;
default -> ELEVEE;
};
}
if (typeAide.getPriorite().equals("important")) {
return ELEVEE;
}
return NORMALE;
}
/**
* Retourne les priorités urgentes
*/
public static java.util.List<PrioriteAide> getPrioritesUrgentes() {
return java.util.Arrays.stream(values())
.filter(PrioriteAide::isUrgente)
.collect(java.util.stream.Collectors.toList());
}
/**
* Retourne les priorités par niveau croissant
*/
public static java.util.List<PrioriteAide> getParNiveauCroissant() {
return java.util.Arrays.stream(values())
.sorted(java.util.Comparator.comparingInt(PrioriteAide::getNiveau))
.collect(java.util.stream.Collectors.toList());
}
/**
* Retourne les priorités par niveau décroissant
*/
public static java.util.List<PrioriteAide> getParNiveauDecroissant() {
return java.util.Arrays.stream(values())
.sorted(java.util.Comparator.comparingInt(PrioriteAide::getNiveau).reversed())
.collect(java.util.stream.Collectors.toList());
}
/**
* Trouve la priorité par code
*/
public static PrioriteAide parCode(String code) {
return java.util.Arrays.stream(values())
.filter(p -> p.getCode().equals(code))
.findFirst()
.orElse(NORMALE);
}
/**
* Calcule le score de priorité (plus bas = plus prioritaire)
*/
public double getScorePriorite() {
double score = niveau;
// Bonus pour notification immédiate
if (notificationImmediate) score -= 0.5;
// Bonus pour escalade automatique
if (escaladeAutomatique) score -= 0.3;
// Malus pour délai long
if (delaiTraitementHeures > 168) score += 0.2;
return score;
}
/**
* Vérifie si le délai de traitement est dépassé
*/
public boolean isDelaiDepasse(java.time.LocalDateTime dateCreation) {
java.time.LocalDateTime dateLimite = dateCreation.plusHours(delaiTraitementHeures);
return java.time.LocalDateTime.now().isAfter(dateLimite);
}
/**
* Calcule le pourcentage de temps écoulé
*/
public double getPourcentageTempsEcoule(java.time.LocalDateTime dateCreation) {
java.time.LocalDateTime maintenant = java.time.LocalDateTime.now();
java.time.LocalDateTime dateLimite = dateCreation.plusHours(delaiTraitementHeures);
long dureeTotal = java.time.Duration.between(dateCreation, dateLimite).toMinutes();
long dureeEcoulee = java.time.Duration.between(dateCreation, maintenant).toMinutes();
if (dureeTotal <= 0) return 100.0;
return Math.min(100.0, (dureeEcoulee * 100.0) / dureeTotal);
}
/**
* Retourne le message d'alerte selon le temps écoulé
*/
public String getMessageAlerte(java.time.LocalDateTime dateCreation) {
double pourcentage = getPourcentageTempsEcoule(dateCreation);
if (pourcentage >= 100) {
return "Délai de traitement dépassé !";
} else if (pourcentage >= 80) {
return "Délai de traitement bientôt dépassé";
} else if (pourcentage >= 60) {
return "Plus de la moitié du délai écoulé";
}
return null;
return NORMALE;
}
/** Retourne les priorités urgentes */
public static java.util.List<PrioriteAide> getPrioritesUrgentes() {
return java.util.Arrays.stream(values())
.filter(PrioriteAide::isUrgente)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les priorités par niveau croissant */
public static java.util.List<PrioriteAide> getParNiveauCroissant() {
return java.util.Arrays.stream(values())
.sorted(java.util.Comparator.comparingInt(PrioriteAide::getNiveau))
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les priorités par niveau décroissant */
public static java.util.List<PrioriteAide> getParNiveauDecroissant() {
return java.util.Arrays.stream(values())
.sorted(java.util.Comparator.comparingInt(PrioriteAide::getNiveau).reversed())
.collect(java.util.stream.Collectors.toList());
}
/** Trouve la priorité par code */
public static PrioriteAide parCode(String code) {
return java.util.Arrays.stream(values())
.filter(p -> p.getCode().equals(code))
.findFirst()
.orElse(NORMALE);
}
/** Calcule le score de priorité (plus bas = plus prioritaire) */
public double getScorePriorite() {
double score = niveau;
// Bonus pour notification immédiate
if (notificationImmediate) score -= 0.5;
// Bonus pour escalade automatique
if (escaladeAutomatique) score -= 0.3;
// Malus pour délai long
if (delaiTraitementHeures > 168) score += 0.2;
return score;
}
/** Vérifie si le délai de traitement est dépassé */
public boolean isDelaiDepasse(java.time.LocalDateTime dateCreation) {
java.time.LocalDateTime dateLimite = dateCreation.plusHours(delaiTraitementHeures);
return java.time.LocalDateTime.now().isAfter(dateLimite);
}
/** Calcule le pourcentage de temps écoulé */
public double getPourcentageTempsEcoule(java.time.LocalDateTime dateCreation) {
java.time.LocalDateTime maintenant = java.time.LocalDateTime.now();
java.time.LocalDateTime dateLimite = dateCreation.plusHours(delaiTraitementHeures);
long dureeTotal = java.time.Duration.between(dateCreation, dateLimite).toMinutes();
long dureeEcoulee = java.time.Duration.between(dateCreation, maintenant).toMinutes();
if (dureeTotal <= 0) return 100.0;
return Math.min(100.0, (dureeEcoulee * 100.0) / dureeTotal);
}
/** Retourne le message d'alerte selon le temps écoulé */
public String getMessageAlerte(java.time.LocalDateTime dateCreation) {
double pourcentage = getPourcentageTempsEcoule(dateCreation);
if (pourcentage >= 100) {
return "Délai de traitement dépassé !";
} else if (pourcentage >= 80) {
return "Délai de traitement bientôt dépassé";
} else if (pourcentage >= 60) {
return "Plus de la moitié du délai écoulé";
}
return null;
}
}

View File

@@ -3,8 +3,8 @@ package dev.lions.unionflow.server.api.enums.solidarite;
/**
* Énumération des statuts d'aide dans le système de solidarité
*
* Cette énumération définit les différents statuts qu'une demande d'aide
* peut avoir tout au long de son cycle de vie.
* <p>Cette énumération définit les différents statuts qu'une demande d'aide peut avoir tout au long
* de son cycle de vie.
*
* @author UnionFlow Team
* @version 1.0
@@ -12,170 +12,276 @@ package dev.lions.unionflow.server.api.enums.solidarite;
*/
public enum StatutAide {
// === STATUTS INITIAUX ===
BROUILLON("Brouillon", "draft", "La demande est en cours de rédaction", "#9E9E9E", "edit", false, false),
SOUMISE("Soumise", "submitted", "La demande a été soumise et attend validation", "#FF9800", "send", false, false),
// === STATUTS INITIAUX ===
BROUILLON(
"Brouillon",
"draft",
"La demande est en cours de rédaction",
"#9E9E9E",
"edit",
false,
false),
SOUMISE(
"Soumise",
"submitted",
"La demande a été soumise et attend validation",
"#FF9800",
"send",
false,
false),
// === STATUTS D'ÉVALUATION ===
EN_ATTENTE("En attente", "pending", "La demande est en attente d'évaluation", "#2196F3", "hourglass_empty", false, false),
EN_COURS_EVALUATION("En cours d'évaluation", "under_review", "La demande est en cours d'évaluation", "#FF9800", "rate_review", false, false),
INFORMATIONS_REQUISES("Informations requises", "info_required", "Des informations complémentaires sont requises", "#FF5722", "info", false, false),
// === STATUTS D'ÉVALUATION ===
EN_ATTENTE(
"En attente",
"pending",
"La demande est en attente d'évaluation",
"#2196F3",
"hourglass_empty",
false,
false),
EN_COURS_EVALUATION(
"En cours d'évaluation",
"under_review",
"La demande est en cours d'évaluation",
"#FF9800",
"rate_review",
false,
false),
INFORMATIONS_REQUISES(
"Informations requises",
"info_required",
"Des informations complémentaires sont requises",
"#FF5722",
"info",
false,
false),
// === STATUTS DE DÉCISION ===
APPROUVEE("Approuvée", "approved", "La demande a été approuvée", "#4CAF50", "check_circle", true, false),
APPROUVEE_PARTIELLEMENT("Approuvée partiellement", "partially_approved", "La demande a été approuvée partiellement", "#8BC34A", "check_circle_outline", true, false),
REJETEE("Rejetée", "rejected", "La demande a été rejetée", "#F44336", "cancel", true, true),
// === STATUTS DE DÉCISION ===
APPROUVEE(
"Approuvée",
"approved",
"La demande a été approuvée",
"#4CAF50",
"check_circle",
true,
false),
APPROUVEE_PARTIELLEMENT(
"Approuvée partiellement",
"partially_approved",
"La demande a été approuvée partiellement",
"#8BC34A",
"check_circle_outline",
true,
false),
REJETEE("Rejetée", "rejected", "La demande a été rejetée", "#F44336", "cancel", true, true),
// === STATUTS DE TRAITEMENT ===
EN_COURS_TRAITEMENT("En cours de traitement", "processing", "La demande approuvée est en cours de traitement", "#9C27B0", "settings", false, false),
EN_COURS_VERSEMENT("En cours de versement", "payment_processing", "Le versement est en cours", "#3F51B5", "payment", false, false),
// === STATUTS DE TRAITEMENT ===
EN_COURS_TRAITEMENT(
"En cours de traitement",
"processing",
"La demande approuvée est en cours de traitement",
"#9C27B0",
"settings",
false,
false),
EN_COURS_VERSEMENT(
"En cours de versement",
"payment_processing",
"Le versement est en cours",
"#3F51B5",
"payment",
false,
false),
// === STATUTS FINAUX ===
VERSEE("Versée", "paid", "L'aide a été versée avec succès", "#4CAF50", "paid", true, false),
LIVREE("Livrée", "delivered", "L'aide matérielle a été livrée", "#4CAF50", "local_shipping", true, false),
TERMINEE("Terminée", "completed", "L'aide a été fournie avec succès", "#4CAF50", "done_all", true, false),
// === STATUTS FINAUX ===
VERSEE("Versée", "paid", "L'aide a été versée avec succès", "#4CAF50", "paid", true, false),
LIVREE(
"Livrée",
"delivered",
"L'aide matérielle a été livrée",
"#4CAF50",
"local_shipping",
true,
false),
TERMINEE(
"Terminée",
"completed",
"L'aide a été fournie avec succès",
"#4CAF50",
"done_all",
true,
false),
// === STATUTS D'EXCEPTION ===
ANNULEE("Annulée", "cancelled", "La demande a été annulée", "#9E9E9E", "cancel", true, true),
SUSPENDUE("Suspendue", "suspended", "La demande a été suspendue temporairement", "#FF5722", "pause_circle", false, false),
EXPIREE("Expirée", "expired", "La demande a expiré", "#795548", "schedule", true, true),
// === STATUTS D'EXCEPTION ===
ANNULEE("Annulée", "cancelled", "La demande a été annulée", "#9E9E9E", "cancel", true, true),
SUSPENDUE(
"Suspendue",
"suspended",
"La demande a été suspendue temporairement",
"#FF5722",
"pause_circle",
false,
false),
EXPIREE("Expirée", "expired", "La demande a expiré", "#795548", "schedule", true, true),
// === STATUTS DE SUIVI ===
EN_SUIVI("En suivi", "follow_up", "L'aide fait l'objet d'un suivi", "#607D8B", "track_changes", false, false),
CLOTUREE("Clôturée", "closed", "Le dossier d'aide est clôturé", "#9E9E9E", "folder", true, false);
// === STATUTS DE SUIVI ===
EN_SUIVI(
"En suivi",
"follow_up",
"L'aide fait l'objet d'un suivi",
"#607D8B",
"track_changes",
false,
false),
CLOTUREE("Clôturée", "closed", "Le dossier d'aide est clôturé", "#9E9E9E", "folder", true, false);
private final String libelle;
private final String code;
private final String description;
private final String couleur;
private final String icone;
private final boolean estFinal;
private final boolean estEchec;
private final String libelle;
private final String code;
private final String description;
private final String couleur;
private final String icone;
private final boolean estFinal;
private final boolean estEchec;
StatutAide(String libelle, String code, String description, String couleur, String icone, boolean estFinal, boolean estEchec) {
this.libelle = libelle;
this.code = code;
this.description = description;
this.couleur = couleur;
this.icone = icone;
this.estFinal = estFinal;
this.estEchec = estEchec;
}
StatutAide(
String libelle,
String code,
String description,
String couleur,
String icone,
boolean estFinal,
boolean estEchec) {
this.libelle = libelle;
this.code = code;
this.description = description;
this.couleur = couleur;
this.icone = icone;
this.estFinal = estFinal;
this.estEchec = estEchec;
}
// === GETTERS ===
// === GETTERS ===
public String getLibelle() { return libelle; }
public String getCode() { return code; }
public String getDescription() { return description; }
public String getCouleur() { return couleur; }
public String getIcone() { return icone; }
public boolean isEstFinal() { return estFinal; }
public boolean isEstEchec() { return estEchec; }
public String getLibelle() {
return libelle;
}
// === MÉTHODES UTILITAIRES ===
public String getCode() {
return code;
}
/**
* Vérifie si le statut indique un succès
*/
public boolean isSucces() {
return this == VERSEE || this == LIVREE || this == TERMINEE;
}
public String getDescription() {
return description;
}
/**
* Vérifie si le statut est en cours de traitement
*/
public boolean isEnCours() {
return this == EN_COURS_EVALUATION || this == EN_COURS_TRAITEMENT || this == EN_COURS_VERSEMENT;
}
public String getCouleur() {
return couleur;
}
/**
* Vérifie si le statut permet la modification
*/
public boolean permetModification() {
return this == BROUILLON || this == INFORMATIONS_REQUISES;
}
public String getIcone() {
return icone;
}
/**
* Vérifie si le statut permet l'annulation
*/
public boolean permetAnnulation() {
return !estFinal && this != ANNULEE;
}
public boolean isEstFinal() {
return estFinal;
}
/**
* Retourne les statuts finaux
*/
public static java.util.List<StatutAide> getStatutsFinaux() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isEstFinal)
.collect(java.util.stream.Collectors.toList());
}
public boolean isEstEchec() {
return estEchec;
}
/**
* Retourne les statuts d'échec
*/
public static java.util.List<StatutAide> getStatutsEchec() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isEstEchec)
.collect(java.util.stream.Collectors.toList());
}
// === MÉTHODES UTILITAIRES ===
/**
* Retourne les statuts de succès
*/
public static java.util.List<StatutAide> getStatutsSucces() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isSucces)
.collect(java.util.stream.Collectors.toList());
}
/** Vérifie si le statut indique un succès */
public boolean isSucces() {
return this == VERSEE || this == LIVREE || this == TERMINEE;
}
/**
* Retourne les statuts en cours
*/
public static java.util.List<StatutAide> getStatutsEnCours() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isEnCours)
.collect(java.util.stream.Collectors.toList());
}
/** Vérifie si le statut est en cours de traitement */
public boolean isEnCours() {
return this == EN_COURS_EVALUATION || this == EN_COURS_TRAITEMENT || this == EN_COURS_VERSEMENT;
}
/**
* Vérifie si la transition vers un autre statut est valide
*/
public boolean peutTransitionnerVers(StatutAide nouveauStatut) {
// Règles de transition simplifiées
if (this == nouveauStatut) return false;
if (estFinal && nouveauStatut != EN_SUIVI) return false;
/** Vérifie si le statut permet la modification */
public boolean permetModification() {
return this == BROUILLON || this == INFORMATIONS_REQUISES;
}
return switch (this) {
case BROUILLON -> nouveauStatut == SOUMISE || nouveauStatut == ANNULEE;
case SOUMISE -> nouveauStatut == EN_ATTENTE || nouveauStatut == ANNULEE;
case EN_ATTENTE -> nouveauStatut == EN_COURS_EVALUATION || nouveauStatut == ANNULEE;
case EN_COURS_EVALUATION -> nouveauStatut == APPROUVEE || nouveauStatut == APPROUVEE_PARTIELLEMENT ||
nouveauStatut == REJETEE || nouveauStatut == INFORMATIONS_REQUISES ||
nouveauStatut == SUSPENDUE;
case INFORMATIONS_REQUISES -> nouveauStatut == EN_COURS_EVALUATION || nouveauStatut == ANNULEE;
case APPROUVEE, APPROUVEE_PARTIELLEMENT -> nouveauStatut == EN_COURS_TRAITEMENT || nouveauStatut == SUSPENDUE;
case EN_COURS_TRAITEMENT -> nouveauStatut == EN_COURS_VERSEMENT || nouveauStatut == LIVREE ||
nouveauStatut == TERMINEE || nouveauStatut == SUSPENDUE;
case EN_COURS_VERSEMENT -> nouveauStatut == VERSEE || nouveauStatut == SUSPENDUE;
case SUSPENDUE -> nouveauStatut == EN_COURS_EVALUATION || nouveauStatut == ANNULEE;
default -> false;
};
}
/** Vérifie si le statut permet l'annulation */
public boolean permetAnnulation() {
return !estFinal && this != ANNULEE;
}
/**
* Retourne le niveau de priorité pour l'affichage
*/
public int getNiveauPriorite() {
return switch (this) {
case INFORMATIONS_REQUISES -> 1;
case EN_COURS_EVALUATION, EN_COURS_TRAITEMENT, EN_COURS_VERSEMENT -> 2;
case APPROUVEE, APPROUVEE_PARTIELLEMENT -> 3;
case EN_ATTENTE, SOUMISE -> 4;
case SUSPENDUE -> 5;
case BROUILLON -> 6;
case EN_SUIVI -> 7;
default -> 8; // Statuts finaux
};
}
/** Retourne les statuts finaux */
public static java.util.List<StatutAide> getStatutsFinaux() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isEstFinal)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les statuts d'échec */
public static java.util.List<StatutAide> getStatutsEchec() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isEstEchec)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les statuts de succès */
public static java.util.List<StatutAide> getStatutsSucces() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isSucces)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les statuts en cours */
public static java.util.List<StatutAide> getStatutsEnCours() {
return java.util.Arrays.stream(values())
.filter(StatutAide::isEnCours)
.collect(java.util.stream.Collectors.toList());
}
/** Vérifie si la transition vers un autre statut est valide */
public boolean peutTransitionnerVers(StatutAide nouveauStatut) {
// Règles de transition simplifiées
if (this == nouveauStatut) return false;
if (estFinal && nouveauStatut != EN_SUIVI) return false;
return switch (this) {
case BROUILLON -> nouveauStatut == SOUMISE || nouveauStatut == ANNULEE;
case SOUMISE -> nouveauStatut == EN_ATTENTE || nouveauStatut == ANNULEE;
case EN_ATTENTE -> nouveauStatut == EN_COURS_EVALUATION || nouveauStatut == ANNULEE;
case EN_COURS_EVALUATION ->
nouveauStatut == APPROUVEE
|| nouveauStatut == APPROUVEE_PARTIELLEMENT
|| nouveauStatut == REJETEE
|| nouveauStatut == INFORMATIONS_REQUISES
|| nouveauStatut == SUSPENDUE;
case INFORMATIONS_REQUISES ->
nouveauStatut == EN_COURS_EVALUATION || nouveauStatut == ANNULEE;
case APPROUVEE, APPROUVEE_PARTIELLEMENT ->
nouveauStatut == EN_COURS_TRAITEMENT || nouveauStatut == SUSPENDUE;
case EN_COURS_TRAITEMENT ->
nouveauStatut == EN_COURS_VERSEMENT
|| nouveauStatut == LIVREE
|| nouveauStatut == TERMINEE
|| nouveauStatut == SUSPENDUE;
case EN_COURS_VERSEMENT -> nouveauStatut == VERSEE || nouveauStatut == SUSPENDUE;
case SUSPENDUE -> nouveauStatut == EN_COURS_EVALUATION || nouveauStatut == ANNULEE;
default -> false;
};
}
/** Retourne le niveau de priorité pour l'affichage */
public int getNiveauPriorite() {
return switch (this) {
case INFORMATIONS_REQUISES -> 1;
case EN_COURS_EVALUATION, EN_COURS_TRAITEMENT, EN_COURS_VERSEMENT -> 2;
case APPROUVEE, APPROUVEE_PARTIELLEMENT -> 3;
case EN_ATTENTE, SOUMISE -> 4;
case SUSPENDUE -> 5;
case BROUILLON -> 6;
case EN_SUIVI -> 7;
default -> 8; // Statuts finaux
};
}
}

View File

@@ -3,8 +3,8 @@ package dev.lions.unionflow.server.api.enums.solidarite;
/**
* Énumération des types d'aide disponibles dans le système de solidarité
*
* Cette énumération définit les différents types d'aide que les membres
* peuvent demander ou proposer dans le cadre du système de solidarité.
* <p>Cette énumération définit les différents types d'aide que les membres peuvent demander ou
* proposer dans le cadre du système de solidarité.
*
* @author UnionFlow Team
* @version 1.0
@@ -12,273 +12,504 @@ package dev.lions.unionflow.server.api.enums.solidarite;
*/
public enum TypeAide {
// === AIDE FINANCIÈRE ===
AIDE_FINANCIERE_URGENTE("Aide financière urgente", "financiere", "urgent",
"Aide financière pour situation d'urgence", "emergency_fund", "#F44336",
true, true, 5000.0, 50000.0, 7),
// === AIDE FINANCIÈRE ===
AIDE_FINANCIERE_URGENTE(
"Aide financière urgente",
"financiere",
"urgent",
"Aide financière pour situation d'urgence",
"emergency_fund",
"#F44336",
true,
true,
5000.0,
50000.0,
7),
PRET_SANS_INTERET("Prêt sans intérêt", "financiere", "important",
"Prêt sans intérêt entre membres", "account_balance", "#FF9800",
true, true, 10000.0, 100000.0, 30),
PRET_SANS_INTERET(
"Prêt sans intérêt",
"financiere",
"important",
"Prêt sans intérêt entre membres",
"account_balance",
"#FF9800",
true,
true,
10000.0,
100000.0,
30),
AIDE_COTISATION("Aide pour cotisation", "financiere", "normal",
"Aide pour payer les cotisations", "payment", "#2196F3",
true, false, 1000.0, 10000.0, 14),
AIDE_COTISATION(
"Aide pour cotisation",
"financiere",
"normal",
"Aide pour payer les cotisations",
"payment",
"#2196F3",
true,
false,
1000.0,
10000.0,
14),
AIDE_FRAIS_MEDICAUX("Aide frais médicaux", "financiere", "urgent",
"Aide pour frais médicaux et hospitaliers", "medical_services", "#E91E63",
true, true, 5000.0, 200000.0, 7),
AIDE_FRAIS_MEDICAUX(
"Aide frais médicaux",
"financiere",
"urgent",
"Aide pour frais médicaux et hospitaliers",
"medical_services",
"#E91E63",
true,
true,
5000.0,
200000.0,
7),
AIDE_FRAIS_SCOLARITE("Aide frais de scolarité", "financiere", "important",
"Aide pour frais de scolarité des enfants", "school", "#9C27B0",
true, true, 10000.0, 100000.0, 21),
AIDE_FRAIS_SCOLARITE(
"Aide frais de scolarité",
"financiere",
"important",
"Aide pour frais de scolarité des enfants",
"school",
"#9C27B0",
true,
true,
10000.0,
100000.0,
21),
// === AIDE MATÉRIELLE ===
DON_MATERIEL("Don de matériel", "materielle", "normal",
"Don d'objets, équipements ou matériel", "inventory", "#4CAF50",
false, false, null, null, 14),
// === AIDE MATÉRIELLE ===
DON_MATERIEL(
"Don de matériel",
"materielle",
"normal",
"Don d'objets, équipements ou matériel",
"inventory",
"#4CAF50",
false,
false,
null,
null,
14),
PRET_MATERIEL("Prêt de matériel", "materielle", "normal",
"Prêt temporaire d'objets ou équipements", "build", "#607D8B",
false, false, null, null, 30),
PRET_MATERIEL(
"Prêt de matériel",
"materielle",
"normal",
"Prêt temporaire d'objets ou équipements",
"build",
"#607D8B",
false,
false,
null,
null,
30),
AIDE_DEMENAGEMENT("Aide déménagement", "materielle", "normal",
"Aide pour déménagement (transport, main d'œuvre)", "local_shipping", "#795548",
false, false, null, null, 7),
AIDE_DEMENAGEMENT(
"Aide déménagement",
"materielle",
"normal",
"Aide pour déménagement (transport, main d'œuvre)",
"local_shipping",
"#795548",
false,
false,
null,
null,
7),
AIDE_TRAVAUX("Aide travaux", "materielle", "normal",
"Aide pour travaux de rénovation ou construction", "construction", "#FF5722",
false, false, null, null, 21),
AIDE_TRAVAUX(
"Aide travaux",
"materielle",
"normal",
"Aide pour travaux de rénovation ou construction",
"construction",
"#FF5722",
false,
false,
null,
null,
21),
// === AIDE PROFESSIONNELLE ===
AIDE_RECHERCHE_EMPLOI("Aide recherche d'emploi", "professionnelle", "important",
"Aide pour recherche d'emploi et CV", "work", "#3F51B5",
false, false, null, null, 30),
// === AIDE PROFESSIONNELLE ===
AIDE_RECHERCHE_EMPLOI(
"Aide recherche d'emploi",
"professionnelle",
"important",
"Aide pour recherche d'emploi et CV",
"work",
"#3F51B5",
false,
false,
null,
null,
30),
FORMATION_PROFESSIONNELLE("Formation professionnelle", "professionnelle", "normal",
"Formation et développement des compétences", "school", "#009688",
false, false, null, null, 60),
FORMATION_PROFESSIONNELLE(
"Formation professionnelle",
"professionnelle",
"normal",
"Formation et développement des compétences",
"school",
"#009688",
false,
false,
null,
null,
60),
CONSEIL_JURIDIQUE("Conseil juridique", "professionnelle", "important",
"Conseil et assistance juridique", "gavel", "#8BC34A",
false, false, null, null, 14),
CONSEIL_JURIDIQUE(
"Conseil juridique",
"professionnelle",
"important",
"Conseil et assistance juridique",
"gavel",
"#8BC34A",
false,
false,
null,
null,
14),
AIDE_CREATION_ENTREPRISE("Aide création d'entreprise", "professionnelle", "normal",
"Accompagnement création d'entreprise", "business", "#CDDC39",
false, false, null, null, 90),
AIDE_CREATION_ENTREPRISE(
"Aide création d'entreprise",
"professionnelle",
"normal",
"Accompagnement création d'entreprise",
"business",
"#CDDC39",
false,
false,
null,
null,
90),
// === AIDE SOCIALE ===
GARDE_ENFANTS("Garde d'enfants", "sociale", "normal",
"Garde d'enfants ponctuelle ou régulière", "child_care", "#FFC107",
false, false, null, null, 7),
// === AIDE SOCIALE ===
GARDE_ENFANTS(
"Garde d'enfants",
"sociale",
"normal",
"Garde d'enfants ponctuelle ou régulière",
"child_care",
"#FFC107",
false,
false,
null,
null,
7),
AIDE_PERSONNES_AGEES("Aide personnes âgées", "sociale", "important",
"Aide et accompagnement personnes âgées", "elderly", "#FF9800",
false, false, null, null, 30),
AIDE_PERSONNES_AGEES(
"Aide personnes âgées",
"sociale",
"important",
"Aide et accompagnement personnes âgées",
"elderly",
"#FF9800",
false,
false,
null,
null,
30),
TRANSPORT("Transport", "sociale", "normal",
"Aide au transport (covoiturage, accompagnement)", "directions_car", "#2196F3",
false, false, null, null, 7),
TRANSPORT(
"Transport",
"sociale",
"normal",
"Aide au transport (covoiturage, accompagnement)",
"directions_car",
"#2196F3",
false,
false,
null,
null,
7),
AIDE_ADMINISTRATIVE("Aide administrative", "sociale", "normal",
"Aide pour démarches administratives", "description", "#9E9E9E",
false, false, null, null, 14),
AIDE_ADMINISTRATIVE(
"Aide administrative",
"sociale",
"normal",
"Aide pour démarches administratives",
"description",
"#9E9E9E",
false,
false,
null,
null,
14),
// === AIDE D'URGENCE ===
HEBERGEMENT_URGENCE("Hébergement d'urgence", "urgence", "urgent",
"Hébergement temporaire d'urgence", "home", "#F44336",
false, true, null, null, 7),
// === AIDE D'URGENCE ===
HEBERGEMENT_URGENCE(
"Hébergement d'urgence",
"urgence",
"urgent",
"Hébergement temporaire d'urgence",
"home",
"#F44336",
false,
true,
null,
null,
7),
AIDE_ALIMENTAIRE("Aide alimentaire", "urgence", "urgent",
"Aide alimentaire d'urgence", "restaurant", "#FF5722",
false, true, null, null, 3),
AIDE_ALIMENTAIRE(
"Aide alimentaire",
"urgence",
"urgent",
"Aide alimentaire d'urgence",
"restaurant",
"#FF5722",
false,
true,
null,
null,
3),
AIDE_VESTIMENTAIRE("Aide vestimentaire", "urgence", "normal",
"Don de vêtements et accessoires", "checkroom", "#795548",
false, false, null, null, 14),
AIDE_VESTIMENTAIRE(
"Aide vestimentaire",
"urgence",
"normal",
"Don de vêtements et accessoires",
"checkroom",
"#795548",
false,
false,
null,
null,
14),
// === AIDE SPÉCIALISÉE ===
SOUTIEN_PSYCHOLOGIQUE("Soutien psychologique", "specialisee", "important",
"Soutien et écoute psychologique", "psychology", "#E91E63",
false, true, null, null, 30),
// === AIDE SPÉCIALISÉE ===
SOUTIEN_PSYCHOLOGIQUE(
"Soutien psychologique",
"specialisee",
"important",
"Soutien et écoute psychologique",
"psychology",
"#E91E63",
false,
true,
null,
null,
30),
AIDE_NUMERIQUE("Aide numérique", "specialisee", "normal",
"Aide pour utilisation outils numériques", "computer", "#607D8B",
false, false, null, null, 14),
AIDE_NUMERIQUE(
"Aide numérique",
"specialisee",
"normal",
"Aide pour utilisation outils numériques",
"computer",
"#607D8B",
false,
false,
null,
null,
14),
TRADUCTION("Traduction", "specialisee", "normal",
"Services de traduction et interprétariat", "translate", "#9C27B0",
false, false, null, null, 7),
TRADUCTION(
"Traduction",
"specialisee",
"normal",
"Services de traduction et interprétariat",
"translate",
"#9C27B0",
false,
false,
null,
null,
7),
AUTRE("Autre", "autre", "normal",
"Autre type d'aide non catégorisé", "help", "#9E9E9E",
false, false, null, null, 14);
AUTRE(
"Autre",
"autre",
"normal",
"Autre type d'aide non catégorisé",
"help",
"#9E9E9E",
false,
false,
null,
null,
14);
private final String libelle;
private final String categorie;
private final String priorite;
private final String description;
private final String icone;
private final String couleur;
private final boolean necessiteMontant;
private final boolean necessiteValidation;
private final Double montantMin;
private final Double montantMax;
private final int delaiReponseJours;
private final String libelle;
private final String categorie;
private final String priorite;
private final String description;
private final String icone;
private final String couleur;
private final boolean necessiteMontant;
private final boolean necessiteValidation;
private final Double montantMin;
private final Double montantMax;
private final int delaiReponseJours;
TypeAide(String libelle, String categorie, String priorite, String description,
String icone, String couleur, boolean necessiteMontant, boolean necessiteValidation,
Double montantMin, Double montantMax, int delaiReponseJours) {
this.libelle = libelle;
this.categorie = categorie;
this.priorite = priorite;
this.description = description;
this.icone = icone;
this.couleur = couleur;
this.necessiteMontant = necessiteMontant;
this.necessiteValidation = necessiteValidation;
this.montantMin = montantMin;
this.montantMax = montantMax;
this.delaiReponseJours = delaiReponseJours;
TypeAide(
String libelle,
String categorie,
String priorite,
String description,
String icone,
String couleur,
boolean necessiteMontant,
boolean necessiteValidation,
Double montantMin,
Double montantMax,
int delaiReponseJours) {
this.libelle = libelle;
this.categorie = categorie;
this.priorite = priorite;
this.description = description;
this.icone = icone;
this.couleur = couleur;
this.necessiteMontant = necessiteMontant;
this.necessiteValidation = necessiteValidation;
this.montantMin = montantMin;
this.montantMax = montantMax;
this.delaiReponseJours = delaiReponseJours;
}
// === GETTERS ===
public String getLibelle() {
return libelle;
}
public String getCategorie() {
return categorie;
}
public String getPriorite() {
return priorite;
}
public String getDescription() {
return description;
}
public String getIcone() {
return icone;
}
public String getCouleur() {
return couleur;
}
public boolean isNecessiteMontant() {
return necessiteMontant;
}
public boolean isNecessiteValidation() {
return necessiteValidation;
}
public Double getMontantMin() {
return montantMin;
}
public Double getMontantMax() {
return montantMax;
}
public int getDelaiReponseJours() {
return delaiReponseJours;
}
// === MÉTHODES UTILITAIRES ===
/** Vérifie si le type d'aide est urgent */
public boolean isUrgent() {
return "urgent".equals(priorite);
}
/** Vérifie si le type d'aide est financier */
public boolean isFinancier() {
return "financiere".equals(categorie);
}
/** Vérifie si le type d'aide est matériel */
public boolean isMateriel() {
return "materielle".equals(categorie);
}
/** Vérifie si le montant est dans la fourchette autorisée */
public boolean isMontantValide(Double montant) {
if (!necessiteMontant || montant == null) return true;
if (montantMin != null && montant < montantMin) return false;
if (montantMax != null && montant > montantMax) return false;
return true;
}
/** Retourne le niveau de priorité numérique */
public int getNiveauPriorite() {
return switch (priorite) {
case "urgent" -> 1;
case "important" -> 2;
case "normal" -> 3;
default -> 3;
};
}
/** Retourne la date limite de réponse */
public java.time.LocalDateTime getDateLimiteReponse() {
return java.time.LocalDateTime.now().plusDays(delaiReponseJours);
}
/** Retourne les types d'aide par catégorie */
public static java.util.List<TypeAide> getParCategorie(String categorie) {
return java.util.Arrays.stream(values())
.filter(type -> type.getCategorie().equals(categorie))
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les types d'aide urgents */
public static java.util.List<TypeAide> getUrgents() {
return java.util.Arrays.stream(values())
.filter(TypeAide::isUrgent)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les types d'aide financiers */
public static java.util.List<TypeAide> getFinanciers() {
return java.util.Arrays.stream(values())
.filter(TypeAide::isFinancier)
.collect(java.util.stream.Collectors.toList());
}
/** Retourne les catégories disponibles */
public static java.util.Set<String> getCategories() {
return java.util.Arrays.stream(values())
.map(TypeAide::getCategorie)
.collect(java.util.stream.Collectors.toSet());
}
/** Retourne le libellé de la catégorie */
public String getLibelleCategorie() {
return switch (categorie) {
case "financiere" -> "Aide financière";
case "materielle" -> "Aide matérielle";
case "professionnelle" -> "Aide professionnelle";
case "sociale" -> "Aide sociale";
case "urgence" -> "Aide d'urgence";
case "specialisee" -> "Aide spécialisée";
case "autre" -> "Autre";
default -> categorie;
};
}
/** Retourne l'unité du montant si applicable */
public String getUniteMontant() {
return necessiteMontant ? "FCFA" : null;
}
/** Retourne le message de validation du montant */
public String getMessageValidationMontant(Double montant) {
if (!necessiteMontant) return null;
if (montant == null) return "Le montant est obligatoire";
if (montantMin != null && montant < montantMin) {
return String.format("Le montant minimum est de %.0f FCFA", montantMin);
}
// === GETTERS ===
public String getLibelle() { return libelle; }
public String getCategorie() { return categorie; }
public String getPriorite() { return priorite; }
public String getDescription() { return description; }
public String getIcone() { return icone; }
public String getCouleur() { return couleur; }
public boolean isNecessiteMontant() { return necessiteMontant; }
public boolean isNecessiteValidation() { return necessiteValidation; }
public Double getMontantMin() { return montantMin; }
public Double getMontantMax() { return montantMax; }
public int getDelaiReponseJours() { return delaiReponseJours; }
// === MÉTHODES UTILITAIRES ===
/**
* Vérifie si le type d'aide est urgent
*/
public boolean isUrgent() {
return "urgent".equals(priorite);
}
/**
* Vérifie si le type d'aide est financier
*/
public boolean isFinancier() {
return "financiere".equals(categorie);
}
/**
* Vérifie si le type d'aide est matériel
*/
public boolean isMateriel() {
return "materielle".equals(categorie);
}
/**
* Vérifie si le montant est dans la fourchette autorisée
*/
public boolean isMontantValide(Double montant) {
if (!necessiteMontant || montant == null) return true;
if (montantMin != null && montant < montantMin) return false;
if (montantMax != null && montant > montantMax) return false;
return true;
}
/**
* Retourne le niveau de priorité numérique
*/
public int getNiveauPriorite() {
return switch (priorite) {
case "urgent" -> 1;
case "important" -> 2;
case "normal" -> 3;
default -> 3;
};
}
/**
* Retourne la date limite de réponse
*/
public java.time.LocalDateTime getDateLimiteReponse() {
return java.time.LocalDateTime.now().plusDays(delaiReponseJours);
}
/**
* Retourne les types d'aide par catégorie
*/
public static java.util.List<TypeAide> getParCategorie(String categorie) {
return java.util.Arrays.stream(values())
.filter(type -> type.getCategorie().equals(categorie))
.collect(java.util.stream.Collectors.toList());
}
/**
* Retourne les types d'aide urgents
*/
public static java.util.List<TypeAide> getUrgents() {
return java.util.Arrays.stream(values())
.filter(TypeAide::isUrgent)
.collect(java.util.stream.Collectors.toList());
}
/**
* Retourne les types d'aide financiers
*/
public static java.util.List<TypeAide> getFinanciers() {
return java.util.Arrays.stream(values())
.filter(TypeAide::isFinancier)
.collect(java.util.stream.Collectors.toList());
}
/**
* Retourne les catégories disponibles
*/
public static java.util.Set<String> getCategories() {
return java.util.Arrays.stream(values())
.map(TypeAide::getCategorie)
.collect(java.util.stream.Collectors.toSet());
}
/**
* Retourne le libellé de la catégorie
*/
public String getLibelleCategorie() {
return switch (categorie) {
case "financiere" -> "Aide financière";
case "materielle" -> "Aide matérielle";
case "professionnelle" -> "Aide professionnelle";
case "sociale" -> "Aide sociale";
case "urgence" -> "Aide d'urgence";
case "specialisee" -> "Aide spécialisée";
case "autre" -> "Autre";
default -> categorie;
};
}
/**
* Retourne l'unité du montant si applicable
*/
public String getUniteMontant() {
return necessiteMontant ? "FCFA" : null;
}
/**
* Retourne le message de validation du montant
*/
public String getMessageValidationMontant(Double montant) {
if (!necessiteMontant) return null;
if (montant == null) return "Le montant est obligatoire";
if (montantMin != null && montant < montantMin) {
return String.format("Le montant minimum est de %.0f FCFA", montantMin);
}
if (montantMax != null && montant > montantMax) {
return String.format("Le montant maximum est de %.0f FCFA", montantMax);
}
return null;
if (montantMax != null && montant > montantMax) {
return String.format("Le montant maximum est de %.0f FCFA", montantMax);
}
return null;
}
}

View File

@@ -0,0 +1,233 @@
package dev.lions.unionflow.server.api.validation;
/**
* Constantes pour la validation des DTOs
*
* <p>Cette classe centralise toutes les contraintes de validation pour assurer la cohérence entre
* les différents DTOs du système.
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
public final class ValidationConstants {
private ValidationConstants() {
// Classe utilitaire - constructeur privé
}
// === CONTRAINTES DE TAILLE POUR LES TEXTES ===
/** Titre court (événements, aides, etc.) */
public static final int TITRE_MIN_LENGTH = 5;
public static final int TITRE_MAX_LENGTH = 100;
public static final String TITRE_SIZE_MESSAGE =
"Le titre doit contenir entre "
+ TITRE_MIN_LENGTH
+ " et "
+ TITRE_MAX_LENGTH
+ " caractères";
/** Nom d'organisation */
public static final int NOM_ORGANISATION_MIN_LENGTH = 2;
public static final int NOM_ORGANISATION_MAX_LENGTH = 200;
public static final String NOM_ORGANISATION_SIZE_MESSAGE =
"Le nom doit contenir entre "
+ NOM_ORGANISATION_MIN_LENGTH
+ " et "
+ NOM_ORGANISATION_MAX_LENGTH
+ " caractères";
/** Description standard */
public static final int DESCRIPTION_MIN_LENGTH = 20;
public static final int DESCRIPTION_MAX_LENGTH = 2000;
public static final String DESCRIPTION_SIZE_MESSAGE =
"La description doit contenir entre "
+ DESCRIPTION_MIN_LENGTH
+ " et "
+ DESCRIPTION_MAX_LENGTH
+ " caractères";
/** Description courte (événements) */
public static final int DESCRIPTION_COURTE_MAX_LENGTH = 1000;
public static final String DESCRIPTION_COURTE_SIZE_MESSAGE =
"La description ne peut pas dépasser " + DESCRIPTION_COURTE_MAX_LENGTH + " caractères";
/** Justification */
public static final int JUSTIFICATION_MAX_LENGTH = 1000;
public static final String JUSTIFICATION_SIZE_MESSAGE =
"La justification ne peut pas dépasser " + JUSTIFICATION_MAX_LENGTH + " caractères";
/** Commentaires */
public static final int COMMENTAIRES_MAX_LENGTH = 1000;
public static final String COMMENTAIRES_SIZE_MESSAGE =
"Les commentaires ne peuvent pas dépasser " + COMMENTAIRES_MAX_LENGTH + " caractères";
/** Raison de rejet */
public static final int RAISON_REJET_MAX_LENGTH = 500;
public static final String RAISON_REJET_SIZE_MESSAGE =
"La raison du rejet ne peut pas dépasser " + RAISON_REJET_MAX_LENGTH + " caractères";
/** Adresse */
public static final int ADRESSE_MAX_LENGTH = 200;
public static final String ADRESSE_SIZE_MESSAGE =
"L'adresse ne peut pas dépasser " + ADRESSE_MAX_LENGTH + " caractères";
/** Ville, région, quartier */
public static final int LOCALISATION_MAX_LENGTH = 50;
public static final String VILLE_SIZE_MESSAGE =
"La ville ne peut pas dépasser " + LOCALISATION_MAX_LENGTH + " caractères";
public static final String REGION_SIZE_MESSAGE =
"La région ne peut pas dépasser " + LOCALISATION_MAX_LENGTH + " caractères";
public static final String QUARTIER_SIZE_MESSAGE =
"Le quartier ne peut pas dépasser " + LOCALISATION_MAX_LENGTH + " caractères";
/** Rôle */
public static final int ROLE_MAX_LENGTH = 50;
public static final String ROLE_SIZE_MESSAGE =
"Le rôle ne peut pas dépasser " + ROLE_MAX_LENGTH + " caractères";
/** URL */
public static final int URL_MAX_LENGTH = 255;
public static final String URL_SIZE_MESSAGE =
"L'URL ne peut pas dépasser " + URL_MAX_LENGTH + " caractères";
/** Email */
public static final int EMAIL_MAX_LENGTH = 100;
public static final String EMAIL_SIZE_MESSAGE =
"L'email ne peut pas dépasser " + EMAIL_MAX_LENGTH + " caractères";
/** Nom et prénom */
public static final int NOM_PRENOM_MIN_LENGTH = 2;
public static final int NOM_PRENOM_MAX_LENGTH = 50;
public static final String NOM_SIZE_MESSAGE =
"Le nom doit contenir entre "
+ NOM_PRENOM_MIN_LENGTH
+ " et "
+ NOM_PRENOM_MAX_LENGTH
+ " caractères";
public static final String PRENOM_SIZE_MESSAGE =
"Le prénom doit contenir entre "
+ NOM_PRENOM_MIN_LENGTH
+ " et "
+ NOM_PRENOM_MAX_LENGTH
+ " caractères";
// === PATTERNS DE VALIDATION ===
/** Numéro de téléphone international */
public static final String TELEPHONE_PATTERN = "^\\+?[0-9]{8,15}$";
public static final String TELEPHONE_MESSAGE =
"Le numéro de téléphone doit contenir entre 8 et 15 chiffres, avec un indicatif optionnel"
+ " (+)";
/** Code devise ISO */
public static final String DEVISE_PATTERN = "^[A-Z]{3}$";
public static final String DEVISE_MESSAGE =
"La devise doit être un code ISO à 3 lettres majuscules";
/** Numéro de référence aide */
public static final String REFERENCE_AIDE_PATTERN = "^DA-\\d{4}-\\d{6}$";
public static final String REFERENCE_AIDE_MESSAGE =
"Le numéro de référence doit suivre le format DA-YYYY-NNNNNN";
/** Numéro de membre */
public static final String NUMERO_MEMBRE_PATTERN = "^UF-\\d{4}-[A-Z0-9]{8}$";
public static final String NUMERO_MEMBRE_MESSAGE =
"Format de numéro de membre invalide (UF-YYYY-XXXXXXXX)";
/** Couleur hexadécimale */
public static final String COULEUR_HEX_PATTERN = "^#[0-9A-Fa-f]{6}$";
public static final String COULEUR_HEX_MESSAGE = "Format de couleur invalide (format: #RRGGBB)";
// === CONTRAINTES NUMÉRIQUES ===
/** Montant minimum */
public static final String MONTANT_MIN_VALUE = "0.0";
public static final String MONTANT_POSITIF_MESSAGE = "Le montant doit être positif";
/** Contraintes pour les montants */
public static final int MONTANT_INTEGER_DIGITS = 10;
public static final int MONTANT_FRACTION_DIGITS = 2;
public static final String MONTANT_DIGITS_MESSAGE =
"Le montant doit avoir au maximum "
+ MONTANT_INTEGER_DIGITS
+ " chiffres entiers et "
+ MONTANT_FRACTION_DIGITS
+ " décimales";
// === MESSAGES D'ERREUR STANDARD ===
public static final String OBLIGATOIRE_MESSAGE = " est obligatoire";
public static final String EMAIL_FORMAT_MESSAGE = "L'adresse email n'est pas valide";
public static final String DATE_PASSEE_MESSAGE = "La date doit être dans le passé";
public static final String DATE_FUTURE_MESSAGE = "La date doit être dans le futur";
// === CONTRAINTES SPÉCIFIQUES ===
/** Documents joints */
public static final int DOCUMENTS_JOINTS_MAX_LENGTH = 1000;
public static final String DOCUMENTS_JOINTS_SIZE_MESSAGE =
"La liste des documents ne peut pas dépasser " + DOCUMENTS_JOINTS_MAX_LENGTH + " caractères";
/** Mode de versement */
public static final int MODE_VERSEMENT_MAX_LENGTH = 50;
public static final String MODE_VERSEMENT_SIZE_MESSAGE =
"Le mode de versement ne peut pas dépasser " + MODE_VERSEMENT_MAX_LENGTH + " caractères";
/** Numéro de transaction */
public static final int NUMERO_TRANSACTION_MAX_LENGTH = 100;
public static final String NUMERO_TRANSACTION_SIZE_MESSAGE =
"Le numéro de transaction ne peut pas dépasser "
+ NUMERO_TRANSACTION_MAX_LENGTH
+ " caractères";
/** Numéro d'enregistrement */
public static final int NUMERO_ENREGISTREMENT_MAX_LENGTH = 100;
public static final String NUMERO_ENREGISTREMENT_SIZE_MESSAGE =
"Le numéro d'enregistrement ne peut pas dépasser "
+ NUMERO_ENREGISTREMENT_MAX_LENGTH
+ " caractères";
/** Nom court d'organisation */
public static final int NOM_COURT_MAX_LENGTH = 50;
public static final String NOM_COURT_SIZE_MESSAGE =
"Le nom court ne peut pas dépasser " + NOM_COURT_MAX_LENGTH + " caractères";
/** Instructions et matériel */
public static final int INSTRUCTIONS_MAX_LENGTH = 500;
public static final String INSTRUCTIONS_SIZE_MESSAGE =
"Les instructions ne peuvent pas dépasser " + INSTRUCTIONS_MAX_LENGTH + " caractères";
/** Conditions météo */
public static final int CONDITIONS_METEO_MAX_LENGTH = 100;
public static final String CONDITIONS_METEO_SIZE_MESSAGE =
"Les conditions météo ne peuvent pas dépasser " + CONDITIONS_METEO_MAX_LENGTH + " caractères";
}

View File

@@ -0,0 +1,154 @@
package dev.lions.unionflow.server.api;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.dto.evenement.EvenementDTO;
import dev.lions.unionflow.server.api.dto.solidarite.DemandeAideDTO;
import dev.lions.unionflow.server.api.dto.solidarite.PropositionAideDTO;
import dev.lions.unionflow.server.api.dto.solidarite.aide.AideDTO;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import dev.lions.unionflow.server.api.validation.ValidationConstants;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* Test de compilation pour vérifier que tous les DTOs compilent correctement
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@DisplayName("Tests de Compilation")
class CompilationTest {
@Test
@DisplayName("Test compilation EvenementDTO")
void testCompilationEvenementDTO() {
EvenementDTO evenement = new EvenementDTO();
evenement.setTitre("Test Formation");
evenement.setStatut(StatutEvenement.PLANIFIE);
evenement.setPriorite(PrioriteEvenement.NORMALE);
evenement.setTypeEvenement(TypeEvenementMetier.FORMATION);
evenement.setDateDebut(LocalDate.now().plusDays(30));
// Test des méthodes métier
assertThat(evenement.estEnCours()).isFalse();
assertThat(evenement.getStatutLibelle()).isEqualTo("Planifié");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Formation");
// Test des setters
evenement.setStatut(StatutEvenement.CONFIRME);
assertThat(evenement.getStatut()).isEqualTo(StatutEvenement.CONFIRME);
}
@Test
@DisplayName("Test compilation DemandeAideDTO")
void testCompilationDemandeAideDTO() {
DemandeAideDTO demande = new DemandeAideDTO();
demande.setTitre("Test Demande");
demande.setMontantDemande(new BigDecimal("50000"));
demande.setDevise("XOF");
// Test des méthodes métier
assertThat(demande.getId()).isNotNull(); // BaseDTO génère automatiquement un UUID
assertThat(demande.getVersion()).isEqualTo(0L);
// Test de la méthode marquerCommeModifie
demande.marquerCommeModifie("testUser");
assertThat(demande.getModifiePar()).isEqualTo("testUser");
}
@Test
@DisplayName("Test compilation PropositionAideDTO")
void testCompilationPropositionAideDTO() {
PropositionAideDTO proposition = new PropositionAideDTO();
proposition.setTitre("Test Proposition");
proposition.setMontantMaximum(new BigDecimal("100000"));
// Vérifier que le type est correct
assertThat(proposition.getMontantMaximum()).isInstanceOf(BigDecimal.class);
}
@Test
@DisplayName("Test compilation AideDTO (deprecated)")
void testCompilationAideDTO() {
@SuppressWarnings("deprecation")
AideDTO aide = new AideDTO();
aide.setTitre("Test Aide");
// Test des méthodes métier
assertThat(aide.getTypeAideLibelle()).isNotNull();
assertThat(aide.getStatutLibelle()).isNotNull();
}
@Test
@DisplayName("Test compilation ValidationConstants")
void testCompilationValidationConstants() {
// Test que les constantes sont accessibles
assertThat(ValidationConstants.TITRE_MIN_LENGTH).isEqualTo(5);
assertThat(ValidationConstants.TITRE_MAX_LENGTH).isEqualTo(100);
assertThat(ValidationConstants.TELEPHONE_PATTERN).isNotNull();
assertThat(ValidationConstants.DEVISE_PATTERN).isNotNull();
}
@Test
@DisplayName("Test compilation énumérations")
void testCompilationEnumerations() {
// Test StatutEvenement
StatutEvenement statut = StatutEvenement.PLANIFIE;
assertThat(statut.getLibelle()).isEqualTo("Planifié");
assertThat(statut.permetModification()).isTrue();
// Test PrioriteEvenement
PrioriteEvenement priorite = PrioriteEvenement.HAUTE;
assertThat(priorite.getLibelle()).isEqualTo("Haute");
assertThat(priorite.isUrgente()).isTrue(); // Amélioration TDD : HAUTE est maintenant urgente
// Test TypeEvenementMetier
TypeEvenementMetier type = TypeEvenementMetier.FORMATION;
assertThat(type.getLibelle()).isEqualTo("Formation");
}
@Test
@DisplayName("Test intégration complète")
void testIntegrationComplete() {
// Créer un événement complet
EvenementDTO evenement =
new EvenementDTO(
"Formation Leadership",
TypeEvenementMetier.FORMATION,
LocalDate.now().plusDays(30),
"Centre de Formation");
evenement.setStatut(StatutEvenement.PLANIFIE);
evenement.setPriorite(PrioriteEvenement.HAUTE);
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(0);
evenement.setBudget(new BigDecimal("500000"));
evenement.setCodeDevise("XOF");
evenement.setAssociationId(UUID.randomUUID());
// Vérifier que tout fonctionne
assertThat(evenement.estEnCours()).isFalse();
assertThat(evenement.estComplet()).isFalse();
assertThat(evenement.sontInscriptionsOuvertes()).isTrue();
// Créer une demande d'aide complète
DemandeAideDTO demande = new DemandeAideDTO();
demande.setTitre("Aide Médicale Urgente");
demande.setDescription("Besoin d'aide pour frais médicaux");
demande.setMontantDemande(new BigDecimal("250000"));
demande.setDevise("XOF");
demande.setMembreDemandeurId(UUID.randomUUID());
demande.setAssociationId(UUID.randomUUID());
// Vérifier que tout fonctionne
assertThat(demande.getId()).isNotNull();
assertThat(demande.getVersion()).isEqualTo(0L);
assertThat(demande.getMontantDemande()).isEqualTo(new BigDecimal("250000"));
}
}

View File

@@ -224,10 +224,10 @@ class BaseDTOTest {
void testEqualsMemeId() {
UUID id = UUID.randomUUID();
baseDto.setId(id);
TestableBaseDTO autre = new TestableBaseDTO();
autre.setId(id);
assertThat(baseDto).isEqualTo(autre);
assertThat(baseDto.hashCode()).isEqualTo(autre.hashCode());
}
@@ -236,10 +236,10 @@ class BaseDTOTest {
@DisplayName("Test equals - IDs différents")
void testEqualsIdsDifferents() {
baseDto.setId(UUID.randomUUID());
TestableBaseDTO autre = new TestableBaseDTO();
autre.setId(UUID.randomUUID());
assertThat(baseDto).isNotEqualTo(autre);
}
@@ -247,10 +247,10 @@ class BaseDTOTest {
@DisplayName("Test equals - ID null")
void testEqualsIdNull() {
baseDto.setId(null);
TestableBaseDTO autre = new TestableBaseDTO();
autre.setId(null);
assertThat(baseDto).isNotEqualTo(autre);
}
@@ -299,7 +299,7 @@ class BaseDTOTest {
baseDto.setId(id);
baseDto.setVersion(2L);
baseDto.setActif(true);
String result = baseDto.toString();
assertThat(result).contains("TestableBaseDTO");
assertThat(result).contains("id=" + id.toString());
@@ -308,9 +308,7 @@ class BaseDTOTest {
}
}
/**
* Classe de test concrète pour tester BaseDTO.
*/
/** Classe de test concrète pour tester BaseDTO. */
private static class TestableBaseDTO extends BaseDTO {
private static final long serialVersionUID = 1L;

View File

@@ -1,672 +0,0 @@
package dev.lions.unionflow.server.api.dto.evenement;
import static org.assertj.core.api.Assertions.assertThat;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires complets pour EvenementDTO.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-10
*/
@DisplayName("Tests EvenementDTO")
class EvenementDTOBasicTest {
private EvenementDTO evenement;
@BeforeEach
void setUp() {
evenement = new EvenementDTO();
}
@Nested
@DisplayName("Tests de Construction")
class ConstructionTests {
@Test
@DisplayName("Constructeur par défaut - Initialisation correcte")
void testConstructeurParDefaut() {
EvenementDTO newEvenement = new EvenementDTO();
assertThat(newEvenement.getId()).isNotNull();
assertThat(newEvenement.getDateCreation()).isNotNull();
assertThat(newEvenement.isActif()).isTrue();
assertThat(newEvenement.getVersion()).isEqualTo(0L);
assertThat(newEvenement.getStatut()).isEqualTo("PLANIFIE");
assertThat(newEvenement.getPriorite()).isEqualTo("NORMALE");
assertThat(newEvenement.getParticipantsInscrits()).isEqualTo(0);
assertThat(newEvenement.getParticipantsPresents()).isEqualTo(0);
assertThat(newEvenement.getInscriptionObligatoire()).isFalse();
assertThat(newEvenement.getEvenementPublic()).isTrue();
assertThat(newEvenement.getRecurrent()).isFalse();
assertThat(newEvenement.getCodeDevise()).isEqualTo("XOF");
}
@Test
@DisplayName("Constructeur avec paramètres - Initialisation correcte")
void testConstructeurAvecParametres() {
String titre = "Réunion mensuelle";
String typeEvenement = "REUNION_BUREAU";
LocalDate dateDebut = LocalDate.now().plusDays(7);
String lieu = "Salle de conférence";
EvenementDTO newEvenement = new EvenementDTO(titre, typeEvenement, dateDebut, lieu);
assertThat(newEvenement.getTitre()).isEqualTo(titre);
assertThat(newEvenement.getTypeEvenement()).isEqualTo(typeEvenement);
assertThat(newEvenement.getDateDebut()).isEqualTo(dateDebut);
assertThat(newEvenement.getLieu()).isEqualTo(lieu);
assertThat(newEvenement.getStatut()).isEqualTo("PLANIFIE");
}
}
@Nested
@DisplayName("Tests Getters/Setters")
class GettersSettersTests {
@Test
@DisplayName("Test tous les getters/setters")
void testTousLesGettersSetters() {
// Données de test
String titre = "Formation Leadership";
String description = "Formation sur le leadership associatif";
String typeEvenement = "FORMATION";
String statut = "EN_COURS";
String priorite = "HAUTE";
LocalDate dateDebut = LocalDate.now().plusDays(1);
LocalDate dateFin = LocalDate.now().plusDays(2);
LocalTime heureDebut = LocalTime.of(9, 0);
LocalTime heureFin = LocalTime.of(17, 0);
String lieu = "Centre de formation";
String adresse = "123 Avenue de la République";
String ville = "Dakar";
String region = "Dakar";
BigDecimal latitude = new BigDecimal("14.6937");
BigDecimal longitude = new BigDecimal("-17.4441");
UUID associationId = UUID.randomUUID();
String nomAssociation = "Lions Club Dakar";
String organisateur = "Jean Dupont";
String emailOrganisateur = "jean.dupont@example.com";
String telephoneOrganisateur = "+221701234567";
Integer capaciteMax = 50;
Integer participantsInscrits = 25;
Integer participantsPresents = 20;
BigDecimal budget = new BigDecimal("500000.00");
BigDecimal coutReel = new BigDecimal("450000.00");
String codeDevise = "XOF";
Boolean inscriptionObligatoire = true;
LocalDate dateLimiteInscription = LocalDate.now().plusDays(5);
Boolean evenementPublic = false;
Boolean recurrent = true;
String frequenceRecurrence = "MENSUELLE";
String instructions = "Apporter un carnet de notes";
String materielNecessaire = "Projecteur, tableau";
String conditionsMeteo = "Intérieur";
String imageUrl = "https://example.com/image.jpg";
String couleurTheme = "#FF5733";
LocalDateTime dateAnnulation = LocalDateTime.now();
String raisonAnnulation = "Conditions météo";
Long annulePar = 123L;
String nomAnnulateur = "Admin";
// Test des setters
evenement.setTitre(titre);
evenement.setDescription(description);
evenement.setTypeEvenement(typeEvenement);
evenement.setStatut(statut);
evenement.setPriorite(priorite);
evenement.setDateDebut(dateDebut);
evenement.setDateFin(dateFin);
evenement.setHeureDebut(heureDebut);
evenement.setHeureFin(heureFin);
evenement.setLieu(lieu);
evenement.setAdresse(adresse);
evenement.setVille(ville);
evenement.setRegion(region);
evenement.setLatitude(latitude);
evenement.setLongitude(longitude);
evenement.setAssociationId(associationId);
evenement.setNomAssociation(nomAssociation);
evenement.setOrganisateur(organisateur);
evenement.setEmailOrganisateur(emailOrganisateur);
evenement.setTelephoneOrganisateur(telephoneOrganisateur);
evenement.setCapaciteMax(capaciteMax);
evenement.setParticipantsInscrits(participantsInscrits);
evenement.setParticipantsPresents(participantsPresents);
evenement.setBudget(budget);
evenement.setCoutReel(coutReel);
evenement.setCodeDevise(codeDevise);
evenement.setInscriptionObligatoire(inscriptionObligatoire);
evenement.setDateLimiteInscription(dateLimiteInscription);
evenement.setEvenementPublic(evenementPublic);
evenement.setRecurrent(recurrent);
evenement.setFrequenceRecurrence(frequenceRecurrence);
evenement.setInstructions(instructions);
evenement.setMaterielNecessaire(materielNecessaire);
evenement.setConditionsMeteo(conditionsMeteo);
evenement.setImageUrl(imageUrl);
evenement.setCouleurTheme(couleurTheme);
evenement.setDateAnnulation(dateAnnulation);
evenement.setRaisonAnnulation(raisonAnnulation);
evenement.setAnnulePar(annulePar);
evenement.setNomAnnulateur(nomAnnulateur);
// Test des getters
assertThat(evenement.getTitre()).isEqualTo(titre);
assertThat(evenement.getDescription()).isEqualTo(description);
assertThat(evenement.getTypeEvenement()).isEqualTo(typeEvenement);
assertThat(evenement.getStatut()).isEqualTo(statut);
assertThat(evenement.getPriorite()).isEqualTo(priorite);
assertThat(evenement.getDateDebut()).isEqualTo(dateDebut);
assertThat(evenement.getDateFin()).isEqualTo(dateFin);
assertThat(evenement.getHeureDebut()).isEqualTo(heureDebut);
assertThat(evenement.getHeureFin()).isEqualTo(heureFin);
assertThat(evenement.getLieu()).isEqualTo(lieu);
assertThat(evenement.getAdresse()).isEqualTo(adresse);
assertThat(evenement.getVille()).isEqualTo(ville);
assertThat(evenement.getRegion()).isEqualTo(region);
assertThat(evenement.getLatitude()).isEqualTo(latitude);
assertThat(evenement.getLongitude()).isEqualTo(longitude);
assertThat(evenement.getAssociationId()).isEqualTo(associationId);
assertThat(evenement.getNomAssociation()).isEqualTo(nomAssociation);
assertThat(evenement.getOrganisateur()).isEqualTo(organisateur);
assertThat(evenement.getEmailOrganisateur()).isEqualTo(emailOrganisateur);
assertThat(evenement.getTelephoneOrganisateur()).isEqualTo(telephoneOrganisateur);
assertThat(evenement.getCapaciteMax()).isEqualTo(capaciteMax);
assertThat(evenement.getParticipantsInscrits()).isEqualTo(participantsInscrits);
assertThat(evenement.getParticipantsPresents()).isEqualTo(participantsPresents);
assertThat(evenement.getBudget()).isEqualTo(budget);
assertThat(evenement.getCoutReel()).isEqualTo(coutReel);
assertThat(evenement.getCodeDevise()).isEqualTo(codeDevise);
assertThat(evenement.getInscriptionObligatoire()).isEqualTo(inscriptionObligatoire);
assertThat(evenement.getDateLimiteInscription()).isEqualTo(dateLimiteInscription);
assertThat(evenement.getEvenementPublic()).isEqualTo(evenementPublic);
assertThat(evenement.getRecurrent()).isEqualTo(recurrent);
assertThat(evenement.getFrequenceRecurrence()).isEqualTo(frequenceRecurrence);
assertThat(evenement.getInstructions()).isEqualTo(instructions);
assertThat(evenement.getMaterielNecessaire()).isEqualTo(materielNecessaire);
assertThat(evenement.getConditionsMeteo()).isEqualTo(conditionsMeteo);
assertThat(evenement.getImageUrl()).isEqualTo(imageUrl);
assertThat(evenement.getCouleurTheme()).isEqualTo(couleurTheme);
assertThat(evenement.getDateAnnulation()).isEqualTo(dateAnnulation);
assertThat(evenement.getRaisonAnnulation()).isEqualTo(raisonAnnulation);
assertThat(evenement.getAnnulePar()).isEqualTo(annulePar);
assertThat(evenement.getNomAnnulateur()).isEqualTo(nomAnnulateur);
}
}
@Nested
@DisplayName("Tests Méthodes Métier")
class MethodesMetierTests {
@Test
@DisplayName("Test méthodes de statut")
void testMethodesStatut() {
// Test isEnCours
evenement.setStatut("EN_COURS");
assertThat(evenement.isEnCours()).isTrue();
evenement.setStatut("PLANIFIE");
assertThat(evenement.isEnCours()).isFalse();
// Test isTermine
evenement.setStatut("TERMINE");
assertThat(evenement.isTermine()).isTrue();
evenement.setStatut("PLANIFIE");
assertThat(evenement.isTermine()).isFalse();
// Test isAnnule
evenement.setStatut("ANNULE");
assertThat(evenement.isAnnule()).isTrue();
evenement.setStatut("PLANIFIE");
assertThat(evenement.isAnnule()).isFalse();
}
@Test
@DisplayName("Test méthodes de capacité")
void testMethodesCapacite() {
// Test isComplet - cas avec capaciteMax null
evenement.setCapaciteMax(null);
evenement.setParticipantsInscrits(50);
assertThat(evenement.isComplet()).isFalse();
// Test isComplet - cas avec participantsInscrits null (capaciteMax définie)
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(null);
assertThat(evenement.isComplet()).isFalse();
// Test isComplet - cas avec les deux null
evenement.setCapaciteMax(null);
evenement.setParticipantsInscrits(null);
assertThat(evenement.isComplet()).isFalse();
// Test isComplet - cas normal complet
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(50);
assertThat(evenement.isComplet()).isTrue();
// Test isComplet - cas normal non complet
evenement.setParticipantsInscrits(30);
assertThat(evenement.isComplet()).isFalse();
// Test getPlacesDisponibles
assertThat(evenement.getPlacesDisponibles()).isEqualTo(20);
evenement.setCapaciteMax(null);
assertThat(evenement.getPlacesDisponibles()).isEqualTo(0);
// Test getTauxRemplissage
evenement.setCapaciteMax(100);
evenement.setParticipantsInscrits(75);
assertThat(evenement.getTauxRemplissage()).isEqualTo(75);
evenement.setCapaciteMax(0);
assertThat(evenement.getTauxRemplissage()).isEqualTo(0);
}
@Test
@DisplayName("Test isComplet - branches spécifiques")
void testIsCompletBranchesSpecifiques() {
// Test spécifique pour la branche: capaciteMax != null && participantsInscrits == null
// Nous devons nous assurer que capaciteMax est définie ET que participantsInscrits est null
evenement.setCapaciteMax(100); // Défini explicitement
evenement.setParticipantsInscrits(null); // Null explicitement
// Cette condition devrait évaluer:
// capaciteMax != null (true) && participantsInscrits != null (false) && ...
// Donc retourner false à cause du court-circuit sur participantsInscrits != null
assertThat(evenement.isComplet()).isFalse();
// Test pour vérifier que la branche participantsInscrits != null est bien testée
// Maintenant avec participantsInscrits défini
evenement.setParticipantsInscrits(50); // Défini mais < capaciteMax
assertThat(evenement.isComplet()).isFalse();
// Et maintenant avec participantsInscrits >= capaciteMax
evenement.setParticipantsInscrits(100); // Égal à capaciteMax
assertThat(evenement.isComplet()).isTrue();
}
@Test
@DisplayName("Test getTauxPresence")
void testGetTauxPresence() {
evenement.setParticipantsInscrits(100);
evenement.setParticipantsPresents(80);
assertThat(evenement.getTauxPresence()).isEqualTo(80);
evenement.setParticipantsInscrits(0);
assertThat(evenement.getTauxPresence()).isEqualTo(0);
evenement.setParticipantsInscrits(null);
assertThat(evenement.getTauxPresence()).isEqualTo(0);
}
@Test
@DisplayName("Test isInscriptionsOuvertes")
void testIsInscriptionsOuvertes() {
// Événement normal avec places disponibles
evenement.setStatut("PLANIFIE");
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(30);
assertThat(evenement.isInscriptionsOuvertes()).isTrue();
// Événement annulé
evenement.setStatut("ANNULE");
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
// Événement terminé
evenement.setStatut("TERMINE");
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
// Événement complet
evenement.setStatut("PLANIFIE");
evenement.setParticipantsInscrits(50);
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
// Date limite dépassée
evenement.setParticipantsInscrits(30);
evenement.setDateLimiteInscription(LocalDate.now().minusDays(1));
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
}
@Test
@DisplayName("Test getDureeEnHeures")
void testGetDureeEnHeures() {
evenement.setHeureDebut(LocalTime.of(9, 0));
evenement.setHeureFin(LocalTime.of(17, 0));
assertThat(evenement.getDureeEnHeures()).isEqualTo(8);
evenement.setHeureDebut(null);
assertThat(evenement.getDureeEnHeures()).isEqualTo(0);
}
@Test
@DisplayName("Test isEvenementMultiJours")
void testIsEvenementMultiJours() {
LocalDate dateDebut = LocalDate.now();
evenement.setDateDebut(dateDebut);
evenement.setDateFin(dateDebut.plusDays(2));
assertThat(evenement.isEvenementMultiJours()).isTrue();
evenement.setDateFin(dateDebut);
assertThat(evenement.isEvenementMultiJours()).isFalse();
evenement.setDateFin(null);
assertThat(evenement.isEvenementMultiJours()).isFalse();
}
@Test
@DisplayName("Test getTypeEvenementLibelle")
void testGetTypeEvenementLibelle() {
evenement.setTypeEvenement("ASSEMBLEE_GENERALE");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Assemblée Générale");
evenement.setTypeEvenement("FORMATION");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Formation");
evenement.setTypeEvenement("ACTIVITE_SOCIALE");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Activité Sociale");
evenement.setTypeEvenement("ACTION_CARITATIVE");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Action Caritative");
evenement.setTypeEvenement("REUNION_BUREAU");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Réunion de Bureau");
evenement.setTypeEvenement("CONFERENCE");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Conférence");
evenement.setTypeEvenement("ATELIER");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Atelier");
evenement.setTypeEvenement("CEREMONIE");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Cérémonie");
evenement.setTypeEvenement("AUTRE");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Autre");
evenement.setTypeEvenement("INCONNU");
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("INCONNU");
evenement.setTypeEvenement(null);
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Non défini");
}
@Test
@DisplayName("Test getStatutLibelle")
void testGetStatutLibelle() {
evenement.setStatut("PLANIFIE");
assertThat(evenement.getStatutLibelle()).isEqualTo("Planifié");
evenement.setStatut("EN_COURS");
assertThat(evenement.getStatutLibelle()).isEqualTo("En cours");
evenement.setStatut("TERMINE");
assertThat(evenement.getStatutLibelle()).isEqualTo("Terminé");
evenement.setStatut("ANNULE");
assertThat(evenement.getStatutLibelle()).isEqualTo("Annulé");
evenement.setStatut("REPORTE");
assertThat(evenement.getStatutLibelle()).isEqualTo("Reporté");
evenement.setStatut("INCONNU");
assertThat(evenement.getStatutLibelle()).isEqualTo("INCONNU");
evenement.setStatut(null);
assertThat(evenement.getStatutLibelle()).isEqualTo("Non défini");
}
@Test
@DisplayName("Test getPrioriteLibelle")
void testGetPrioriteLibelle() {
evenement.setPriorite("BASSE");
assertThat(evenement.getPrioriteLibelle()).isEqualTo("Basse");
evenement.setPriorite("NORMALE");
assertThat(evenement.getPrioriteLibelle()).isEqualTo("Normale");
evenement.setPriorite("HAUTE");
assertThat(evenement.getPrioriteLibelle()).isEqualTo("Haute");
evenement.setPriorite("CRITIQUE");
assertThat(evenement.getPrioriteLibelle()).isEqualTo("Critique");
evenement.setPriorite("INCONNU");
assertThat(evenement.getPrioriteLibelle()).isEqualTo("INCONNU");
evenement.setPriorite(null);
assertThat(evenement.getPrioriteLibelle()).isEqualTo("Normale");
}
@Test
@DisplayName("Test getAdresseComplete")
void testGetAdresseComplete() {
// Adresse complète
evenement.setLieu("Centre de conférence");
evenement.setAdresse("123 Avenue de la République");
evenement.setVille("Dakar");
evenement.setRegion("Dakar");
assertThat(evenement.getAdresseComplete())
.isEqualTo("Centre de conférence, 123 Avenue de la République, Dakar, Dakar");
// Adresse partielle
evenement.setAdresse(null);
evenement.setRegion(null);
assertThat(evenement.getAdresseComplete()).isEqualTo("Centre de conférence, Dakar");
// Lieu seulement
evenement.setVille(null);
assertThat(evenement.getAdresseComplete()).isEqualTo("Centre de conférence");
// Aucune information
evenement.setLieu(null);
assertThat(evenement.getAdresseComplete()).isEmpty();
}
@Test
@DisplayName("Test hasCoordonnees")
void testHasCoordonnees() {
evenement.setLatitude(new BigDecimal("14.6937"));
evenement.setLongitude(new BigDecimal("-17.4441"));
assertThat(evenement.hasCoordonnees()).isTrue();
evenement.setLatitude(null);
assertThat(evenement.hasCoordonnees()).isFalse();
evenement.setLatitude(new BigDecimal("14.6937"));
evenement.setLongitude(null);
assertThat(evenement.hasCoordonnees()).isFalse();
}
@Test
@DisplayName("Test méthodes budgétaires")
void testMethodesBudgetaires() {
// Test getEcartBudgetaire - économie
evenement.setBudget(new BigDecimal("500000.00"));
evenement.setCoutReel(new BigDecimal("450000.00"));
assertThat(evenement.getEcartBudgetaire()).isEqualTo(new BigDecimal("50000.00"));
assertThat(evenement.isBudgetDepasse()).isFalse();
// Test getEcartBudgetaire - dépassement
evenement.setCoutReel(new BigDecimal("550000.00"));
assertThat(evenement.getEcartBudgetaire()).isEqualTo(new BigDecimal("-50000.00"));
assertThat(evenement.isBudgetDepasse()).isTrue();
// Test avec valeurs nulles
evenement.setBudget(null);
assertThat(evenement.getEcartBudgetaire()).isEqualTo(BigDecimal.ZERO);
assertThat(evenement.isBudgetDepasse()).isFalse();
evenement.setBudget(new BigDecimal("500000.00"));
evenement.setCoutReel(null);
assertThat(evenement.getEcartBudgetaire()).isEqualTo(BigDecimal.ZERO);
assertThat(evenement.isBudgetDepasse()).isFalse();
}
}
@Test
@DisplayName("Test toString")
void testToString() {
evenement.setTitre("Événement test");
evenement.setTypeEvenement("FORMATION");
evenement.setStatut("PLANIFIE");
evenement.setDateDebut(LocalDate.now());
evenement.setLieu("Salle de test");
evenement.setParticipantsInscrits(10);
evenement.setCapaciteMax(50);
String result = evenement.toString();
assertThat(result).isNotNull();
assertThat(result).contains("EvenementDTO");
assertThat(result).contains("titre='Événement test'");
assertThat(result).contains("typeEvenement='FORMATION'");
assertThat(result).contains("statut='PLANIFIE'");
assertThat(result).contains("lieu='Salle de test'");
assertThat(result).contains("participantsInscrits=10");
assertThat(result).contains("capaciteMax=50");
}
@Test
@DisplayName("Test branches supplémentaires getPlacesDisponibles")
void testBranchesSupplementairesPlacesDisponibles() {
// Test avec capaciteMax null
evenement.setCapaciteMax(null);
evenement.setParticipantsInscrits(10);
assertThat(evenement.getPlacesDisponibles()).isEqualTo(0);
// Test avec participantsInscrits null
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(null);
assertThat(evenement.getPlacesDisponibles()).isEqualTo(0);
// Test avec les deux null
evenement.setCapaciteMax(null);
evenement.setParticipantsInscrits(null);
assertThat(evenement.getPlacesDisponibles()).isEqualTo(0);
}
@Test
@DisplayName("Test branches supplémentaires getTauxRemplissage")
void testBranchesSupplementairesTauxRemplissage() {
// Test avec capaciteMax null
evenement.setCapaciteMax(null);
evenement.setParticipantsInscrits(10);
assertThat(evenement.getTauxRemplissage()).isEqualTo(0);
// Test avec capaciteMax zéro
evenement.setCapaciteMax(0);
evenement.setParticipantsInscrits(10);
assertThat(evenement.getTauxRemplissage()).isEqualTo(0);
// Test avec participantsInscrits null
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(null);
assertThat(evenement.getTauxRemplissage()).isEqualTo(0);
}
@Test
@DisplayName("Test branches supplémentaires getTauxPresence")
void testBranchesSupplementairesTauxPresence() {
// Test avec participantsInscrits null
evenement.setParticipantsInscrits(null);
evenement.setParticipantsPresents(5);
assertThat(evenement.getTauxPresence()).isEqualTo(0);
// Test avec participantsInscrits zéro
evenement.setParticipantsInscrits(0);
evenement.setParticipantsPresents(5);
assertThat(evenement.getTauxPresence()).isEqualTo(0);
// Test avec participantsPresents null
evenement.setParticipantsInscrits(10);
evenement.setParticipantsPresents(null);
assertThat(evenement.getTauxPresence()).isEqualTo(0);
}
@Test
@DisplayName("Test branches supplémentaires isInscriptionsOuvertes")
void testBranchesSupplementairesInscriptionsOuvertes() {
// Test avec événement annulé
evenement.setStatut("ANNULE");
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(10);
evenement.setDateLimiteInscription(LocalDate.now().plusDays(5));
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
// Test avec événement terminé
evenement.setStatut("TERMINE");
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
// Test avec date limite dépassée
evenement.setStatut("PLANIFIE");
evenement.setDateLimiteInscription(LocalDate.now().minusDays(1));
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
// Test avec événement complet
evenement.setDateLimiteInscription(LocalDate.now().plusDays(5));
evenement.setCapaciteMax(10);
evenement.setParticipantsInscrits(10);
assertThat(evenement.isInscriptionsOuvertes()).isFalse();
}
@Test
@DisplayName("Test branches supplémentaires getDureeEnHeures")
void testBranchesSupplementairesDureeEnHeures() {
// Test avec heureDebut null
evenement.setHeureDebut(null);
evenement.setHeureFin(LocalTime.of(17, 0));
assertThat(evenement.getDureeEnHeures()).isEqualTo(0);
// Test avec heureFin null
evenement.setHeureDebut(LocalTime.of(9, 0));
evenement.setHeureFin(null);
assertThat(evenement.getDureeEnHeures()).isEqualTo(0);
// Test avec les deux null
evenement.setHeureDebut(null);
evenement.setHeureFin(null);
assertThat(evenement.getDureeEnHeures()).isEqualTo(0);
}
@Test
@DisplayName("Test branches supplémentaires getAdresseComplete")
void testBranchesSupplementairesAdresseComplete() {
// Test avec adresse seulement (sans lieu)
evenement.setLieu(null);
evenement.setAdresse("123 Avenue Test");
evenement.setVille(null);
evenement.setRegion(null);
assertThat(evenement.getAdresseComplete()).isEqualTo("123 Avenue Test");
// Test avec ville seulement (sans lieu ni adresse)
evenement.setLieu(null);
evenement.setAdresse(null);
evenement.setVille("Dakar");
evenement.setRegion(null);
assertThat(evenement.getAdresseComplete()).isEqualTo("Dakar");
// Test avec région seulement
evenement.setLieu(null);
evenement.setAdresse(null);
evenement.setVille(null);
evenement.setRegion("Dakar");
assertThat(evenement.getAdresseComplete()).isEqualTo("Dakar");
// Test avec adresse et ville (sans lieu)
evenement.setLieu(null);
evenement.setAdresse("123 Avenue Test");
evenement.setVille("Dakar");
evenement.setRegion(null);
assertThat(evenement.getAdresseComplete()).isEqualTo("123 Avenue Test, Dakar");
}
}

View File

@@ -0,0 +1,144 @@
package dev.lions.unionflow.server.api.dto.evenement;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires simples pour EvenementDTO
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@DisplayName("Tests EvenementDTO")
class EvenementDTOSimpleTest {
private EvenementDTO evenement;
@BeforeEach
void setUp() {
evenement = new EvenementDTO();
}
@Test
@DisplayName("Test création et getters/setters de base")
void testCreationEtGettersSetters() {
// Données de test
String titre = "Formation Leadership";
String description = "Formation sur les techniques de leadership";
TypeEvenementMetier typeEvenement = TypeEvenementMetier.FORMATION;
StatutEvenement statut = StatutEvenement.PLANIFIE;
PrioriteEvenement priorite = PrioriteEvenement.NORMALE;
LocalDate dateDebut = LocalDate.now().plusDays(30);
LocalDate dateFin = LocalDate.now().plusDays(30);
LocalTime heureDebut = LocalTime.of(9, 0);
LocalTime heureFin = LocalTime.of(17, 0);
String lieu = "Centre de Formation";
Integer capaciteMax = 50;
BigDecimal budget = new BigDecimal("500000");
// Test des setters
evenement.setTitre(titre);
evenement.setDescription(description);
evenement.setTypeEvenement(typeEvenement);
evenement.setStatut(statut);
evenement.setPriorite(priorite);
evenement.setDateDebut(dateDebut);
evenement.setDateFin(dateFin);
evenement.setHeureDebut(heureDebut);
evenement.setHeureFin(heureFin);
evenement.setLieu(lieu);
evenement.setCapaciteMax(capaciteMax);
evenement.setBudget(budget);
// Test des getters
assertThat(evenement.getTitre()).isEqualTo(titre);
assertThat(evenement.getDescription()).isEqualTo(description);
assertThat(evenement.getTypeEvenement()).isEqualTo(typeEvenement);
assertThat(evenement.getStatut()).isEqualTo(statut);
assertThat(evenement.getPriorite()).isEqualTo(priorite);
assertThat(evenement.getDateDebut()).isEqualTo(dateDebut);
assertThat(evenement.getDateFin()).isEqualTo(dateFin);
assertThat(evenement.getHeureDebut()).isEqualTo(heureDebut);
assertThat(evenement.getHeureFin()).isEqualTo(heureFin);
assertThat(evenement.getLieu()).isEqualTo(lieu);
assertThat(evenement.getCapaciteMax()).isEqualTo(capaciteMax);
assertThat(evenement.getBudget()).isEqualTo(budget);
}
@Test
@DisplayName("Test constructeur avec paramètres")
void testConstructeurAvecParametres() {
String titre = "Assemblée Générale";
TypeEvenementMetier type = TypeEvenementMetier.ASSEMBLEE_GENERALE;
LocalDate date = LocalDate.now().plusDays(15);
String lieu = "Salle de conférence";
EvenementDTO newEvenement = new EvenementDTO(titre, type, date, lieu);
assertThat(newEvenement.getTitre()).isEqualTo(titre);
assertThat(newEvenement.getTypeEvenement()).isEqualTo(type);
assertThat(newEvenement.getDateDebut()).isEqualTo(date);
assertThat(newEvenement.getLieu()).isEqualTo(lieu);
assertThat(newEvenement.getStatut()).isEqualTo(StatutEvenement.PLANIFIE);
}
@Test
@DisplayName("Test méthodes utilitaires existantes")
void testMethodesUtilitaires() {
// Test des méthodes qui existent réellement
evenement.setStatut(StatutEvenement.EN_COURS);
assertThat(evenement.estEnCours()).isTrue();
evenement.setStatut(StatutEvenement.TERMINE);
assertThat(evenement.estTermine()).isTrue();
evenement.setStatut(StatutEvenement.ANNULE);
assertThat(evenement.estAnnule()).isTrue();
// Test capacité
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(25);
assertThat(evenement.estComplet()).isFalse();
assertThat(evenement.getPlacesDisponibles()).isEqualTo(25);
assertThat(evenement.getTauxRemplissage()).isEqualTo(50);
}
@Test
@DisplayName("Test validation des énumérations")
void testValidationEnumerations() {
// Test que toutes les énumérations sont bien supportées
for (TypeEvenementMetier type : TypeEvenementMetier.values()) {
evenement.setTypeEvenement(type);
assertThat(evenement.getTypeEvenement()).isEqualTo(type);
}
for (StatutEvenement statut : StatutEvenement.values()) {
evenement.setStatut(statut);
assertThat(evenement.getStatut()).isEqualTo(statut);
}
for (PrioriteEvenement priorite : PrioriteEvenement.values()) {
evenement.setPriorite(priorite);
assertThat(evenement.getPriorite()).isEqualTo(priorite);
}
}
@Test
@DisplayName("Test héritage BaseDTO")
void testHeritageBaseDTO() {
assertThat(evenement.getId()).isNotNull();
assertThat(evenement.getDateCreation()).isNotNull();
assertThat(evenement.isActif()).isTrue();
assertThat(evenement.getVersion()).isEqualTo(0L);
}
}

View File

@@ -0,0 +1,270 @@
package dev.lions.unionflow.server.api.dto.evenement;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires pour EvenementDTO
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@DisplayName("Tests EvenementDTO")
class EvenementDTOTest {
private EvenementDTO evenement;
@BeforeEach
void setUp() {
evenement = new EvenementDTO();
evenement.setTitre("Formation Leadership");
evenement.setStatut(StatutEvenement.PLANIFIE);
evenement.setPriorite(PrioriteEvenement.NORMALE);
evenement.setTypeEvenement(TypeEvenementMetier.FORMATION);
evenement.setDateDebut(LocalDate.now().plusDays(30));
evenement.setDateFin(LocalDate.now().plusDays(30));
evenement.setHeureDebut(LocalTime.of(9, 0));
evenement.setHeureFin(LocalTime.of(17, 0));
evenement.setLieu("Centre de Formation");
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(25);
evenement.setBudget(new BigDecimal("500000"));
evenement.setCoutReel(new BigDecimal("450000"));
evenement.setCodeDevise("XOF");
evenement.setAssociationId(UUID.randomUUID());
}
@Nested
@DisplayName("Tests de Construction")
class ConstructionTests {
@Test
@DisplayName("Test constructeur par défaut")
void testConstructeurParDefaut() {
EvenementDTO newEvenement = new EvenementDTO();
assertThat(newEvenement.getId()).isNotNull();
assertThat(newEvenement.getDateCreation()).isNotNull();
assertThat(newEvenement.isActif()).isTrue();
assertThat(newEvenement.getVersion()).isEqualTo(0L);
assertThat(newEvenement.getStatut()).isEqualTo(StatutEvenement.PLANIFIE);
assertThat(newEvenement.getPriorite()).isEqualTo(PrioriteEvenement.NORMALE);
assertThat(newEvenement.getParticipantsInscrits()).isEqualTo(0);
assertThat(newEvenement.getParticipantsPresents()).isEqualTo(0);
assertThat(newEvenement.getCodeDevise()).isEqualTo("XOF");
}
@Test
@DisplayName("Test constructeur avec paramètres")
void testConstructeurAvecParametres() {
String titre = "Assemblée Générale";
TypeEvenementMetier type = TypeEvenementMetier.ASSEMBLEE_GENERALE;
LocalDate date = LocalDate.now().plusDays(15);
EvenementDTO newEvenement = new EvenementDTO(titre, type, date, "Lieu par défaut");
assertThat(newEvenement.getTitre()).isEqualTo(titre);
assertThat(newEvenement.getTypeEvenement()).isEqualTo(type);
assertThat(newEvenement.getDateDebut()).isEqualTo(date);
assertThat(newEvenement.getStatut()).isEqualTo(StatutEvenement.PLANIFIE);
}
}
@Nested
@DisplayName("Tests des Méthodes Métier")
class MethodesMetierTests {
@Test
@DisplayName("Test estEnCours")
void testEstEnCours() {
evenement.setStatut(StatutEvenement.EN_COURS);
assertThat(evenement.estEnCours()).isTrue();
evenement.setStatut(StatutEvenement.PLANIFIE);
assertThat(evenement.estEnCours()).isFalse();
}
@Test
@DisplayName("Test estTermine")
void testEstTermine() {
evenement.setStatut(StatutEvenement.TERMINE);
assertThat(evenement.estTermine()).isTrue();
evenement.setStatut(StatutEvenement.EN_COURS);
assertThat(evenement.estTermine()).isFalse();
}
@Test
@DisplayName("Test estAnnule")
void testEstAnnule() {
evenement.setStatut(StatutEvenement.ANNULE);
assertThat(evenement.estAnnule()).isTrue();
evenement.setStatut(StatutEvenement.PLANIFIE);
assertThat(evenement.estAnnule()).isFalse();
}
@Test
@DisplayName("Test estComplet")
void testEstComplet() {
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(50);
assertThat(evenement.estComplet()).isTrue();
evenement.setParticipantsInscrits(49);
assertThat(evenement.estComplet()).isFalse();
evenement.setCapaciteMax(null);
assertThat(evenement.estComplet()).isFalse();
}
@Test
@DisplayName("Test getPlacesDisponibles")
void testGetPlacesDisponibles() {
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(25);
assertThat(evenement.getPlacesDisponibles()).isEqualTo(25);
evenement.setParticipantsInscrits(60); // Plus que la capacité
assertThat(evenement.getPlacesDisponibles()).isEqualTo(0);
evenement.setCapaciteMax(null);
assertThat(evenement.getPlacesDisponibles()).isEqualTo(0);
}
@Test
@DisplayName("Test getTauxRemplissage")
void testGetTauxRemplissage() {
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(25);
assertThat(evenement.getTauxRemplissage()).isEqualTo(50);
evenement.setParticipantsInscrits(50);
assertThat(evenement.getTauxRemplissage()).isEqualTo(100);
evenement.setCapaciteMax(0);
assertThat(evenement.getTauxRemplissage()).isEqualTo(0);
evenement.setCapaciteMax(null);
assertThat(evenement.getTauxRemplissage()).isEqualTo(0);
}
@Test
@DisplayName("Test sontInscriptionsOuvertes")
void testSontInscriptionsOuvertes() {
// Événement normal avec places disponibles
evenement.setStatut(StatutEvenement.PLANIFIE);
evenement.setCapaciteMax(50);
evenement.setParticipantsInscrits(25);
evenement.setDateLimiteInscription(LocalDate.now().plusDays(5));
assertThat(evenement.sontInscriptionsOuvertes()).isTrue();
// Événement annulé
evenement.setStatut(StatutEvenement.ANNULE);
assertThat(evenement.sontInscriptionsOuvertes()).isFalse();
// Événement terminé
evenement.setStatut(StatutEvenement.TERMINE);
assertThat(evenement.sontInscriptionsOuvertes()).isFalse();
// Événement complet
evenement.setStatut(StatutEvenement.PLANIFIE);
evenement.setParticipantsInscrits(50);
assertThat(evenement.sontInscriptionsOuvertes()).isFalse();
// Date limite dépassée
evenement.setParticipantsInscrits(25);
evenement.setDateLimiteInscription(LocalDate.now().minusDays(1));
assertThat(evenement.sontInscriptionsOuvertes()).isFalse();
}
@Test
@DisplayName("Test estEvenementMultiJours")
void testEstEvenementMultiJours() {
evenement.setDateDebut(LocalDate.now().plusDays(1));
evenement.setDateFin(LocalDate.now().plusDays(3));
assertThat(evenement.estEvenementMultiJours()).isTrue();
evenement.setDateFin(LocalDate.now().plusDays(1));
assertThat(evenement.estEvenementMultiJours()).isFalse();
evenement.setDateFin(null);
assertThat(evenement.estEvenementMultiJours()).isFalse();
}
@Test
@DisplayName("Test estBudgetDepasse")
void testEstBudgetDepasse() {
evenement.setBudget(new BigDecimal("500000"));
evenement.setCoutReel(new BigDecimal("600000"));
assertThat(evenement.estBudgetDepasse()).isTrue();
evenement.setCoutReel(new BigDecimal("400000"));
assertThat(evenement.estBudgetDepasse()).isFalse();
evenement.setCoutReel(new BigDecimal("500000"));
assertThat(evenement.estBudgetDepasse()).isFalse();
}
}
@Nested
@DisplayName("Tests des Méthodes Utilitaires")
class MethodesUtilitairesTests {
@Test
@DisplayName("Test getStatutLibelle")
void testGetStatutLibelle() {
evenement.setStatut(StatutEvenement.PLANIFIE);
assertThat(evenement.getStatutLibelle()).isEqualTo("Planifié");
evenement.setStatut(null);
assertThat(evenement.getStatutLibelle()).isEqualTo("Non défini");
}
@Test
@DisplayName("Test getPrioriteLibelle")
void testGetPrioriteLibelle() {
evenement.setPriorite(PrioriteEvenement.HAUTE);
assertThat(evenement.getPrioriteLibelle()).isEqualTo("Haute");
evenement.setPriorite(null);
assertThat(evenement.getPrioriteLibelle()).isEqualTo("Normale");
}
@Test
@DisplayName("Test getTypeEvenementLibelle")
void testGetTypeEvenementLibelle() {
evenement.setTypeEvenement(TypeEvenementMetier.FORMATION);
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Formation");
evenement.setTypeEvenement(null);
assertThat(evenement.getTypeEvenementLibelle()).isEqualTo("Non défini");
}
@Test
@DisplayName("Test getEcartBudgetaire")
void testGetEcartBudgetaire() {
evenement.setBudget(new BigDecimal("500000"));
evenement.setCoutReel(new BigDecimal("450000"));
assertThat(evenement.getEcartBudgetaire()).isEqualTo(new BigDecimal("50000"));
evenement.setCoutReel(new BigDecimal("550000"));
assertThat(evenement.getEcartBudgetaire()).isEqualTo(new BigDecimal("-50000"));
evenement.setBudget(null);
assertThat(evenement.getEcartBudgetaire()).isEqualTo(BigDecimal.ZERO);
}
}
}

View File

@@ -121,8 +121,6 @@ class CotisationDTOBasicTest {
assertThat(cotisation.getDatePaiement()).isNotNull();
}
@Test
@DisplayName("Test méthodes métier avancées")
void testMethodesMetierAvancees() {
@@ -276,7 +274,8 @@ class CotisationDTOBasicTest {
BigDecimal montantDu = new BigDecimal("25000.00");
LocalDate dateEcheance = LocalDate.of(2025, 1, 31);
CotisationDTO newCotisation = new CotisationDTO(membreId, typeCotisation, montantDu, dateEcheance);
CotisationDTO newCotisation =
new CotisationDTO(membreId, typeCotisation, montantDu, dateEcheance);
assertThat(newCotisation.getMembreId()).isEqualTo(membreId);
assertThat(newCotisation.getTypeCotisation()).isEqualTo(typeCotisation);
@@ -284,7 +283,8 @@ class CotisationDTOBasicTest {
assertThat(newCotisation.getDateEcheance()).isEqualTo(dateEcheance);
assertThat(newCotisation.getNumeroReference()).isNotNull();
assertThat(newCotisation.getNumeroReference()).startsWith("COT-");
assertThat(newCotisation.getNumeroReference()).contains(String.valueOf(LocalDate.now().getYear()));
assertThat(newCotisation.getNumeroReference())
.contains(String.valueOf(LocalDate.now().getYear()));
// Vérifier que les valeurs par défaut sont toujours appliquées
assertThat(newCotisation.getMontantPaye()).isEqualByComparingTo(BigDecimal.ZERO);
assertThat(newCotisation.getCodeDevise()).isEqualTo("XOF");
@@ -474,7 +474,8 @@ class CotisationDTOBasicTest {
cotisation.setDatePaiement(datePaiementExistante);
cotisation.mettreAJourStatut();
assertThat(cotisation.getStatut()).isEqualTo("PAYEE");
assertThat(cotisation.getDatePaiement()).isEqualTo(datePaiementExistante); // Ne doit pas changer
assertThat(cotisation.getDatePaiement())
.isEqualTo(datePaiementExistante); // Ne doit pas changer
// Test avec paiement partiel
cotisation.setMontantDu(BigDecimal.valueOf(1000));

View File

@@ -300,7 +300,8 @@ class FormuleAbonnementDTOBasicTest {
formule.setPrixAnnuel(new BigDecimal("100000.00"));
BigDecimal economieAttendue = new BigDecimal("20000.00"); // 12*10000 - 100000
assertThat(formule.getEconomieAnnuelle()).isEqualTo(economieAttendue);
assertThat(formule.getPourcentageEconomieAnnuelle()).isEqualTo(17); // 20000/120000 * 100 = 16.67 arrondi à 17
assertThat(formule.getPourcentageEconomieAnnuelle())
.isEqualTo(17); // 20000/120000 * 100 = 16.67 arrondi à 17
// Cas sans économie
formule.setPrixMensuel(new BigDecimal("10000.00"));
@@ -422,9 +423,9 @@ class FormuleAbonnementDTOBasicTest {
assertThat(formule.getScoreFonctionnalites()).isEqualTo(100);
// Test cas intermédiaire : seulement quelques fonctionnalités
formule.setSupportTechnique(true); // +10
formule.setSupportTechnique(true); // +10
formule.setSauvegardeAutomatique(false);
formule.setFonctionnalitesAvancees(true); // +15
formule.setFonctionnalitesAvancees(true); // +15
formule.setApiAccess(false);
formule.setRapportsPersonnalises(false);
formule.setIntegrationsTierces(false);
@@ -447,7 +448,7 @@ class FormuleAbonnementDTOBasicTest {
assertThat(formule.getScoreFonctionnalites()).isEqualTo(0);
// Test avec un seul élément activé pour vérifier la division
formule.setSupportTechnique(true); // score = 10, total = 100
formule.setSupportTechnique(true); // score = 10, total = 100
formule.setSauvegardeAutomatique(false);
formule.setFonctionnalitesAvancees(false);
formule.setApiAccess(false);

View File

@@ -1,442 +0,0 @@
package dev.lions.unionflow.server.api.dto.membre;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.LocalDate;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires complets pour MembreDTO.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-10
*/
@DisplayName("Tests MembreDTO")
class MembreDTOBasicTest {
private MembreDTO membre;
@BeforeEach
void setUp() {
membre = new MembreDTO();
}
@Test
@DisplayName("Constructeur par défaut - Initialisation correcte")
void testConstructeurParDefaut() {
MembreDTO newMembre = new MembreDTO();
assertThat(newMembre.getId()).isNotNull();
assertThat(newMembre.getDateCreation()).isNotNull();
assertThat(newMembre.isActif()).isTrue();
assertThat(newMembre.getVersion()).isEqualTo(0L);
}
@Test
@DisplayName("Test getters/setters principaux")
void testGettersSettersPrincipaux() {
// Données de test
String numeroMembre = "M001";
String prenom = "Jean";
String nom = "Dupont";
String email = "jean.dupont@example.com";
String telephone = "+221701234567";
LocalDate dateNaissance = LocalDate.of(1980, 5, 15);
String adresse = "123 Rue de la Paix";
String ville = "Dakar";
String profession = "Ingénieur";
LocalDate dateAdhesion = LocalDate.now().minusYears(2);
String statut = "ACTIF";
Long associationId = 123L;
String associationNom = "Lions Club Dakar";
String region = "Dakar";
String quartier = "Plateau";
String role = "Membre";
Boolean membreBureau = true;
Boolean responsable = false;
String photoUrl = "https://example.com/photo.jpg";
// Test des setters
membre.setNumeroMembre(numeroMembre);
membre.setPrenom(prenom);
membre.setNom(nom);
membre.setEmail(email);
membre.setTelephone(telephone);
membre.setDateNaissance(dateNaissance);
membre.setAdresse(adresse);
membre.setVille(ville);
membre.setProfession(profession);
membre.setDateAdhesion(dateAdhesion);
membre.setStatut(statut);
membre.setAssociationId(associationId);
membre.setAssociationNom(associationNom);
membre.setRegion(region);
membre.setQuartier(quartier);
membre.setRole(role);
membre.setMembreBureau(membreBureau);
membre.setResponsable(responsable);
membre.setPhotoUrl(photoUrl);
// Test des getters
assertThat(membre.getNumeroMembre()).isEqualTo(numeroMembre);
assertThat(membre.getPrenom()).isEqualTo(prenom);
assertThat(membre.getNom()).isEqualTo(nom);
assertThat(membre.getEmail()).isEqualTo(email);
assertThat(membre.getTelephone()).isEqualTo(telephone);
assertThat(membre.getDateNaissance()).isEqualTo(dateNaissance);
assertThat(membre.getAdresse()).isEqualTo(adresse);
assertThat(membre.getVille()).isEqualTo(ville);
assertThat(membre.getProfession()).isEqualTo(profession);
assertThat(membre.getDateAdhesion()).isEqualTo(dateAdhesion);
assertThat(membre.getStatut()).isEqualTo(statut);
assertThat(membre.getAssociationId()).isEqualTo(associationId);
assertThat(membre.getAssociationNom()).isEqualTo(associationNom);
assertThat(membre.getRegion()).isEqualTo(region);
assertThat(membre.getQuartier()).isEqualTo(quartier);
assertThat(membre.getRole()).isEqualTo(role);
assertThat(membre.getMembreBureau()).isEqualTo(membreBureau);
assertThat(membre.getResponsable()).isEqualTo(responsable);
assertThat(membre.getPhotoUrl()).isEqualTo(photoUrl);
}
@Test
@DisplayName("Test méthodes métier")
void testMethodesMetier() {
// Test getNomComplet
membre.setPrenom("Jean");
membre.setNom("Dupont");
assertThat(membre.getNomComplet()).isEqualTo("Jean Dupont");
// Test avec prenom null
membre.setPrenom(null);
assertThat(membre.getNomComplet()).isEqualTo("Dupont");
// Test avec nom null
membre.setPrenom("Jean");
membre.setNom(null);
assertThat(membre.getNomComplet()).isEqualTo("Jean");
// Test getAge
membre.setDateNaissance(LocalDate.now().minusYears(30));
int age = membre.getAge();
assertThat(age).isEqualTo(30);
// Test avec date null
membre.setDateNaissance(null);
assertThat(membre.getAge()).isEqualTo(-1);
// Test isMajeur
membre.setDateNaissance(LocalDate.now().minusYears(25));
assertThat(membre.isMajeur()).isTrue();
membre.setDateNaissance(LocalDate.now().minusYears(15));
assertThat(membre.isMajeur()).isFalse();
membre.setDateNaissance(null);
assertThat(membre.isMajeur()).isFalse();
// Test isActif
membre.setStatut("ACTIF");
assertThat(membre.isActif()).isTrue();
membre.setStatut("INACTIF");
assertThat(membre.isActif()).isFalse();
// Test hasRoleDirection
membre.setMembreBureau(true);
membre.setResponsable(false);
assertThat(membre.hasRoleDirection()).isTrue();
membre.setMembreBureau(false);
membre.setResponsable(true);
assertThat(membre.hasRoleDirection()).isTrue();
membre.setMembreBureau(false);
membre.setResponsable(false);
assertThat(membre.hasRoleDirection()).isFalse();
// Test getStatutLibelle
membre.setStatut("ACTIF");
assertThat(membre.getStatutLibelle()).isEqualTo("Actif");
membre.setStatut("INACTIF");
assertThat(membre.getStatutLibelle()).isEqualTo("Inactif");
membre.setStatut("SUSPENDU");
assertThat(membre.getStatutLibelle()).isEqualTo("Suspendu");
membre.setStatut("RADIE");
assertThat(membre.getStatutLibelle()).isEqualTo("Radié");
membre.setStatut(null);
assertThat(membre.getStatutLibelle()).isEqualTo("Non défini");
// Test isDataValid - cas valide (selon l'implémentation réelle)
membre.setNumeroMembre("UF-2025-12345678");
membre.setNom("Dupont");
membre.setPrenom("Jean");
membre.setEmail("jean.dupont@example.com");
// Vérifier d'abord si la méthode existe et ce qu'elle teste réellement
boolean isValid = membre.isDataValid();
assertThat(isValid).isNotNull(); // Au moins vérifier qu'elle ne plante pas
// Test isDataValid - numéro membre null
membre.setNumeroMembre(null);
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - numéro membre vide
membre.setNumeroMembre("");
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - numéro membre avec espaces
membre.setNumeroMembre(" ");
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - nom null
membre.setNumeroMembre("UF-2025-12345678");
membre.setNom(null);
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - nom vide
membre.setNom("");
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - nom avec espaces
membre.setNom(" ");
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - prénom null
membre.setNom("Dupont");
membre.setPrenom(null);
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - prénom vide
membre.setPrenom("");
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - prénom avec espaces
membre.setPrenom(" ");
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - email null
membre.setPrenom("Jean");
membre.setEmail(null);
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - email vide
membre.setEmail("");
assertThat(membre.isDataValid()).isFalse();
// Test isDataValid - email avec espaces
membre.setEmail(" ");
assertThat(membre.isDataValid()).isFalse();
}
@Test
@DisplayName("Test constructeur avec paramètres")
void testConstructeurAvecParametres() {
String numeroMembre = "UF-2025-001";
String nom = "Dupont";
String prenom = "Jean";
String email = "jean.dupont@example.com";
MembreDTO nouveauMembre = new MembreDTO(numeroMembre, nom, prenom, email);
assertThat(nouveauMembre.getNumeroMembre()).isEqualTo(numeroMembre);
assertThat(nouveauMembre.getNom()).isEqualTo(nom);
assertThat(nouveauMembre.getPrenom()).isEqualTo(prenom);
assertThat(nouveauMembre.getEmail()).isEqualTo(email);
// Vérifier les valeurs par défaut
assertThat(nouveauMembre.getStatut()).isEqualTo("ACTIF");
assertThat(nouveauMembre.getDateAdhesion()).isEqualTo(LocalDate.now());
assertThat(nouveauMembre.getMembreBureau()).isFalse();
assertThat(nouveauMembre.getResponsable()).isFalse();
}
@Test
@DisplayName("Test tous les statuts")
void testTousLesStatuts() {
// Test tous les statuts possibles (selon le switch dans la classe)
membre.setStatut("EXCLU");
assertThat(membre.getStatutLibelle()).isEqualTo("EXCLU"); // Valeur par défaut car non dans le switch
membre.setStatut("DEMISSIONNAIRE");
assertThat(membre.getStatutLibelle()).isEqualTo("DEMISSIONNAIRE"); // Valeur par défaut car non dans le switch
membre.setStatut("STATUT_INCONNU");
assertThat(membre.getStatutLibelle()).isEqualTo("STATUT_INCONNU");
}
@Test
@DisplayName("Test getNomComplet cas limites")
void testGetNomCompletCasLimites() {
// Test avec les deux null - retourne chaîne vide selon l'implémentation
membre.setPrenom(null);
membre.setNom(null);
assertThat(membre.getNomComplet()).isEqualTo("");
// Test avec prénom vide - l'implémentation concatène quand même
membre.setPrenom("");
membre.setNom("Dupont");
assertThat(membre.getNomComplet()).isEqualTo(" Dupont");
// Test avec nom vide - l'implémentation concatène quand même
membre.setPrenom("Jean");
membre.setNom("");
assertThat(membre.getNomComplet()).isEqualTo("Jean ");
}
@Test
@DisplayName("Test hasRoleDirection cas limites")
void testHasRoleDirectionCasLimites() {
// Test avec null
membre.setMembreBureau(null);
membre.setResponsable(null);
assertThat(membre.hasRoleDirection()).isFalse();
// Test avec Boolean.FALSE explicite
membre.setMembreBureau(Boolean.FALSE);
membre.setResponsable(Boolean.FALSE);
assertThat(membre.hasRoleDirection()).isFalse();
// Test avec Boolean.TRUE explicite
membre.setMembreBureau(Boolean.TRUE);
membre.setResponsable(Boolean.FALSE);
assertThat(membre.hasRoleDirection()).isTrue();
membre.setMembreBureau(Boolean.FALSE);
membre.setResponsable(Boolean.TRUE);
assertThat(membre.hasRoleDirection()).isTrue();
}
@Test
@DisplayName("Test toString complet")
void testToStringComplet() {
membre.setNumeroMembre("UF-2025-001");
membre.setPrenom("Jean");
membre.setNom("Dupont");
membre.setEmail("jean.dupont@example.com");
membre.setStatut("ACTIF");
membre.setAssociationId(123L);
String result = membre.toString();
assertThat(result).isNotNull();
assertThat(result).contains("MembreDTO");
assertThat(result).contains("numeroMembre='UF-2025-001'");
assertThat(result).contains("nom='Dupont'");
assertThat(result).contains("prenom='Jean'");
assertThat(result).contains("email='jean.dupont@example.com'");
assertThat(result).contains("statut='ACTIF'");
assertThat(result).contains("associationId=123");
}
@Test
@DisplayName("Test propriétés supplémentaires")
void testProprietesSupplementaires() {
// Test des propriétés qui pourraient ne pas être couvertes
String statutMatrimonial = "MARIE";
String nationalite = "Sénégalaise";
String numeroIdentite = "1234567890123";
String typeIdentite = "CNI";
LocalDate dateAdhesion = LocalDate.of(2020, 1, 15);
membre.setStatutMatrimonial(statutMatrimonial);
membre.setNationalite(nationalite);
membre.setNumeroIdentite(numeroIdentite);
membre.setTypeIdentite(typeIdentite);
membre.setDateAdhesion(dateAdhesion);
assertThat(membre.getStatutMatrimonial()).isEqualTo(statutMatrimonial);
assertThat(membre.getNationalite()).isEqualTo(nationalite);
assertThat(membre.getNumeroIdentite()).isEqualTo(numeroIdentite);
assertThat(membre.getTypeIdentite()).isEqualTo(typeIdentite);
assertThat(membre.getDateAdhesion()).isEqualTo(dateAdhesion);
}
@Test
@DisplayName("Test branches supplémentaires isDataValid")
void testBranchesSupplementairesIsDataValid() {
// Test avec tous les champs valides
membre.setNumeroMembre("UF-2025-001");
membre.setNom("Dupont");
membre.setPrenom("Jean");
membre.setStatut("ACTIF");
membre.setAssociationId(123L);
assertThat(membre.isDataValid()).isTrue();
// Test avec numéro membre avec espaces seulement
membre.setNumeroMembre(" ");
assertThat(membre.isDataValid()).isFalse();
// Test avec nom avec espaces seulement
membre.setNumeroMembre("UF-2025-001");
membre.setNom(" ");
assertThat(membre.isDataValid()).isFalse();
// Test avec prénom avec espaces seulement
membre.setNom("Dupont");
membre.setPrenom(" ");
assertThat(membre.isDataValid()).isFalse();
// Test avec statut avec espaces seulement
membre.setPrenom("Jean");
membre.setStatut(" ");
assertThat(membre.isDataValid()).isFalse();
// Test avec statut null
membre.setStatut(null);
assertThat(membre.isDataValid()).isFalse();
// Test avec associationId null
membre.setStatut("ACTIF");
membre.setAssociationId(null);
assertThat(membre.isDataValid()).isFalse();
}
@Test
@DisplayName("Test branches supplémentaires isMajeur")
void testBranchesSupplementairesIsMajeur() {
// Test avec date exactement 18 ans
LocalDate dateExactement18Ans = LocalDate.now().minusYears(18);
membre.setDateNaissance(dateExactement18Ans);
assertThat(membre.isMajeur()).isTrue();
// Test avec date plus de 18 ans
LocalDate datePlus18Ans = LocalDate.now().minusYears(25);
membre.setDateNaissance(datePlus18Ans);
assertThat(membre.isMajeur()).isTrue();
// Test avec date moins de 18 ans
LocalDate dateMoins18Ans = LocalDate.now().minusYears(15);
membre.setDateNaissance(dateMoins18Ans);
assertThat(membre.isMajeur()).isFalse();
}
@Test
@DisplayName("Test branches supplémentaires hasRoleDirection")
void testBranchesSupplementairesHasRoleDirection() {
// Test avec membreBureau true et responsable false
membre.setMembreBureau(Boolean.TRUE);
membre.setResponsable(Boolean.FALSE);
assertThat(membre.hasRoleDirection()).isTrue();
// Test avec membreBureau false et responsable true
membre.setMembreBureau(Boolean.FALSE);
membre.setResponsable(Boolean.TRUE);
assertThat(membre.hasRoleDirection()).isTrue();
// Test avec les deux false
membre.setMembreBureau(Boolean.FALSE);
membre.setResponsable(Boolean.FALSE);
assertThat(membre.hasRoleDirection()).isFalse();
// Test avec les deux null
membre.setMembreBureau(null);
membre.setResponsable(null);
assertThat(membre.hasRoleDirection()).isFalse();
}
}

View File

@@ -1,611 +0,0 @@
package dev.lions.unionflow.server.api.dto.organisation;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.enums.organisation.StatutOrganisation;
import dev.lions.unionflow.server.api.enums.organisation.TypeOrganisation;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires complets pour OrganisationDTO.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-10
*/
@DisplayName("Tests OrganisationDTO")
class OrganisationDTOBasicTest {
private OrganisationDTO organisation;
@BeforeEach
void setUp() {
organisation = new OrganisationDTO();
}
@Nested
@DisplayName("Tests de Construction")
class ConstructionTests {
@Test
@DisplayName("Constructeur par défaut - Initialisation correcte")
void testConstructeurParDefaut() {
OrganisationDTO newOrganisation = new OrganisationDTO();
assertThat(newOrganisation.getId()).isNotNull();
assertThat(newOrganisation.getDateCreation()).isNotNull();
assertThat(newOrganisation.isActif()).isTrue();
assertThat(newOrganisation.getVersion()).isEqualTo(0L);
assertThat(newOrganisation.getStatut()).isEqualTo(StatutOrganisation.ACTIVE);
assertThat(newOrganisation.getNombreMembres()).isEqualTo(0);
assertThat(newOrganisation.getNombreAdministrateurs()).isEqualTo(0);
assertThat(newOrganisation.getBudgetAnnuel()).isNull();
}
@Test
@DisplayName("Constructeur avec paramètres - Initialisation correcte")
void testConstructeurAvecParametres() {
String nom = "Lions Club Dakar";
TypeOrganisation type = TypeOrganisation.LIONS_CLUB;
OrganisationDTO newOrganisation = new OrganisationDTO(nom, type);
assertThat(newOrganisation.getNom()).isEqualTo(nom);
assertThat(newOrganisation.getTypeOrganisation()).isEqualTo(type);
assertThat(newOrganisation.getStatut()).isEqualTo(StatutOrganisation.ACTIVE);
}
}
@Nested
@DisplayName("Tests Getters/Setters")
class GettersSettersTests {
@Test
@DisplayName("Test tous les getters/setters - Partie 1")
void testTousLesGettersSettersPart1() {
// Données de test
String nom = "Lions Club Dakar";
String nomCourt = "LCD";
TypeOrganisation typeOrganisation = TypeOrganisation.LIONS_CLUB;
StatutOrganisation statut = StatutOrganisation.ACTIVE;
String numeroEnregistrement = "REG-2025-001";
LocalDate dateFondation = LocalDate.of(2020, 1, 15);
String description = "Club service Lions de Dakar";
String adresse = "123 Avenue Bourguiba";
String ville = "Dakar";
String region = "Dakar";
String pays = "Sénégal";
String codePostal = "10000";
String telephone = "+221338234567";
String email = "contact@lionsclubdakar.sn";
String siteWeb = "https://lionsclubdakar.sn";
// Test des setters
organisation.setNom(nom);
organisation.setNomCourt(nomCourt);
organisation.setTypeOrganisation(typeOrganisation);
organisation.setStatut(statut);
organisation.setNumeroEnregistrement(numeroEnregistrement);
organisation.setDateFondation(dateFondation);
organisation.setDescription(description);
organisation.setAdresse(adresse);
organisation.setVille(ville);
organisation.setRegion(region);
organisation.setPays(pays);
organisation.setCodePostal(codePostal);
organisation.setTelephone(telephone);
organisation.setEmail(email);
organisation.setSiteWeb(siteWeb);
// Test des getters
assertThat(organisation.getNom()).isEqualTo(nom);
assertThat(organisation.getNomCourt()).isEqualTo(nomCourt);
assertThat(organisation.getTypeOrganisation()).isEqualTo(typeOrganisation);
assertThat(organisation.getStatut()).isEqualTo(statut);
assertThat(organisation.getNumeroEnregistrement()).isEqualTo(numeroEnregistrement);
assertThat(organisation.getDateFondation()).isEqualTo(dateFondation);
assertThat(organisation.getDescription()).isEqualTo(description);
assertThat(organisation.getAdresse()).isEqualTo(adresse);
assertThat(organisation.getVille()).isEqualTo(ville);
assertThat(organisation.getRegion()).isEqualTo(region);
assertThat(organisation.getPays()).isEqualTo(pays);
assertThat(organisation.getCodePostal()).isEqualTo(codePostal);
assertThat(organisation.getTelephone()).isEqualTo(telephone);
assertThat(organisation.getEmail()).isEqualTo(email);
assertThat(organisation.getSiteWeb()).isEqualTo(siteWeb);
}
@Test
@DisplayName("Test getters/setters - Géolocalisation et hiérarchie")
void testGettersSettersGeolocalisationHierarchie() {
// Données de test
BigDecimal latitude = new BigDecimal("14.6937");
BigDecimal longitude = new BigDecimal("-17.4441");
UUID organisationParenteId = UUID.randomUUID();
String nomOrganisationParente = "Lions District 403";
Integer niveauHierarchique = 2;
Integer nombreMembres = 50;
Integer nombreAdministrateurs = 5;
BigDecimal budgetAnnuel = new BigDecimal("5000000.00");
String devise = "XOF";
// Test des setters
organisation.setLatitude(latitude);
organisation.setLongitude(longitude);
organisation.setOrganisationParenteId(organisationParenteId);
organisation.setNomOrganisationParente(nomOrganisationParente);
organisation.setNiveauHierarchique(niveauHierarchique);
organisation.setNombreMembres(nombreMembres);
organisation.setNombreAdministrateurs(nombreAdministrateurs);
organisation.setBudgetAnnuel(budgetAnnuel);
organisation.setDevise(devise);
// Test des getters
assertThat(organisation.getLatitude()).isEqualTo(latitude);
assertThat(organisation.getLongitude()).isEqualTo(longitude);
assertThat(organisation.getOrganisationParenteId()).isEqualTo(organisationParenteId);
assertThat(organisation.getNomOrganisationParente()).isEqualTo(nomOrganisationParente);
assertThat(organisation.getNiveauHierarchique()).isEqualTo(niveauHierarchique);
assertThat(organisation.getNombreMembres()).isEqualTo(nombreMembres);
assertThat(organisation.getNombreAdministrateurs()).isEqualTo(nombreAdministrateurs);
assertThat(organisation.getBudgetAnnuel()).isEqualTo(budgetAnnuel);
assertThat(organisation.getDevise()).isEqualTo(devise);
}
@Test
@DisplayName("Test getters/setters - Informations complémentaires")
void testGettersSettersInformationsComplementaires() {
// Données de test
String objectifs = "Servir la communauté";
String activitesPrincipales = "Actions sociales, environnement";
String reseauxSociaux = "{\"facebook\":\"@lionsclub\"}";
String certifications = "ISO 9001";
String partenaires = "UNICEF, Croix-Rouge";
String notes = "Notes administratives";
Boolean organisationPublique = true;
Boolean accepteNouveauxMembres = true;
Boolean cotisationObligatoire = true;
BigDecimal montantCotisationAnnuelle = new BigDecimal("50000.00");
// Test des setters
organisation.setObjectifs(objectifs);
organisation.setActivitesPrincipales(activitesPrincipales);
organisation.setReseauxSociaux(reseauxSociaux);
organisation.setCertifications(certifications);
organisation.setPartenaires(partenaires);
organisation.setNotes(notes);
organisation.setOrganisationPublique(organisationPublique);
organisation.setAccepteNouveauxMembres(accepteNouveauxMembres);
organisation.setCotisationObligatoire(cotisationObligatoire);
organisation.setMontantCotisationAnnuelle(montantCotisationAnnuelle);
// Test des getters
assertThat(organisation.getObjectifs()).isEqualTo(objectifs);
assertThat(organisation.getActivitesPrincipales()).isEqualTo(activitesPrincipales);
assertThat(organisation.getReseauxSociaux()).isEqualTo(reseauxSociaux);
assertThat(organisation.getCertifications()).isEqualTo(certifications);
assertThat(organisation.getPartenaires()).isEqualTo(partenaires);
assertThat(organisation.getNotes()).isEqualTo(notes);
assertThat(organisation.getOrganisationPublique()).isEqualTo(organisationPublique);
assertThat(organisation.getAccepteNouveauxMembres()).isEqualTo(accepteNouveauxMembres);
assertThat(organisation.getCotisationObligatoire()).isEqualTo(cotisationObligatoire);
assertThat(organisation.getMontantCotisationAnnuelle()).isEqualTo(montantCotisationAnnuelle);
}
@Test
@DisplayName("Test tous les getters/setters - Partie 2")
void testTousLesGettersSettersPart2() {
// Données de test
UUID organisationParenteId = UUID.randomUUID();
String nomOrganisationParente = "Lions District 403";
Integer nombreMembres = 45;
Integer nombreAdministrateurs = 7;
BigDecimal budgetAnnuel = new BigDecimal("5000000.00");
String devise = "XOF";
BigDecimal latitude = new BigDecimal("14.6937");
BigDecimal longitude = new BigDecimal("-17.4441");
String telephoneSecondaire = "+221338765432";
String emailSecondaire = "info@lionsclubdakar.sn";
String logo = "logo_lions_dakar.png";
Integer niveauHierarchique = 2;
// Test des setters
organisation.setOrganisationParenteId(organisationParenteId);
organisation.setNomOrganisationParente(nomOrganisationParente);
organisation.setNombreMembres(nombreMembres);
organisation.setNombreAdministrateurs(nombreAdministrateurs);
organisation.setBudgetAnnuel(budgetAnnuel);
organisation.setDevise(devise);
organisation.setLatitude(latitude);
organisation.setLongitude(longitude);
organisation.setTelephoneSecondaire(telephoneSecondaire);
organisation.setEmailSecondaire(emailSecondaire);
organisation.setLogo(logo);
organisation.setNiveauHierarchique(niveauHierarchique);
// Test des getters
assertThat(organisation.getOrganisationParenteId()).isEqualTo(organisationParenteId);
assertThat(organisation.getNomOrganisationParente()).isEqualTo(nomOrganisationParente);
assertThat(organisation.getNombreMembres()).isEqualTo(nombreMembres);
assertThat(organisation.getNombreAdministrateurs()).isEqualTo(nombreAdministrateurs);
assertThat(organisation.getBudgetAnnuel()).isEqualTo(budgetAnnuel);
assertThat(organisation.getDevise()).isEqualTo(devise);
assertThat(organisation.getLatitude()).isEqualTo(latitude);
assertThat(organisation.getLongitude()).isEqualTo(longitude);
assertThat(organisation.getTelephoneSecondaire()).isEqualTo(telephoneSecondaire);
assertThat(organisation.getEmailSecondaire()).isEqualTo(emailSecondaire);
assertThat(organisation.getLogo()).isEqualTo(logo);
assertThat(organisation.getNiveauHierarchique()).isEqualTo(niveauHierarchique);
}
}
@Nested
@DisplayName("Tests des méthodes métier")
class MethodesMetierTests {
@Test
@DisplayName("Test méthodes de statut")
void testMethodesStatut() {
// Test isActive
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.isActive()).isTrue();
organisation.setStatut(StatutOrganisation.INACTIVE);
assertThat(organisation.isActive()).isFalse();
// Test isInactive
organisation.setStatut(StatutOrganisation.INACTIVE);
assertThat(organisation.isInactive()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.isInactive()).isFalse();
// Test isSuspendue
organisation.setStatut(StatutOrganisation.SUSPENDUE);
assertThat(organisation.isSuspendue()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.isSuspendue()).isFalse();
// Test isEnCreation
organisation.setStatut(StatutOrganisation.EN_CREATION);
assertThat(organisation.isEnCreation()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.isEnCreation()).isFalse();
// Test isDissoute
organisation.setStatut(StatutOrganisation.DISSOUTE);
assertThat(organisation.isDissoute()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.isDissoute()).isFalse();
}
@Test
@DisplayName("Test calculs d'ancienneté")
void testCalculsAnciennete() {
// Cas sans date de fondation
organisation.setDateFondation(null);
assertThat(organisation.getAncienneteAnnees()).isEqualTo(0);
assertThat(organisation.getAncienneteMois()).isEqualTo(0);
// Cas avec date de fondation il y a 5 ans
LocalDate dateFondation = LocalDate.now().minusYears(5).minusMonths(3);
organisation.setDateFondation(dateFondation);
assertThat(organisation.getAncienneteAnnees()).isEqualTo(5);
assertThat(organisation.getAncienneteMois()).isEqualTo(63); // 5*12 + 3
// Cas avec date de fondation récente (moins d'un an)
dateFondation = LocalDate.now().minusMonths(8);
organisation.setDateFondation(dateFondation);
assertThat(organisation.getAncienneteAnnees()).isEqualTo(0);
assertThat(organisation.getAncienneteMois()).isEqualTo(8);
}
@Test
@DisplayName("Test hasGeolocalisation")
void testHasGeolocalisation() {
// Cas sans géolocalisation
organisation.setLatitude(null);
organisation.setLongitude(null);
assertThat(organisation.hasGeolocalisation()).isFalse();
// Cas avec latitude seulement
organisation.setLatitude(new BigDecimal("14.6937"));
organisation.setLongitude(null);
assertThat(organisation.hasGeolocalisation()).isFalse();
// Cas avec longitude seulement
organisation.setLatitude(null);
organisation.setLongitude(new BigDecimal("-17.4441"));
assertThat(organisation.hasGeolocalisation()).isFalse();
// Cas avec géolocalisation complète
organisation.setLatitude(new BigDecimal("14.6937"));
organisation.setLongitude(new BigDecimal("-17.4441"));
assertThat(organisation.hasGeolocalisation()).isTrue();
}
@Test
@DisplayName("Test hiérarchie")
void testHierarchie() {
// Test isOrganisationRacine
organisation.setOrganisationParenteId(null);
assertThat(organisation.isOrganisationRacine()).isTrue();
organisation.setOrganisationParenteId(UUID.randomUUID());
assertThat(organisation.isOrganisationRacine()).isFalse();
// Test hasSousOrganisations
organisation.setNiveauHierarchique(null);
assertThat(organisation.hasSousOrganisations()).isFalse();
organisation.setNiveauHierarchique(0);
assertThat(organisation.hasSousOrganisations()).isFalse();
organisation.setNiveauHierarchique(1);
assertThat(organisation.hasSousOrganisations()).isTrue();
organisation.setNiveauHierarchique(3);
assertThat(organisation.hasSousOrganisations()).isTrue();
}
@Test
@DisplayName("Test getNomAffichage")
void testGetNomAffichage() {
String nomComplet = "Lions Club Dakar Plateau";
String nomCourt = "LCD Plateau";
// Cas avec nom court
organisation.setNom(nomComplet);
organisation.setNomCourt(nomCourt);
assertThat(organisation.getNomAffichage()).isEqualTo(nomCourt);
// Cas avec nom court vide
organisation.setNomCourt("");
assertThat(organisation.getNomAffichage()).isEqualTo(nomComplet);
// Cas avec nom court null
organisation.setNomCourt(null);
assertThat(organisation.getNomAffichage()).isEqualTo(nomComplet);
// Cas avec nom court contenant seulement des espaces
organisation.setNomCourt(" ");
assertThat(organisation.getNomAffichage()).isEqualTo(nomComplet);
}
@Test
@DisplayName("Test getAdresseComplete")
void testGetAdresseComplete() {
// Cas avec adresse complète
organisation.setAdresse("123 Avenue Bourguiba");
organisation.setVille("Dakar");
organisation.setCodePostal("10000");
organisation.setRegion("Dakar");
organisation.setPays("Sénégal");
String adresseComplete = organisation.getAdresseComplete();
assertThat(adresseComplete).contains("123 Avenue Bourguiba");
assertThat(adresseComplete).contains("Dakar");
assertThat(adresseComplete).contains("10000");
assertThat(adresseComplete).contains("Sénégal");
// Cas avec adresse partielle
organisation.setAdresse("123 Avenue Bourguiba");
organisation.setVille("Dakar");
organisation.setCodePostal(null);
organisation.setRegion(null);
organisation.setPays(null);
adresseComplete = organisation.getAdresseComplete();
assertThat(adresseComplete).isEqualTo("123 Avenue Bourguiba, Dakar");
// Cas avec adresse vide
organisation.setAdresse(null);
organisation.setVille(null);
organisation.setCodePostal(null);
organisation.setRegion(null);
organisation.setPays(null);
adresseComplete = organisation.getAdresseComplete();
assertThat(adresseComplete).isEmpty();
}
@Test
@DisplayName("Test getRatioAdministrateurs")
void testGetRatioAdministrateurs() {
// Cas sans membres
organisation.setNombreMembres(null);
organisation.setNombreAdministrateurs(5);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(0.0);
organisation.setNombreMembres(0);
organisation.setNombreAdministrateurs(5);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(0.0);
// Cas sans administrateurs
organisation.setNombreMembres(100);
organisation.setNombreAdministrateurs(null);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(0.0);
// Cas normal
organisation.setNombreMembres(100);
organisation.setNombreAdministrateurs(10);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(10.0);
organisation.setNombreMembres(50);
organisation.setNombreAdministrateurs(5);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(10.0);
}
@Test
@DisplayName("Test hasBudget")
void testHasBudget() {
// Cas sans budget
organisation.setBudgetAnnuel(null);
assertThat(organisation.hasBudget()).isFalse();
// Cas avec budget zéro
organisation.setBudgetAnnuel(BigDecimal.ZERO);
assertThat(organisation.hasBudget()).isFalse();
// Cas avec budget négatif
organisation.setBudgetAnnuel(new BigDecimal("-1000.00"));
assertThat(organisation.hasBudget()).isFalse();
// Cas avec budget positif
organisation.setBudgetAnnuel(new BigDecimal("5000000.00"));
assertThat(organisation.hasBudget()).isTrue();
}
@Test
@DisplayName("Test méthodes d'action")
void testMethodesAction() {
String utilisateur = "admin";
// Test activer
organisation.setStatut(StatutOrganisation.INACTIVE);
organisation.activer(utilisateur);
assertThat(organisation.getStatut()).isEqualTo(StatutOrganisation.ACTIVE);
// Test suspendre
organisation.setStatut(StatutOrganisation.ACTIVE);
organisation.suspendre(utilisateur);
assertThat(organisation.getStatut()).isEqualTo(StatutOrganisation.SUSPENDUE);
// Test dissoudre
organisation.setStatut(StatutOrganisation.ACTIVE);
organisation.setAccepteNouveauxMembres(true);
organisation.dissoudre(utilisateur);
assertThat(organisation.getStatut()).isEqualTo(StatutOrganisation.DISSOUTE);
assertThat(organisation.getAccepteNouveauxMembres()).isFalse();
}
@Test
@DisplayName("Test gestion des membres")
void testGestionMembres() {
String utilisateur = "admin";
// Test mettreAJourNombreMembres
organisation.mettreAJourNombreMembres(50, utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(50);
// Test ajouterMembre
organisation.setNombreMembres(null);
organisation.ajouterMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(1);
organisation.ajouterMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(2);
// Test retirerMembre
organisation.setNombreMembres(5);
organisation.retirerMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(4);
// Test retirerMembre avec 0 membres
organisation.setNombreMembres(0);
organisation.retirerMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(0);
// Test retirerMembre avec null
organisation.setNombreMembres(null);
organisation.retirerMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isNull();
}
@Test
@DisplayName("Test toString")
void testToString() {
organisation.setNom("Lions Club Dakar");
organisation.setNomCourt("LCD");
organisation.setTypeOrganisation(TypeOrganisation.LIONS_CLUB);
organisation.setStatut(StatutOrganisation.ACTIVE);
organisation.setVille("Dakar");
organisation.setPays("Sénégal");
organisation.setNombreMembres(50);
organisation.setDateFondation(LocalDate.of(2020, 1, 15));
String result = organisation.toString();
assertThat(result).isNotNull();
assertThat(result).contains("OrganisationDTO");
assertThat(result).contains("nom='Lions Club Dakar'");
assertThat(result).contains("nomCourt='LCD'");
assertThat(result).contains("typeOrganisation=LIONS_CLUB");
assertThat(result).contains("statut=ACTIVE");
assertThat(result).contains("ville='Dakar'");
assertThat(result).contains("pays='Sénégal'");
assertThat(result).contains("nombreMembres=50");
assertThat(result).contains("anciennete=" + organisation.getAncienneteAnnees() + " ans");
}
@Test
@DisplayName("Test branches supplémentaires getAdresseComplete")
void testBranchesSupplementairesAdresseComplete() {
// Test avec ville seulement (sans adresse)
organisation.setAdresse(null);
organisation.setVille("Dakar");
organisation.setCodePostal(null);
organisation.setRegion(null);
organisation.setPays(null);
assertThat(organisation.getAdresseComplete()).isEqualTo("Dakar");
// Test avec code postal seulement (sans adresse ni ville)
organisation.setAdresse(null);
organisation.setVille(null);
organisation.setCodePostal("12000");
organisation.setRegion(null);
organisation.setPays(null);
assertThat(organisation.getAdresseComplete()).isEqualTo("12000");
// Test avec région seulement
organisation.setAdresse(null);
organisation.setVille(null);
organisation.setCodePostal(null);
organisation.setRegion("Dakar");
organisation.setPays(null);
assertThat(organisation.getAdresseComplete()).isEqualTo("Dakar");
// Test avec pays seulement
organisation.setAdresse(null);
organisation.setVille(null);
organisation.setCodePostal(null);
organisation.setRegion(null);
organisation.setPays("Sénégal");
assertThat(organisation.getAdresseComplete()).isEqualTo("Sénégal");
// Test avec ville et code postal (sans adresse)
organisation.setAdresse(null);
organisation.setVille("Dakar");
organisation.setCodePostal("12000");
organisation.setRegion(null);
organisation.setPays(null);
assertThat(organisation.getAdresseComplete()).isEqualTo("Dakar 12000");
// Test avec ville et région (sans adresse)
organisation.setAdresse(null);
organisation.setVille("Dakar");
organisation.setCodePostal(null);
organisation.setRegion("Dakar");
organisation.setPays(null);
assertThat(organisation.getAdresseComplete()).isEqualTo("Dakar, Dakar");
// Test avec ville et pays (sans adresse)
organisation.setAdresse(null);
organisation.setVille("Dakar");
organisation.setCodePostal(null);
organisation.setRegion(null);
organisation.setPays("Sénégal");
assertThat(organisation.getAdresseComplete()).isEqualTo("Dakar, Sénégal");
}
}
}

View File

@@ -0,0 +1,96 @@
package dev.lions.unionflow.server.api.dto.organisation;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.enums.organisation.StatutOrganisation;
import dev.lions.unionflow.server.api.enums.organisation.TypeOrganisation;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires simples pour OrganisationDTO
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@DisplayName("Tests OrganisationDTO")
class OrganisationDTOSimpleTest {
private OrganisationDTO organisation;
@BeforeEach
void setUp() {
organisation = new OrganisationDTO();
}
@Test
@DisplayName("Test création et getters/setters de base")
void testCreationEtGettersSetters() {
// Données de test
String nom = "Lions Club Dakar";
String nomCourt = "LCD";
String description = "Club service de Dakar";
StatutOrganisation statut = StatutOrganisation.ACTIVE;
TypeOrganisation typeOrganisation = TypeOrganisation.LIONS_CLUB;
String adresse = "Avenue Bourguiba, Dakar";
String telephone = "+221 33 123 45 67";
String email = "contact@lionsclubdakar.sn";
// Test des setters
organisation.setNom(nom);
organisation.setNomCourt(nomCourt);
organisation.setDescription(description);
organisation.setStatut(statut);
organisation.setTypeOrganisation(typeOrganisation);
organisation.setAdresse(adresse);
organisation.setTelephone(telephone);
organisation.setEmail(email);
// Test des getters
assertThat(organisation.getNom()).isEqualTo(nom);
assertThat(organisation.getNomCourt()).isEqualTo(nomCourt);
assertThat(organisation.getDescription()).isEqualTo(description);
assertThat(organisation.getStatut()).isEqualTo(statut);
assertThat(organisation.getTypeOrganisation()).isEqualTo(typeOrganisation);
assertThat(organisation.getAdresse()).isEqualTo(adresse);
assertThat(organisation.getTelephone()).isEqualTo(telephone);
assertThat(organisation.getEmail()).isEqualTo(email);
}
@Test
@DisplayName("Test méthodes utilitaires ajoutées")
void testMethodesUtilitaires() {
organisation.setStatut(StatutOrganisation.ACTIVE);
organisation.setTypeOrganisation(TypeOrganisation.LIONS_CLUB);
// Test des méthodes getLibelle
assertThat(organisation.getStatutLibelle()).isNotNull();
assertThat(organisation.getTypeLibelle()).isNotNull();
}
@Test
@DisplayName("Test validation des énumérations")
void testValidationEnumerations() {
// Test que toutes les énumérations sont bien supportées
for (StatutOrganisation statut : StatutOrganisation.values()) {
organisation.setStatut(statut);
assertThat(organisation.getStatut()).isEqualTo(statut);
}
for (TypeOrganisation type : TypeOrganisation.values()) {
organisation.setTypeOrganisation(type);
assertThat(organisation.getTypeOrganisation()).isEqualTo(type);
}
}
@Test
@DisplayName("Test héritage BaseDTO")
void testHeritageBaseDTO() {
assertThat(organisation.getId()).isNotNull();
assertThat(organisation.getDateCreation()).isNotNull();
assertThat(organisation.isActif()).isTrue();
assertThat(organisation.getVersion()).isEqualTo(0L);
}
}

View File

@@ -0,0 +1,371 @@
package dev.lions.unionflow.server.api.dto.organisation;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.enums.organisation.StatutOrganisation;
import dev.lions.unionflow.server.api.enums.organisation.TypeOrganisation;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires pour OrganisationDTO
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@DisplayName("Tests OrganisationDTO")
class OrganisationDTOTest {
private OrganisationDTO organisation;
@BeforeEach
void setUp() {
organisation = new OrganisationDTO();
organisation.setNom("Lions Club Dakar");
organisation.setNomCourt("LCD");
organisation.setTypeOrganisation(TypeOrganisation.LIONS_CLUB);
organisation.setStatut(StatutOrganisation.ACTIVE);
organisation.setVille("Dakar");
organisation.setPays("Sénégal");
organisation.setDateCreation(LocalDateTime.now().minusYears(5));
organisation.setNombreMembres(150);
organisation.setNombreAdministrateurs(10);
organisation.setLatitude(new BigDecimal("14.6937"));
organisation.setLongitude(new BigDecimal("-17.4441"));
}
@Nested
@DisplayName("Tests de Construction")
class ConstructionTests {
@Test
@DisplayName("Test constructeur par défaut")
void testConstructeurParDefaut() {
OrganisationDTO newOrganisation = new OrganisationDTO();
assertThat(newOrganisation.getId()).isNotNull();
assertThat(newOrganisation.getDateCreation()).isNotNull();
assertThat(newOrganisation.isActif()).isTrue();
assertThat(newOrganisation.getVersion()).isEqualTo(0L);
assertThat(newOrganisation.getStatut()).isEqualTo(StatutOrganisation.ACTIVE);
assertThat(newOrganisation.getTypeOrganisation()).isEqualTo(TypeOrganisation.ASSOCIATION);
assertThat(newOrganisation.getDevise()).isEqualTo("XOF");
assertThat(newOrganisation.getNiveauHierarchique()).isEqualTo(0);
assertThat(newOrganisation.getNombreMembres()).isEqualTo(0);
assertThat(newOrganisation.getNombreAdministrateurs()).isEqualTo(0);
assertThat(newOrganisation.getOrganisationPublique()).isTrue();
assertThat(newOrganisation.getAccepteNouveauxMembres()).isTrue();
assertThat(newOrganisation.getCotisationObligatoire()).isFalse();
}
@Test
@DisplayName("Test constructeur avec paramètres")
void testConstructeurAvecParametres() {
String nom = "Association des Jeunes";
TypeOrganisation type = TypeOrganisation.ASSOCIATION;
OrganisationDTO newOrganisation = new OrganisationDTO(nom, type);
assertThat(newOrganisation.getNom()).isEqualTo(nom);
assertThat(newOrganisation.getTypeOrganisation()).isEqualTo(type);
assertThat(newOrganisation.getStatut()).isEqualTo(StatutOrganisation.ACTIVE);
}
}
@Nested
@DisplayName("Tests des Méthodes de Statut")
class MethodesStatutTests {
@Test
@DisplayName("Test estActive")
void testEstActive() {
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.estActive()).isTrue();
organisation.setStatut(StatutOrganisation.INACTIVE);
assertThat(organisation.estActive()).isFalse();
}
@Test
@DisplayName("Test estInactive")
void testEstInactive() {
organisation.setStatut(StatutOrganisation.INACTIVE);
assertThat(organisation.estInactive()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.estInactive()).isFalse();
}
@Test
@DisplayName("Test estSuspendue")
void testEstSuspendue() {
organisation.setStatut(StatutOrganisation.SUSPENDUE);
assertThat(organisation.estSuspendue()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.estSuspendue()).isFalse();
}
@Test
@DisplayName("Test estEnCreation")
void testEstEnCreation() {
organisation.setStatut(StatutOrganisation.EN_CREATION);
assertThat(organisation.estEnCreation()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.estEnCreation()).isFalse();
}
@Test
@DisplayName("Test estDissoute")
void testEstDissoute() {
organisation.setStatut(StatutOrganisation.DISSOUTE);
assertThat(organisation.estDissoute()).isTrue();
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.estDissoute()).isFalse();
}
}
@Nested
@DisplayName("Tests des Méthodes Utilitaires")
class MethodesUtilitairesTests {
@Test
@DisplayName("Test getAncienneteAnnees")
void testGetAncienneteAnnees() {
organisation.setDateFondation(LocalDate.now().minusYears(5));
assertThat(organisation.getAncienneteAnnees()).isEqualTo(5);
organisation.setDateFondation(LocalDate.now().minusMonths(6));
assertThat(organisation.getAncienneteAnnees()).isEqualTo(0);
organisation.setDateCreation(null);
assertThat(organisation.getAncienneteAnnees()).isEqualTo(0);
}
@Test
@DisplayName("Test possedGeolocalisation")
void testPossedGeolocalisation() {
organisation.setLatitude(new BigDecimal("14.6937"));
organisation.setLongitude(new BigDecimal("-17.4441"));
assertThat(organisation.possedGeolocalisation()).isTrue();
organisation.setLatitude(null);
assertThat(organisation.possedGeolocalisation()).isFalse();
organisation.setLatitude(new BigDecimal("14.6937"));
organisation.setLongitude(null);
assertThat(organisation.possedGeolocalisation()).isFalse();
}
@Test
@DisplayName("Test estOrganisationRacine")
void testEstOrganisationRacine() {
organisation.setOrganisationParenteId(null);
assertThat(organisation.estOrganisationRacine()).isTrue();
organisation.setOrganisationParenteId(UUID.randomUUID());
assertThat(organisation.estOrganisationRacine()).isFalse();
}
@Test
@DisplayName("Test possedeSousOrganisations")
void testPossedeSousOrganisations() {
organisation.setNiveauHierarchique(2);
assertThat(organisation.possedeSousOrganisations()).isTrue();
organisation.setNiveauHierarchique(0);
assertThat(organisation.possedeSousOrganisations()).isFalse();
organisation.setNiveauHierarchique(null);
assertThat(organisation.possedeSousOrganisations()).isFalse();
}
@Test
@DisplayName("Test getNomAffichage")
void testGetNomAffichage() {
organisation.setNom("Lions Club Dakar");
organisation.setNomCourt("LCD");
assertThat(organisation.getNomAffichage()).isEqualTo("LCD");
organisation.setNomCourt(null);
assertThat(organisation.getNomAffichage()).isEqualTo("Lions Club Dakar");
organisation.setNomCourt("");
assertThat(organisation.getNomAffichage()).isEqualTo("Lions Club Dakar");
}
@Test
@DisplayName("Test getStatutLibelle")
void testGetStatutLibelle() {
organisation.setStatut(StatutOrganisation.ACTIVE);
assertThat(organisation.getStatutLibelle()).isEqualTo("Active");
organisation.setStatut(null);
assertThat(organisation.getStatutLibelle()).isEqualTo("Non défini");
}
@Test
@DisplayName("Test getTypeLibelle")
void testGetTypeLibelle() {
organisation.setTypeOrganisation(TypeOrganisation.LIONS_CLUB);
assertThat(organisation.getTypeLibelle()).isEqualTo("Lions Club");
organisation.setTypeOrganisation(null);
assertThat(organisation.getTypeLibelle()).isEqualTo("Non défini");
}
@Test
@DisplayName("Test getRatioAdministrateurs")
void testGetRatioAdministrateurs() {
organisation.setNombreMembres(100);
organisation.setNombreAdministrateurs(10);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(10.0);
organisation.setNombreMembres(0);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(0.0);
organisation.setNombreMembres(null);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(0.0);
organisation.setNombreMembres(100);
organisation.setNombreAdministrateurs(null);
assertThat(organisation.getRatioAdministrateurs()).isEqualTo(0.0);
}
}
@Nested
@DisplayName("Tests des Méthodes d'Action")
class MethodesActionTests {
@Test
@DisplayName("Test activer")
void testActiver() {
String utilisateur = "admin";
organisation.activer(utilisateur);
assertThat(organisation.getStatut()).isEqualTo(StatutOrganisation.ACTIVE);
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
}
@Test
@DisplayName("Test suspendre")
void testSuspendre() {
String utilisateur = "admin";
organisation.suspendre(utilisateur);
assertThat(organisation.getStatut()).isEqualTo(StatutOrganisation.SUSPENDUE);
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
}
@Test
@DisplayName("Test dissoudre")
void testDissoudre() {
String utilisateur = "admin";
organisation.dissoudre(utilisateur);
assertThat(organisation.getStatut()).isEqualTo(StatutOrganisation.DISSOUTE);
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
}
@Test
@DisplayName("Test desactiver")
void testDesactiver() {
String utilisateur = "admin";
organisation.desactiver(utilisateur);
assertThat(organisation.getStatut()).isEqualTo(StatutOrganisation.INACTIVE);
assertThat(organisation.getAccepteNouveauxMembres()).isFalse();
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
}
@Test
@DisplayName("Test ajouterMembre")
void testAjouterMembre() {
String utilisateur = "secretaire";
organisation.setNombreMembres(100);
organisation.ajouterMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(101);
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
}
@Test
@DisplayName("Test retirerMembre")
void testRetirerMembre() {
String utilisateur = "secretaire";
organisation.setNombreMembres(100);
organisation.retirerMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(99);
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
// Test avec 0 membres
organisation.setNombreMembres(0);
organisation.retirerMembre(utilisateur);
assertThat(organisation.getNombreMembres()).isEqualTo(0);
}
@Test
@DisplayName("Test ajouterAdministrateur")
void testAjouterAdministrateur() {
String utilisateur = "president";
organisation.setNombreAdministrateurs(5);
organisation.ajouterAdministrateur(utilisateur);
assertThat(organisation.getNombreAdministrateurs()).isEqualTo(6);
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
}
@Test
@DisplayName("Test retirerAdministrateur")
void testRetirerAdministrateur() {
String utilisateur = "president";
organisation.setNombreAdministrateurs(5);
organisation.retirerAdministrateur(utilisateur);
assertThat(organisation.getNombreAdministrateurs()).isEqualTo(4);
assertThat(organisation.getModifiePar()).isEqualTo(utilisateur);
// Test avec 0 administrateurs
organisation.setNombreAdministrateurs(0);
organisation.retirerAdministrateur(utilisateur);
assertThat(organisation.getNombreAdministrateurs()).isEqualTo(0);
}
}
@Nested
@DisplayName("Tests de Validation")
class ValidationTests {
@Test
@DisplayName("Test toString")
void testToString() {
organisation.setDateFondation(LocalDate.now().minusYears(5));
String result = organisation.toString();
assertThat(result).contains("Lions Club Dakar");
assertThat(result).contains("LCD");
assertThat(result).contains("LIONS_CLUB");
assertThat(result).contains("ACTIVE");
assertThat(result).contains("Dakar");
assertThat(result).contains("Sénégal");
assertThat(result).contains("150");
assertThat(result).contains("5 ans");
}
}
}

View File

@@ -68,28 +68,33 @@ class WaveBalanceDTOBasicTest {
balanceAvecSoldeDisponibleNull.setSoldeDisponible(new BigDecimal("100000.00"));
balanceAvecSoldeDisponibleNull.setSoldeEnAttente(new BigDecimal("25000.00"));
// Vérifier que le total est calculé
assertThat(balanceAvecSoldeDisponibleNull.getSoldeTotal()).isEqualByComparingTo(new BigDecimal("125000.00"));
assertThat(balanceAvecSoldeDisponibleNull.getSoldeTotal())
.isEqualByComparingTo(new BigDecimal("125000.00"));
// Maintenant mettre soldeDisponible à null - le total ne devrait pas être recalculé
balanceAvecSoldeDisponibleNull.setSoldeDisponible(null);
assertThat(balanceAvecSoldeDisponibleNull.getSoldeTotal()).isEqualByComparingTo(new BigDecimal("125000.00")); // Garde l'ancienne valeur
assertThat(balanceAvecSoldeDisponibleNull.getSoldeTotal())
.isEqualByComparingTo(new BigDecimal("125000.00")); // Garde l'ancienne valeur
// Test avec soldeEnAttente null - même principe
WaveBalanceDTO balanceAvecSoldeEnAttenteNull = new WaveBalanceDTO();
balanceAvecSoldeEnAttenteNull.setSoldeDisponible(new BigDecimal("150000.00"));
balanceAvecSoldeEnAttenteNull.setSoldeEnAttente(new BigDecimal("30000.00"));
// Vérifier que le total est calculé
assertThat(balanceAvecSoldeEnAttenteNull.getSoldeTotal()).isEqualByComparingTo(new BigDecimal("180000.00"));
assertThat(balanceAvecSoldeEnAttenteNull.getSoldeTotal())
.isEqualByComparingTo(new BigDecimal("180000.00"));
// Maintenant mettre soldeEnAttente à null - le total ne devrait pas être recalculé
balanceAvecSoldeEnAttenteNull.setSoldeEnAttente(null);
assertThat(balanceAvecSoldeEnAttenteNull.getSoldeTotal()).isEqualByComparingTo(new BigDecimal("180000.00")); // Garde l'ancienne valeur
assertThat(balanceAvecSoldeEnAttenteNull.getSoldeTotal())
.isEqualByComparingTo(new BigDecimal("180000.00")); // Garde l'ancienne valeur
// Test avec les deux null dès le début
WaveBalanceDTO balanceAvecLesDeuxNull = new WaveBalanceDTO();
balanceAvecLesDeuxNull.setSoldeDisponible(null);
balanceAvecLesDeuxNull.setSoldeEnAttente(null);
assertThat(balanceAvecLesDeuxNull.getSoldeTotal()).isNull(); // Pas calculé car les deux sont null dès le début
assertThat(balanceAvecLesDeuxNull.getSoldeTotal())
.isNull(); // Pas calculé car les deux sont null dès le début
}
}
@@ -146,7 +151,8 @@ class WaveBalanceDTOBasicTest {
assertThat(balance.getDateDerniereSynchronisation()).isEqualTo(dateDerniereSynchronisation);
assertThat(balance.getStatutWallet()).isEqualTo(statutWallet);
assertThat(balance.getLimiteQuotidienne()).isEqualByComparingTo(limiteQuotidienne);
assertThat(balance.getMontantUtiliseAujourdhui()).isEqualByComparingTo(montantUtiliseAujourdhui);
assertThat(balance.getMontantUtiliseAujourdhui())
.isEqualByComparingTo(montantUtiliseAujourdhui);
assertThat(balance.getLimiteMensuelle()).isEqualByComparingTo(limiteMensuelle);
assertThat(balance.getMontantUtiliseCeMois()).isEqualByComparingTo(montantUtiliseCeMois);
assertThat(balance.getNombreTransactionsAujourdhui()).isEqualTo(nombreTransactionsAujourdhui);
@@ -239,7 +245,8 @@ class WaveBalanceDTOBasicTest {
// Limite restante = 100000 - 30000 = 70000
// Solde disponible aujourd'hui = min(200000, 70000) = 70000
assertThat(balance.getSoldeDisponibleAujourdhui()).isEqualByComparingTo(new BigDecimal("70000.00"));
assertThat(balance.getSoldeDisponibleAujourdhui())
.isEqualByComparingTo(new BigDecimal("70000.00"));
// Test sans limite
balance.setLimiteQuotidienne(null);
@@ -271,8 +278,10 @@ class WaveBalanceDTOBasicTest {
balance.mettreAJourApresTransaction(montantTransaction);
assertThat(balance.getMontantUtiliseAujourdhui()).isEqualByComparingTo(new BigDecimal("75000.00"));
assertThat(balance.getMontantUtiliseCeMois()).isEqualByComparingTo(new BigDecimal("525000.00"));
assertThat(balance.getMontantUtiliseAujourdhui())
.isEqualByComparingTo(new BigDecimal("75000.00"));
assertThat(balance.getMontantUtiliseCeMois())
.isEqualByComparingTo(new BigDecimal("525000.00"));
assertThat(balance.getNombreTransactionsAujourdhui()).isEqualTo(6);
assertThat(balance.getNombreTransactionsCeMois()).isEqualTo(46);
assertThat(balance.getDateDerniereMiseAJour()).isNotNull();

View File

@@ -170,7 +170,7 @@ class WaveCheckoutSessionDTOBasicTest {
@DisplayName("Test types de paiement valides")
void testTypesPaiementValides() {
String[] typesValides = {"COTISATION", "ABONNEMENT", "DON", "EVENEMENT", "FORMATION", "AUTRE"};
for (String type : typesValides) {
session.setTypePaiement(type);
assertThat(session.getTypePaiement()).isEqualTo(type);
@@ -181,7 +181,7 @@ class WaveCheckoutSessionDTOBasicTest {
@DisplayName("Test statuts de session")
void testStatutsSession() {
StatutSession[] statuts = StatutSession.values();
for (StatutSession statut : statuts) {
session.setStatut(statut);
assertThat(session.getStatut()).isEqualTo(statut);
@@ -192,7 +192,7 @@ class WaveCheckoutSessionDTOBasicTest {
@DisplayName("Test valeurs par défaut")
void testValeursParDefaut() {
WaveCheckoutSessionDTO newSession = new WaveCheckoutSessionDTO();
assertThat(newSession.getDevise()).isEqualTo("XOF");
assertThat(newSession.getStatut()).isEqualTo(StatutSession.PENDING);
assertThat(newSession.getNombreTentatives()).isEqualTo(0);
@@ -205,7 +205,7 @@ class WaveCheckoutSessionDTOBasicTest {
session.setCodeErreurWave("E001");
session.setMessageErreurWave("Paiement échoué");
session.setStatut(StatutSession.FAILED);
assertThat(session.getCodeErreurWave()).isEqualTo("E001");
assertThat(session.getMessageErreurWave()).isEqualTo("Paiement échoué");
assertThat(session.getStatut()).isEqualTo(StatutSession.FAILED);
@@ -216,11 +216,11 @@ class WaveCheckoutSessionDTOBasicTest {
void testGestionWebhook() {
LocalDateTime dateWebhook = LocalDateTime.now();
String donneesWebhook = "{\"event\":\"payment.completed\"}";
session.setWebhookRecu(true);
session.setDateWebhook(dateWebhook);
session.setDonneesWebhook(donneesWebhook);
assertThat(session.getWebhookRecu()).isTrue();
assertThat(session.getDateWebhook()).isEqualTo(dateWebhook);
assertThat(session.getDonneesWebhook()).isEqualTo(donneesWebhook);

View File

@@ -212,16 +212,17 @@ class WaveWebhookDTOBasicTest {
webhook.setTypeEvenement(null);
assertThat(webhook.getTypeEvenement()).isNull();
assertThat(webhook.getCodeEvenement()).isEqualTo("checkout.complete"); // Garde l'ancienne valeur
assertThat(webhook.getCodeEvenement())
.isEqualTo("checkout.complete"); // Garde l'ancienne valeur
}
@Test
@DisplayName("Test setCodeEvenement avec mise à jour du type")
void testSetCodeEvenementAvecMiseAJourType() {
String codeEvenement = "checkout.completed";
webhook.setCodeEvenement(codeEvenement);
assertThat(webhook.getCodeEvenement()).isEqualTo(codeEvenement);
assertThat(webhook.getTypeEvenement()).isEqualTo(TypeEvenement.fromCode(codeEvenement));
}
@@ -308,7 +309,7 @@ class WaveWebhookDTOBasicTest {
webhook.setMontantTransaction(new BigDecimal("25000.00"));
String result = webhook.toString();
assertThat(result).isNotNull();
assertThat(result).contains("WaveWebhookDTO");
assertThat(result).contains("webhook_123");

View File

@@ -0,0 +1,143 @@
package dev.lions.unionflow.server.api.dto.solidarite;
import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.enums.solidarite.PrioriteAide;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires pour DemandeAideDTO
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@DisplayName("Tests DemandeAideDTO")
class DemandeAideDTOTest {
private DemandeAideDTO demandeAide;
@BeforeEach
void setUp() {
demandeAide = new DemandeAideDTO();
}
@Test
@DisplayName("Test création et getters/setters de base")
void testCreationEtGettersSetters() {
// Données de test
String numeroReference = "DA-2025-001";
UUID membreDemandeurId = UUID.randomUUID();
String nomDemandeur = "Jean Dupont";
UUID associationId = UUID.randomUUID();
TypeAide typeAide = TypeAide.AIDE_FINANCIERE_URGENTE;
String titre = "Aide pour frais médicaux";
String description = "Demande d'aide pour couvrir les frais d'hospitalisation";
BigDecimal montantDemande = new BigDecimal("500000.00");
StatutAide statut = StatutAide.EN_ATTENTE;
PrioriteAide priorite = PrioriteAide.ELEVEE;
// Test des setters
demandeAide.setNumeroReference(numeroReference);
demandeAide.setMembreDemandeurId(membreDemandeurId);
demandeAide.setNomDemandeur(nomDemandeur);
demandeAide.setAssociationId(associationId);
demandeAide.setTypeAide(typeAide);
demandeAide.setTitre(titre);
demandeAide.setDescription(description);
demandeAide.setMontantDemande(montantDemande);
demandeAide.setStatut(statut);
demandeAide.setPriorite(priorite);
// Test des getters
assertThat(demandeAide.getNumeroReference()).isEqualTo(numeroReference);
assertThat(demandeAide.getMembreDemandeurId()).isEqualTo(membreDemandeurId);
assertThat(demandeAide.getNomDemandeur()).isEqualTo(nomDemandeur);
assertThat(demandeAide.getAssociationId()).isEqualTo(associationId);
assertThat(demandeAide.getTypeAide()).isEqualTo(typeAide);
assertThat(demandeAide.getTitre()).isEqualTo(titre);
assertThat(demandeAide.getDescription()).isEqualTo(description);
assertThat(demandeAide.getMontantDemande()).isEqualTo(montantDemande);
assertThat(demandeAide.getStatut()).isEqualTo(statut);
assertThat(demandeAide.getPriorite()).isEqualTo(priorite);
}
@Test
@DisplayName("Test méthode marquerCommeModifie")
void testMarquerCommeModifie() {
String utilisateur = "admin@unionflow.dev";
LocalDateTime avant = LocalDateTime.now();
demandeAide.marquerCommeModifie(utilisateur);
LocalDateTime apres = LocalDateTime.now();
assertThat(demandeAide.getDateModification()).isBetween(avant, apres);
}
@Test
@DisplayName("Test constructeur et setters")
void testConstructeurEtSetters() {
DemandeAideDTO demande = new DemandeAideDTO();
demande.setNumeroReference("DA-2025-002");
demande.setTitre("Test Constructeur");
demande.setTypeAide(TypeAide.DON_MATERIEL);
demande.setStatut(StatutAide.BROUILLON);
demande.setPriorite(PrioriteAide.NORMALE);
assertThat(demande.getNumeroReference()).isEqualTo("DA-2025-002");
assertThat(demande.getTitre()).isEqualTo("Test Constructeur");
assertThat(demande.getTypeAide()).isEqualTo(TypeAide.DON_MATERIEL);
assertThat(demande.getStatut()).isEqualTo(StatutAide.BROUILLON);
assertThat(demande.getPriorite()).isEqualTo(PrioriteAide.NORMALE);
}
@Test
@DisplayName("Test champs spécifiques à DemandeAideDTO")
void testChampsSpecifiques() {
// Données de test
String raisonRejet = "Dossier incomplet";
LocalDateTime dateRejet = LocalDateTime.now().minusDays(2);
UUID rejeteParId = UUID.randomUUID();
String rejetePar = "Admin System";
// Test des setters
demandeAide.setRaisonRejet(raisonRejet);
demandeAide.setDateRejet(dateRejet);
demandeAide.setRejeteParId(rejeteParId);
demandeAide.setRejetePar(rejetePar);
// Test des getters
assertThat(demandeAide.getRaisonRejet()).isEqualTo(raisonRejet);
assertThat(demandeAide.getDateRejet()).isEqualTo(dateRejet);
assertThat(demandeAide.getRejeteParId()).isEqualTo(rejeteParId);
assertThat(demandeAide.getRejetePar()).isEqualTo(rejetePar);
}
@Test
@DisplayName("Test validation des énumérations")
void testValidationEnumerations() {
// Test que toutes les énumérations sont bien supportées
for (TypeAide type : TypeAide.values()) {
demandeAide.setTypeAide(type);
assertThat(demandeAide.getTypeAide()).isEqualTo(type);
}
for (StatutAide statut : StatutAide.values()) {
demandeAide.setStatut(statut);
assertThat(demandeAide.getStatut()).isEqualTo(statut);
}
for (PrioriteAide priorite : PrioriteAide.values()) {
demandeAide.setPriorite(priorite);
assertThat(demandeAide.getPriorite()).isEqualTo(priorite);
}
}
}

View File

@@ -1,559 +0,0 @@
package dev.lions.unionflow.server.api.dto.solidarite.aide;
import static org.assertj.core.api.Assertions.assertThat;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires complets pour AideDTO.
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-10
*/
@DisplayName("Tests AideDTO")
class AideDTOBasicTest {
private AideDTO aide;
@BeforeEach
void setUp() {
aide = new AideDTO();
}
@Nested
@DisplayName("Tests de Construction")
class ConstructionTests {
@Test
@DisplayName("Constructeur par défaut - Initialisation correcte")
void testConstructeurParDefaut() {
AideDTO newAide = new AideDTO();
assertThat(newAide.getId()).isNotNull();
assertThat(newAide.getDateCreation()).isNotNull();
assertThat(newAide.isActif()).isTrue();
assertThat(newAide.getVersion()).isEqualTo(0L);
assertThat(newAide.getStatut()).isEqualTo("EN_ATTENTE");
assertThat(newAide.getDevise()).isEqualTo("XOF");
assertThat(newAide.getPriorite()).isEqualTo("NORMALE");
assertThat(newAide.getNumeroReference()).isNotNull();
assertThat(newAide.getNumeroReference()).matches("^AIDE-\\d{4}-[A-Z0-9]{6}$");
}
@Test
@DisplayName("Constructeur avec paramètres - Initialisation correcte")
void testConstructeurAvecParametres() {
UUID membreDemandeurId = UUID.randomUUID();
UUID associationId = UUID.randomUUID();
String typeAide = "FINANCIERE";
String titre = "Aide pour frais médicaux";
AideDTO newAide = new AideDTO(membreDemandeurId, associationId, typeAide, titre);
assertThat(newAide.getMembreDemandeurId()).isEqualTo(membreDemandeurId);
assertThat(newAide.getAssociationId()).isEqualTo(associationId);
assertThat(newAide.getTypeAide()).isEqualTo(typeAide);
assertThat(newAide.getTitre()).isEqualTo(titre);
assertThat(newAide.getStatut()).isEqualTo("EN_ATTENTE");
}
}
@Nested
@DisplayName("Tests Getters/Setters")
class GettersSettersTests {
@Test
@DisplayName("Test tous les getters/setters - Partie 1")
void testTousLesGettersSettersPart1() {
// Données de test
String numeroReference = "AIDE-2025-ABC123";
UUID membreDemandeurId = UUID.randomUUID();
String nomDemandeur = "Jean Dupont";
String numeroMembreDemandeur = "UF-2025-12345678";
UUID associationId = UUID.randomUUID();
String nomAssociation = "Lions Club Dakar";
String typeAide = "FINANCIERE";
String titre = "Aide pour frais médicaux";
String description = "Demande d'aide pour couvrir les frais d'hospitalisation";
BigDecimal montantDemande = new BigDecimal("500000.00");
String devise = "XOF";
String statut = "EN_COURS_EVALUATION";
String priorite = "HAUTE";
// Test des setters
aide.setNumeroReference(numeroReference);
aide.setMembreDemandeurId(membreDemandeurId);
aide.setNomDemandeur(nomDemandeur);
aide.setNumeroMembreDemandeur(numeroMembreDemandeur);
aide.setAssociationId(associationId);
aide.setNomAssociation(nomAssociation);
aide.setTypeAide(typeAide);
aide.setTitre(titre);
aide.setDescription(description);
aide.setMontantDemande(montantDemande);
aide.setDevise(devise);
aide.setStatut(statut);
aide.setPriorite(priorite);
// Test des getters
assertThat(aide.getNumeroReference()).isEqualTo(numeroReference);
assertThat(aide.getMembreDemandeurId()).isEqualTo(membreDemandeurId);
assertThat(aide.getNomDemandeur()).isEqualTo(nomDemandeur);
assertThat(aide.getNumeroMembreDemandeur()).isEqualTo(numeroMembreDemandeur);
assertThat(aide.getAssociationId()).isEqualTo(associationId);
assertThat(aide.getNomAssociation()).isEqualTo(nomAssociation);
assertThat(aide.getTypeAide()).isEqualTo(typeAide);
assertThat(aide.getTitre()).isEqualTo(titre);
assertThat(aide.getDescription()).isEqualTo(description);
assertThat(aide.getMontantDemande()).isEqualTo(montantDemande);
assertThat(aide.getDevise()).isEqualTo(devise);
assertThat(aide.getStatut()).isEqualTo(statut);
assertThat(aide.getPriorite()).isEqualTo(priorite);
}
@Test
@DisplayName("Test tous les getters/setters - Partie 2")
void testTousLesGettersSettersPart2() {
// Données de test
LocalDate dateLimite = LocalDate.now().plusMonths(3);
Boolean justificatifsFournis = true;
String documentsJoints = "certificat_medical.pdf,facture_hopital.pdf";
UUID membreEvaluateurId = UUID.randomUUID();
String nomEvaluateur = "Marie Martin";
LocalDateTime dateEvaluation = LocalDateTime.now();
String commentairesEvaluateur = "Dossier complet, situation vérifiée";
BigDecimal montantApprouve = new BigDecimal("400000.00");
LocalDateTime dateApprobation = LocalDateTime.now();
UUID membreAidantId = UUID.randomUUID();
String nomAidant = "Paul Durand";
LocalDate dateDebutAide = LocalDate.now();
LocalDate dateFinAide = LocalDate.now().plusMonths(6);
BigDecimal montantVerse = new BigDecimal("400000.00");
String modeVersement = "WAVE_MONEY";
String numeroTransaction = "TXN123456789";
LocalDateTime dateVersement = LocalDateTime.now();
// Test des setters
aide.setDateLimite(dateLimite);
aide.setJustificatifsFournis(justificatifsFournis);
aide.setDocumentsJoints(documentsJoints);
aide.setMembreEvaluateurId(membreEvaluateurId);
aide.setNomEvaluateur(nomEvaluateur);
aide.setDateEvaluation(dateEvaluation);
aide.setCommentairesEvaluateur(commentairesEvaluateur);
aide.setMontantApprouve(montantApprouve);
aide.setDateApprobation(dateApprobation);
aide.setMembreAidantId(membreAidantId);
aide.setNomAidant(nomAidant);
aide.setDateDebutAide(dateDebutAide);
aide.setDateFinAide(dateFinAide);
aide.setMontantVerse(montantVerse);
aide.setModeVersement(modeVersement);
aide.setNumeroTransaction(numeroTransaction);
aide.setDateVersement(dateVersement);
// Test des getters
assertThat(aide.getDateLimite()).isEqualTo(dateLimite);
assertThat(aide.getJustificatifsFournis()).isEqualTo(justificatifsFournis);
assertThat(aide.getDocumentsJoints()).isEqualTo(documentsJoints);
assertThat(aide.getMembreEvaluateurId()).isEqualTo(membreEvaluateurId);
assertThat(aide.getNomEvaluateur()).isEqualTo(nomEvaluateur);
assertThat(aide.getDateEvaluation()).isEqualTo(dateEvaluation);
assertThat(aide.getCommentairesEvaluateur()).isEqualTo(commentairesEvaluateur);
assertThat(aide.getMontantApprouve()).isEqualTo(montantApprouve);
assertThat(aide.getDateApprobation()).isEqualTo(dateApprobation);
assertThat(aide.getMembreAidantId()).isEqualTo(membreAidantId);
assertThat(aide.getNomAidant()).isEqualTo(nomAidant);
assertThat(aide.getDateDebutAide()).isEqualTo(dateDebutAide);
assertThat(aide.getDateFinAide()).isEqualTo(dateFinAide);
assertThat(aide.getMontantVerse()).isEqualTo(montantVerse);
assertThat(aide.getModeVersement()).isEqualTo(modeVersement);
assertThat(aide.getNumeroTransaction()).isEqualTo(numeroTransaction);
assertThat(aide.getDateVersement()).isEqualTo(dateVersement);
}
@Test
@DisplayName("Test tous les getters/setters - Partie 3")
void testTousLesGettersSettersPart3() {
// Données de test
String commentairesBeneficiaire = "Merci beaucoup pour cette aide";
Integer noteSatisfaction = 5;
Boolean aidePublique = false;
Boolean aideAnonyme = true;
Integer nombreVues = 25;
String raisonRejet = "Dossier incomplet";
LocalDateTime dateRejet = LocalDateTime.now();
UUID rejeteParId = UUID.randomUUID();
String rejetePar = "Admin System";
// Test des setters
aide.setCommentairesBeneficiaire(commentairesBeneficiaire);
aide.setNoteSatisfaction(noteSatisfaction);
aide.setAidePublique(aidePublique);
aide.setAideAnonyme(aideAnonyme);
aide.setNombreVues(nombreVues);
aide.setRaisonRejet(raisonRejet);
aide.setDateRejet(dateRejet);
aide.setRejeteParId(rejeteParId);
aide.setRejetePar(rejetePar);
// Test des getters
assertThat(aide.getCommentairesBeneficiaire()).isEqualTo(commentairesBeneficiaire);
assertThat(aide.getNoteSatisfaction()).isEqualTo(noteSatisfaction);
assertThat(aide.getAidePublique()).isEqualTo(aidePublique);
assertThat(aide.getAideAnonyme()).isEqualTo(aideAnonyme);
assertThat(aide.getNombreVues()).isEqualTo(nombreVues);
assertThat(aide.getRaisonRejet()).isEqualTo(raisonRejet);
assertThat(aide.getDateRejet()).isEqualTo(dateRejet);
assertThat(aide.getRejeteParId()).isEqualTo(rejeteParId);
assertThat(aide.getRejetePar()).isEqualTo(rejetePar);
}
}
@Nested
@DisplayName("Tests Méthodes Métier")
class MethodesMetierTests {
@Test
@DisplayName("Test méthodes de statut")
void testMethodesStatut() {
// Test isEnAttente
aide.setStatut("EN_ATTENTE");
assertThat(aide.isEnAttente()).isTrue();
aide.setStatut("APPROUVEE");
assertThat(aide.isEnAttente()).isFalse();
// Test isApprouvee
aide.setStatut("APPROUVEE");
assertThat(aide.isApprouvee()).isTrue();
aide.setStatut("REJETEE");
assertThat(aide.isApprouvee()).isFalse();
// Test isRejetee
aide.setStatut("REJETEE");
assertThat(aide.isRejetee()).isTrue();
aide.setStatut("EN_ATTENTE");
assertThat(aide.isRejetee()).isFalse();
// Test isTerminee
aide.setStatut("TERMINEE");
assertThat(aide.isTerminee()).isTrue();
aide.setStatut("EN_COURS_AIDE");
assertThat(aide.isTerminee()).isFalse();
}
@Test
@DisplayName("Test méthodes de libellé")
void testMethodesLibelle() {
// Test getTypeAideLibelle
aide.setTypeAide("FINANCIERE");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Aide Financière");
aide.setTypeAide("MEDICALE");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Aide Médicale");
aide.setTypeAide(null);
assertThat(aide.getTypeAideLibelle()).isEqualTo("Non défini");
// Test getStatutLibelle
aide.setStatut("EN_ATTENTE");
assertThat(aide.getStatutLibelle()).isEqualTo("En Attente");
aide.setStatut("APPROUVEE");
assertThat(aide.getStatutLibelle()).isEqualTo("Approuvée");
aide.setStatut(null);
assertThat(aide.getStatutLibelle()).isEqualTo("Non défini");
// Test getPrioriteLibelle
aide.setPriorite("URGENTE");
assertThat(aide.getPrioriteLibelle()).isEqualTo("Urgente");
aide.setPriorite("HAUTE");
assertThat(aide.getPrioriteLibelle()).isEqualTo("Haute");
aide.setPriorite(null);
assertThat(aide.getPrioriteLibelle()).isEqualTo("Normale");
}
@Test
@DisplayName("Test méthodes de calcul")
void testMethodesCalcul() {
// Test getPourcentageApprobation
aide.setMontantDemande(new BigDecimal("1000.00"));
aide.setMontantApprouve(new BigDecimal("800.00"));
assertThat(aide.getPourcentageApprobation()).isEqualTo(80);
// Test avec montant demandé null
aide.setMontantDemande(null);
assertThat(aide.getPourcentageApprobation()).isEqualTo(0);
// Test getEcartMontant
aide.setMontantDemande(new BigDecimal("1000.00"));
aide.setMontantApprouve(new BigDecimal("800.00"));
assertThat(aide.getEcartMontant()).isEqualTo(new BigDecimal("200.00"));
// Test avec montants null
aide.setMontantDemande(null);
aide.setMontantApprouve(null);
assertThat(aide.getEcartMontant()).isEqualTo(BigDecimal.ZERO);
}
@Test
@DisplayName("Test méthodes métier")
void testMethodesMetier() {
// Test approuver
UUID evaluateurId = UUID.randomUUID();
String nomEvaluateur = "Marie Martin";
BigDecimal montantApprouve = new BigDecimal("800.00");
String commentaires = "Dossier approuvé";
aide.approuver(evaluateurId, nomEvaluateur, montantApprouve, commentaires);
assertThat(aide.getStatut()).isEqualTo("APPROUVEE");
assertThat(aide.getMembreEvaluateurId()).isEqualTo(evaluateurId);
assertThat(aide.getNomEvaluateur()).isEqualTo(nomEvaluateur);
assertThat(aide.getMontantApprouve()).isEqualTo(montantApprouve);
assertThat(aide.getCommentairesEvaluateur()).isEqualTo(commentaires);
assertThat(aide.getDateEvaluation()).isNotNull();
assertThat(aide.getDateApprobation()).isNotNull();
// Test rejeter
aide.setStatut("EN_ATTENTE"); // Reset
UUID rejeteurId = UUID.randomUUID();
String nomRejeteur = "Paul Durand";
String raisonRejet = "Dossier incomplet";
aide.rejeter(rejeteurId, nomRejeteur, raisonRejet);
assertThat(aide.getStatut()).isEqualTo("REJETEE");
assertThat(aide.getRejeteParId()).isEqualTo(rejeteurId);
assertThat(aide.getRejetePar()).isEqualTo(nomRejeteur);
assertThat(aide.getRaisonRejet()).isEqualTo(raisonRejet);
assertThat(aide.getDateRejet()).isNotNull();
// Test demarrerAide
aide.setStatut("APPROUVEE"); // Reset
UUID aidantId = UUID.randomUUID();
String nomAidant = "Jean Dupont";
aide.demarrerAide(aidantId, nomAidant);
assertThat(aide.getStatut()).isEqualTo("EN_COURS_AIDE");
assertThat(aide.getMembreAidantId()).isEqualTo(aidantId);
assertThat(aide.getNomAidant()).isEqualTo(nomAidant);
assertThat(aide.getDateDebutAide()).isNotNull();
// Test terminerAvecVersement
BigDecimal montantVerse = new BigDecimal("800.00");
String modeVersement = "WAVE_MONEY";
String numeroTransaction = "TXN123456789";
aide.terminerAvecVersement(montantVerse, modeVersement, numeroTransaction);
assertThat(aide.getStatut()).isEqualTo("TERMINEE");
assertThat(aide.getMontantVerse()).isEqualTo(montantVerse);
assertThat(aide.getModeVersement()).isEqualTo(modeVersement);
assertThat(aide.getNumeroTransaction()).isEqualTo(numeroTransaction);
assertThat(aide.getDateVersement()).isNotNull();
assertThat(aide.getDateFinAide()).isNotNull();
// Test incrementerVues
aide.setNombreVues(null);
aide.incrementerVues();
assertThat(aide.getNombreVues()).isEqualTo(1);
aide.incrementerVues();
assertThat(aide.getNombreVues()).isEqualTo(2);
}
@Test
@DisplayName("Test méthodes métier complémentaires")
void testMethodesMetierComplementaires() {
// Test tous les statuts
aide.setStatut("EN_COURS_EVALUATION");
assertThat(aide.isEnCoursEvaluation()).isTrue();
assertThat(aide.isEnAttente()).isFalse();
aide.setStatut("EN_COURS_AIDE");
assertThat(aide.isEnCoursAide()).isTrue();
assertThat(aide.isTerminee()).isFalse();
aide.setStatut("ANNULEE");
assertThat(aide.isAnnulee()).isTrue();
// Test priorité urgente
aide.setPriorite("URGENTE");
assertThat(aide.isUrgente()).isTrue();
aide.setPriorite("NORMALE");
assertThat(aide.isUrgente()).isFalse();
// Test date limite
aide.setDateLimite(LocalDate.now().plusDays(5));
assertThat(aide.isDateLimiteDepassee()).isFalse();
assertThat(aide.getJoursRestants()).isEqualTo(5);
aide.setDateLimite(LocalDate.now().minusDays(3));
assertThat(aide.isDateLimiteDepassee()).isTrue();
assertThat(aide.getJoursRestants()).isEqualTo(0);
// Test avec date limite null
aide.setDateLimite(null);
assertThat(aide.isDateLimiteDepassee()).isFalse();
assertThat(aide.getJoursRestants()).isEqualTo(0);
// Test aide financière
aide.setTypeAide("FINANCIERE");
aide.setMontantDemande(new BigDecimal("50000.00"));
assertThat(aide.isAideFinanciere()).isTrue();
aide.setMontantDemande(null);
assertThat(aide.isAideFinanciere()).isFalse();
aide.setTypeAide("MATERIELLE");
aide.setMontantDemande(new BigDecimal("50000.00"));
assertThat(aide.isAideFinanciere()).isFalse();
// Test getEcartMontant avec différents cas
aide.setMontantDemande(new BigDecimal("100000.00"));
aide.setMontantApprouve(new BigDecimal("80000.00"));
assertThat(aide.getEcartMontant()).isEqualByComparingTo(new BigDecimal("20000.00"));
// Test avec montantDemande null
aide.setMontantDemande(null);
aide.setMontantApprouve(new BigDecimal("80000.00"));
assertThat(aide.getEcartMontant()).isEqualByComparingTo(BigDecimal.ZERO);
// Test avec montantApprouve null
aide.setMontantDemande(new BigDecimal("100000.00"));
aide.setMontantApprouve(null);
assertThat(aide.getEcartMontant()).isEqualByComparingTo(BigDecimal.ZERO);
// Test avec les deux null
aide.setMontantDemande(null);
aide.setMontantApprouve(null);
assertThat(aide.getEcartMontant()).isEqualByComparingTo(BigDecimal.ZERO);
}
@Test
@DisplayName("Test libellés complets")
void testLibellesComplets() {
// Test tous les types d'aide
aide.setTypeAide("MATERIELLE");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Aide Matérielle");
aide.setTypeAide("LOGEMENT");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Aide au Logement");
aide.setTypeAide("MEDICALE");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Aide Médicale");
aide.setTypeAide("JURIDIQUE");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Aide Juridique");
aide.setTypeAide("EDUCATION");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Aide à l'Éducation");
aide.setTypeAide("SANTE");
assertThat(aide.getTypeAideLibelle()).isEqualTo("SANTE"); // Valeur par défaut car non définie dans le switch
aide.setTypeAide("AUTRE");
assertThat(aide.getTypeAideLibelle()).isEqualTo("Autre");
aide.setTypeAide("TYPE_INCONNU");
assertThat(aide.getTypeAideLibelle()).isEqualTo("TYPE_INCONNU");
// Test tous les statuts
aide.setStatut("EN_COURS_EVALUATION");
assertThat(aide.getStatutLibelle()).isEqualTo("En Cours d'Évaluation");
aide.setStatut("REJETEE");
assertThat(aide.getStatutLibelle()).isEqualTo("Rejetée");
aide.setStatut("EN_COURS_AIDE");
assertThat(aide.getStatutLibelle()).isEqualTo("En Cours d'Aide");
aide.setStatut("TERMINEE");
assertThat(aide.getStatutLibelle()).isEqualTo("Terminée");
aide.setStatut("ANNULEE");
assertThat(aide.getStatutLibelle()).isEqualTo("Annulée");
aide.setStatut("STATUT_INCONNU");
assertThat(aide.getStatutLibelle()).isEqualTo("STATUT_INCONNU");
// Test toutes les priorités
aide.setPriorite("BASSE");
assertThat(aide.getPrioriteLibelle()).isEqualTo("Basse");
aide.setPriorite("NORMALE");
assertThat(aide.getPrioriteLibelle()).isEqualTo("Normale");
aide.setPriorite("HAUTE");
assertThat(aide.getPrioriteLibelle()).isEqualTo("Haute");
aide.setPriorite("PRIORITE_INCONNUE");
assertThat(aide.getPrioriteLibelle()).isEqualTo("PRIORITE_INCONNUE");
}
@Test
@DisplayName("Test constructeur avec paramètres")
void testConstructeurAvecParametres() {
UUID membreDemandeurId = UUID.randomUUID();
UUID associationId = UUID.randomUUID();
String typeAide = "FINANCIERE";
String titre = "Aide médicale urgente";
AideDTO nouvelleAide = new AideDTO(membreDemandeurId, associationId, typeAide, titre);
assertThat(nouvelleAide.getMembreDemandeurId()).isEqualTo(membreDemandeurId);
assertThat(nouvelleAide.getAssociationId()).isEqualTo(associationId);
assertThat(nouvelleAide.getTypeAide()).isEqualTo(typeAide);
assertThat(nouvelleAide.getTitre()).isEqualTo(titre);
assertThat(nouvelleAide.getNumeroReference()).isNotNull();
assertThat(nouvelleAide.getNumeroReference()).startsWith("AIDE-");
// Vérifier les valeurs par défaut
assertThat(nouvelleAide.getStatut()).isEqualTo("EN_ATTENTE");
assertThat(nouvelleAide.getPriorite()).isEqualTo("NORMALE");
assertThat(nouvelleAide.getDevise()).isEqualTo("XOF");
assertThat(nouvelleAide.getJustificatifsFournis()).isFalse();
assertThat(nouvelleAide.getAidePublique()).isTrue();
assertThat(nouvelleAide.getAideAnonyme()).isFalse();
assertThat(nouvelleAide.getNombreVues()).isEqualTo(0);
}
}
@Test
@DisplayName("Test toString complet")
void testToStringComplet() {
aide.setNumeroReference("AIDE-2025-ABC123");
aide.setTitre("Aide médicale");
aide.setStatut("EN_ATTENTE");
aide.setTypeAide("FINANCIERE");
aide.setMontantDemande(new BigDecimal("100000.00"));
aide.setPriorite("URGENTE");
String result = aide.toString();
assertThat(result).isNotNull();
assertThat(result).contains("AideDTO");
assertThat(result).contains("numeroReference='AIDE-2025-ABC123'");
assertThat(result).contains("typeAide='FINANCIERE'");
assertThat(result).contains("titre='Aide médicale'");
assertThat(result).contains("statut='EN_ATTENTE'");
assertThat(result).contains("montantDemande=100000.00");
assertThat(result).contains("priorite='URGENTE'");
}
}

View File

@@ -5,6 +5,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement;
import dev.lions.unionflow.server.api.enums.abonnement.StatutFormule;
import dev.lions.unionflow.server.api.enums.abonnement.TypeFormule;
import dev.lions.unionflow.server.api.enums.evenement.PrioriteEvenement;
import dev.lions.unionflow.server.api.enums.evenement.StatutEvenement;
import dev.lions.unionflow.server.api.enums.evenement.TypeEvenementMetier;
import dev.lions.unionflow.server.api.enums.finance.StatutCotisation;
import dev.lions.unionflow.server.api.enums.membre.StatutMembre;
@@ -13,6 +15,7 @@ import dev.lions.unionflow.server.api.enums.organisation.TypeOrganisation;
import dev.lions.unionflow.server.api.enums.paiement.StatutSession;
import dev.lions.unionflow.server.api.enums.paiement.StatutTraitement;
import dev.lions.unionflow.server.api.enums.paiement.TypeEvenement;
import dev.lions.unionflow.server.api.enums.solidarite.PrioriteAide;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import org.junit.jupiter.api.DisplayName;
@@ -170,6 +173,28 @@ class EnumsRefactoringTest {
assertThat(TypeEvenementMetier.CEREMONIE.getLibelle()).isEqualTo("Cérémonie");
assertThat(TypeEvenementMetier.AUTRE.getLibelle()).isEqualTo("Autre");
}
@Test
@DisplayName("StatutEvenement - Tous les statuts disponibles")
void testStatutEvenementTousLesStatuts() {
// Given & When & Then
assertThat(StatutEvenement.PLANIFIE.getLibelle()).isEqualTo("Planifié");
assertThat(StatutEvenement.CONFIRME.getLibelle()).isEqualTo("Confirmé");
assertThat(StatutEvenement.EN_COURS.getLibelle()).isEqualTo("En cours");
assertThat(StatutEvenement.TERMINE.getLibelle()).isEqualTo("Terminé");
assertThat(StatutEvenement.ANNULE.getLibelle()).isEqualTo("Annulé");
assertThat(StatutEvenement.REPORTE.getLibelle()).isEqualTo("Reporté");
}
@Test
@DisplayName("PrioriteEvenement - Toutes les priorités disponibles")
void testPrioriteEvenementToutesLesPriorites() {
// Given & When & Then
assertThat(PrioriteEvenement.CRITIQUE.getLibelle()).isEqualTo("Critique");
assertThat(PrioriteEvenement.HAUTE.getLibelle()).isEqualTo("Haute");
assertThat(PrioriteEvenement.NORMALE.getLibelle()).isEqualTo("Normale");
assertThat(PrioriteEvenement.BASSE.getLibelle()).isEqualTo("Basse");
}
}
@Nested
@@ -198,7 +223,8 @@ class EnumsRefactoringTest {
@DisplayName("TypeAide - Tous les types disponibles")
void testTypeAideTousLesTypes() {
// Given & When & Then
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getLibelle()).isEqualTo("Aide financière urgente");
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getLibelle())
.isEqualTo("Aide financière urgente");
assertThat(TypeAide.AIDE_FRAIS_MEDICAUX.getLibelle()).isEqualTo("Aide frais médicaux");
assertThat(TypeAide.AIDE_FRAIS_SCOLARITE.getLibelle()).isEqualTo("Aide frais de scolarité");
assertThat(TypeAide.HEBERGEMENT_URGENCE.getLibelle()).isEqualTo("Hébergement d'urgence");
@@ -222,6 +248,17 @@ class EnumsRefactoringTest {
assertThat(StatutAide.ANNULEE.getLibelle()).isEqualTo("Annulée");
assertThat(StatutAide.SUSPENDUE.getLibelle()).isEqualTo("Suspendue");
}
@Test
@DisplayName("PrioriteAide - Toutes les priorités disponibles")
void testPrioriteAideToutesLesPriorites() {
// Given & When & Then
assertThat(PrioriteAide.CRITIQUE.getLibelle()).isEqualTo("Critique");
assertThat(PrioriteAide.URGENTE.getLibelle()).isEqualTo("Urgente");
assertThat(PrioriteAide.ELEVEE.getLibelle()).isEqualTo("Élevée");
assertThat(PrioriteAide.NORMALE.getLibelle()).isEqualTo("Normale");
assertThat(PrioriteAide.FAIBLE.getLibelle()).isEqualTo("Faible");
}
}
@Nested

View File

@@ -0,0 +1,303 @@
package dev.lions.unionflow.server.api.enums.evenement;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires EXHAUSTIFS pour PrioriteEvenement - Couverture 100%
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@DisplayName("Tests EXHAUSTIFS PrioriteEvenement")
class PrioriteEvenementTest {
@Nested
@DisplayName("Tests des valeurs enum et constructeur")
class TestsValeursEnum {
@Test
@DisplayName("Test valueOf et values")
void testValueOfEtValues() {
PrioriteEvenement[] values = PrioriteEvenement.values();
assertThat(values).hasSize(4);
assertThat(values).containsExactly(
PrioriteEvenement.CRITIQUE,
PrioriteEvenement.HAUTE,
PrioriteEvenement.NORMALE,
PrioriteEvenement.BASSE);
// Test valueOf pour toutes les valeurs
assertThat(PrioriteEvenement.valueOf("CRITIQUE")).isEqualTo(PrioriteEvenement.CRITIQUE);
assertThat(PrioriteEvenement.valueOf("HAUTE")).isEqualTo(PrioriteEvenement.HAUTE);
assertThat(PrioriteEvenement.valueOf("NORMALE")).isEqualTo(PrioriteEvenement.NORMALE);
assertThat(PrioriteEvenement.valueOf("BASSE")).isEqualTo(PrioriteEvenement.BASSE);
assertThatThrownBy(() -> PrioriteEvenement.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@Test
@DisplayName("Test ordinal, name et toString")
void testOrdinalNameToString() {
assertThat(PrioriteEvenement.CRITIQUE.ordinal()).isEqualTo(0);
assertThat(PrioriteEvenement.HAUTE.ordinal()).isEqualTo(1);
assertThat(PrioriteEvenement.NORMALE.ordinal()).isEqualTo(2);
assertThat(PrioriteEvenement.BASSE.ordinal()).isEqualTo(3);
assertThat(PrioriteEvenement.CRITIQUE.name()).isEqualTo("CRITIQUE");
assertThat(PrioriteEvenement.HAUTE.name()).isEqualTo("HAUTE");
assertThat(PrioriteEvenement.NORMALE.name()).isEqualTo("NORMALE");
assertThat(PrioriteEvenement.BASSE.name()).isEqualTo("BASSE");
assertThat(PrioriteEvenement.CRITIQUE.toString()).isEqualTo("CRITIQUE");
assertThat(PrioriteEvenement.HAUTE.toString()).isEqualTo("HAUTE");
}
@Test
@DisplayName("Test propriétés CRITIQUE")
void testProprieteCritique() {
PrioriteEvenement priorite = PrioriteEvenement.CRITIQUE;
assertThat(priorite.getLibelle()).isEqualTo("Critique");
assertThat(priorite.getCode()).isEqualTo("critical");
assertThat(priorite.getNiveau()).isEqualTo(1);
assertThat(priorite.getDescription()).isEqualTo("Événement critique nécessitant une attention immédiate");
assertThat(priorite.getCouleur()).isEqualTo("#F44336");
assertThat(priorite.getIcone()).isEqualTo("priority_high");
assertThat(priorite.isNotificationImmediate()).isTrue();
assertThat(priorite.isEscaladeAutomatique()).isTrue();
}
@Test
@DisplayName("Test propriétés HAUTE")
void testProprieteHaute() {
PrioriteEvenement priorite = PrioriteEvenement.HAUTE;
assertThat(priorite.getLibelle()).isEqualTo("Haute");
assertThat(priorite.getCode()).isEqualTo("high");
assertThat(priorite.getNiveau()).isEqualTo(2);
assertThat(priorite.getDescription()).isEqualTo("Événement de haute priorité");
assertThat(priorite.getCouleur()).isEqualTo("#FF9800");
assertThat(priorite.getIcone()).isEqualTo("keyboard_arrow_up");
assertThat(priorite.isNotificationImmediate()).isTrue();
assertThat(priorite.isEscaladeAutomatique()).isFalse();
}
@Test
@DisplayName("Test propriétés NORMALE")
void testProprieteNormale() {
PrioriteEvenement priorite = PrioriteEvenement.NORMALE;
assertThat(priorite.getLibelle()).isEqualTo("Normale");
assertThat(priorite.getCode()).isEqualTo("normal");
assertThat(priorite.getNiveau()).isEqualTo(3);
assertThat(priorite.getDescription()).isEqualTo("Événement de priorité normale");
assertThat(priorite.getCouleur()).isEqualTo("#2196F3");
assertThat(priorite.getIcone()).isEqualTo("remove");
assertThat(priorite.isNotificationImmediate()).isFalse();
assertThat(priorite.isEscaladeAutomatique()).isFalse();
}
@Test
@DisplayName("Test propriétés BASSE")
void testProprieteBasse() {
PrioriteEvenement priorite = PrioriteEvenement.BASSE;
assertThat(priorite.getLibelle()).isEqualTo("Basse");
assertThat(priorite.getCode()).isEqualTo("low");
assertThat(priorite.getNiveau()).isEqualTo(4);
assertThat(priorite.getDescription()).isEqualTo("Événement de priorité basse");
assertThat(priorite.getCouleur()).isEqualTo("#4CAF50");
assertThat(priorite.getIcone()).isEqualTo("keyboard_arrow_down");
assertThat(priorite.isNotificationImmediate()).isFalse();
assertThat(priorite.isEscaladeAutomatique()).isFalse();
}
}
@Nested
@DisplayName("Tests des méthodes métier")
class TestsMethodesMetier {
@Test
@DisplayName("Test isElevee - toutes les branches")
void testIsElevee() {
// Priorités élevées (this == CRITIQUE || this == HAUTE)
assertThat(PrioriteEvenement.CRITIQUE.isElevee()).isTrue();
assertThat(PrioriteEvenement.HAUTE.isElevee()).isTrue();
// Priorités non élevées
assertThat(PrioriteEvenement.NORMALE.isElevee()).isFalse();
assertThat(PrioriteEvenement.BASSE.isElevee()).isFalse();
}
@Test
@DisplayName("Test isUrgente - toutes les branches")
void testIsUrgente() {
// Priorités urgentes (this == CRITIQUE || this == HAUTE)
assertThat(PrioriteEvenement.CRITIQUE.isUrgente()).isTrue();
assertThat(PrioriteEvenement.HAUTE.isUrgente()).isTrue();
// Priorités non urgentes
assertThat(PrioriteEvenement.NORMALE.isUrgente()).isFalse();
assertThat(PrioriteEvenement.BASSE.isUrgente()).isFalse();
}
@Test
@DisplayName("Test isSuperieurA - toutes les comparaisons")
void testIsSuperieurA() {
// CRITIQUE (niveau 1) est supérieur à tous les autres
assertThat(PrioriteEvenement.CRITIQUE.isSuperieurA(PrioriteEvenement.HAUTE)).isTrue();
assertThat(PrioriteEvenement.CRITIQUE.isSuperieurA(PrioriteEvenement.NORMALE)).isTrue();
assertThat(PrioriteEvenement.CRITIQUE.isSuperieurA(PrioriteEvenement.BASSE)).isTrue();
assertThat(PrioriteEvenement.CRITIQUE.isSuperieurA(PrioriteEvenement.CRITIQUE)).isFalse();
// HAUTE (niveau 2) est supérieur à NORMALE et BASSE
assertThat(PrioriteEvenement.HAUTE.isSuperieurA(PrioriteEvenement.CRITIQUE)).isFalse();
assertThat(PrioriteEvenement.HAUTE.isSuperieurA(PrioriteEvenement.NORMALE)).isTrue();
assertThat(PrioriteEvenement.HAUTE.isSuperieurA(PrioriteEvenement.BASSE)).isTrue();
assertThat(PrioriteEvenement.HAUTE.isSuperieurA(PrioriteEvenement.HAUTE)).isFalse();
// NORMALE (niveau 3) est supérieur à BASSE seulement
assertThat(PrioriteEvenement.NORMALE.isSuperieurA(PrioriteEvenement.CRITIQUE)).isFalse();
assertThat(PrioriteEvenement.NORMALE.isSuperieurA(PrioriteEvenement.HAUTE)).isFalse();
assertThat(PrioriteEvenement.NORMALE.isSuperieurA(PrioriteEvenement.BASSE)).isTrue();
assertThat(PrioriteEvenement.NORMALE.isSuperieurA(PrioriteEvenement.NORMALE)).isFalse();
// BASSE (niveau 4) n'est supérieur à aucun
assertThat(PrioriteEvenement.BASSE.isSuperieurA(PrioriteEvenement.CRITIQUE)).isFalse();
assertThat(PrioriteEvenement.BASSE.isSuperieurA(PrioriteEvenement.HAUTE)).isFalse();
assertThat(PrioriteEvenement.BASSE.isSuperieurA(PrioriteEvenement.NORMALE)).isFalse();
assertThat(PrioriteEvenement.BASSE.isSuperieurA(PrioriteEvenement.BASSE)).isFalse();
}
}
@Nested
@DisplayName("Tests des méthodes statiques")
class TestsMethodesStatiques {
@Test
@DisplayName("Test getPrioritesElevees")
void testGetPrioritesElevees() {
List<PrioriteEvenement> elevees = PrioriteEvenement.getPrioritesElevees();
// Vérifier que toutes les priorités élevées sont incluses
assertThat(elevees).contains(
PrioriteEvenement.CRITIQUE,
PrioriteEvenement.HAUTE);
// Vérifier qu'aucune priorité non élevée n'est incluse
assertThat(elevees).doesNotContain(
PrioriteEvenement.NORMALE,
PrioriteEvenement.BASSE);
// Vérifier que toutes les priorités retournées sont bien élevées
elevees.forEach(priorite -> assertThat(priorite.isElevee()).isTrue());
}
@Test
@DisplayName("Test getPrioritesUrgentes")
void testGetPrioritesUrgentes() {
List<PrioriteEvenement> urgentes = PrioriteEvenement.getPrioritesUrgentes();
// Vérifier que toutes les priorités urgentes sont incluses
assertThat(urgentes).contains(
PrioriteEvenement.CRITIQUE,
PrioriteEvenement.HAUTE);
// Vérifier qu'aucune priorité non urgente n'est incluse
assertThat(urgentes).doesNotContain(
PrioriteEvenement.NORMALE,
PrioriteEvenement.BASSE);
// Vérifier que toutes les priorités retournées sont bien urgentes
urgentes.forEach(priorite -> assertThat(priorite.isUrgente()).isTrue());
}
@Test
@DisplayName("Test determinerPriorite - toutes les branches du switch")
void testDeterminerPriorite() {
// ASSEMBLEE_GENERALE -> HAUTE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.ASSEMBLEE_GENERALE))
.isEqualTo(PrioriteEvenement.HAUTE);
// REUNION_BUREAU -> HAUTE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.REUNION_BUREAU))
.isEqualTo(PrioriteEvenement.HAUTE);
// ACTION_CARITATIVE -> NORMALE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.ACTION_CARITATIVE))
.isEqualTo(PrioriteEvenement.NORMALE);
// FORMATION -> NORMALE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.FORMATION))
.isEqualTo(PrioriteEvenement.NORMALE);
// CONFERENCE -> NORMALE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.CONFERENCE))
.isEqualTo(PrioriteEvenement.NORMALE);
// ACTIVITE_SOCIALE -> BASSE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.ACTIVITE_SOCIALE))
.isEqualTo(PrioriteEvenement.BASSE);
// ATELIER -> BASSE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.ATELIER))
.isEqualTo(PrioriteEvenement.BASSE);
// CEREMONIE -> NORMALE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.CEREMONIE))
.isEqualTo(PrioriteEvenement.NORMALE);
// AUTRE -> NORMALE
assertThat(PrioriteEvenement.determinerPriorite(TypeEvenementMetier.AUTRE))
.isEqualTo(PrioriteEvenement.NORMALE);
}
@Test
@DisplayName("Test getDefaut")
void testGetDefaut() {
assertThat(PrioriteEvenement.getDefaut()).isEqualTo(PrioriteEvenement.NORMALE);
}
}
@Test
@DisplayName("Test cohérence globale des données")
void testCoherenceGlobale() {
for (PrioriteEvenement priorite : PrioriteEvenement.values()) {
// Tous les champs obligatoires non null
assertThat(priorite.getLibelle()).isNotNull().isNotEmpty();
assertThat(priorite.getCode()).isNotNull().isNotEmpty();
assertThat(priorite.getDescription()).isNotNull().isNotEmpty();
assertThat(priorite.getCouleur()).isNotNull().matches("#[0-9A-Fa-f]{6}");
assertThat(priorite.getIcone()).isNotNull().isNotEmpty();
assertThat(priorite.getNiveau()).isPositive();
// Cohérence logique
if (priorite.isElevee()) {
// Les priorités élevées sont aussi urgentes
assertThat(priorite.isUrgente()).isTrue();
// Les priorités élevées ont notification immédiate
assertThat(priorite.isNotificationImmediate()).isTrue();
}
if (priorite.isEscaladeAutomatique()) {
// Seule CRITIQUE a escalade automatique
assertThat(priorite).isEqualTo(PrioriteEvenement.CRITIQUE);
}
// Niveaux cohérents (plus bas = plus prioritaire)
if (priorite == PrioriteEvenement.CRITIQUE) {
assertThat(priorite.getNiveau()).isEqualTo(1);
}
if (priorite == PrioriteEvenement.BASSE) {
assertThat(priorite.getNiveau()).isEqualTo(4);
}
// Comparaisons cohérentes
assertThat(priorite.isSuperieurA(priorite)).isFalse(); // Pas supérieur à soi-même
}
}
}

View File

@@ -0,0 +1,468 @@
package dev.lions.unionflow.server.api.enums.evenement;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires EXHAUSTIFS pour StatutEvenement - Couverture 100%
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@DisplayName("Tests EXHAUSTIFS StatutEvenement")
class StatutEvenementTest {
@Nested
@DisplayName("Tests des valeurs enum et constructeur")
class TestsValeursEnum {
@Test
@DisplayName("Test valueOf et values")
void testValueOfEtValues() {
StatutEvenement[] values = StatutEvenement.values();
assertThat(values).hasSize(6);
assertThat(values).containsExactly(
StatutEvenement.PLANIFIE,
StatutEvenement.CONFIRME,
StatutEvenement.EN_COURS,
StatutEvenement.TERMINE,
StatutEvenement.ANNULE,
StatutEvenement.REPORTE);
// Test valueOf pour toutes les valeurs
assertThat(StatutEvenement.valueOf("PLANIFIE")).isEqualTo(StatutEvenement.PLANIFIE);
assertThat(StatutEvenement.valueOf("CONFIRME")).isEqualTo(StatutEvenement.CONFIRME);
assertThat(StatutEvenement.valueOf("EN_COURS")).isEqualTo(StatutEvenement.EN_COURS);
assertThat(StatutEvenement.valueOf("TERMINE")).isEqualTo(StatutEvenement.TERMINE);
assertThat(StatutEvenement.valueOf("ANNULE")).isEqualTo(StatutEvenement.ANNULE);
assertThat(StatutEvenement.valueOf("REPORTE")).isEqualTo(StatutEvenement.REPORTE);
assertThatThrownBy(() -> StatutEvenement.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@Test
@DisplayName("Test ordinal, name et toString")
void testOrdinalNameToString() {
assertThat(StatutEvenement.PLANIFIE.ordinal()).isEqualTo(0);
assertThat(StatutEvenement.CONFIRME.ordinal()).isEqualTo(1);
assertThat(StatutEvenement.EN_COURS.ordinal()).isEqualTo(2);
assertThat(StatutEvenement.TERMINE.ordinal()).isEqualTo(3);
assertThat(StatutEvenement.ANNULE.ordinal()).isEqualTo(4);
assertThat(StatutEvenement.REPORTE.ordinal()).isEqualTo(5);
assertThat(StatutEvenement.PLANIFIE.name()).isEqualTo("PLANIFIE");
assertThat(StatutEvenement.EN_COURS.name()).isEqualTo("EN_COURS");
assertThat(StatutEvenement.PLANIFIE.toString()).isEqualTo("PLANIFIE");
assertThat(StatutEvenement.TERMINE.toString()).isEqualTo("TERMINE");
}
@Test
@DisplayName("Test propriétés PLANIFIE")
void testProprietePlanifie() {
StatutEvenement statut = StatutEvenement.PLANIFIE;
assertThat(statut.getLibelle()).isEqualTo("Planifié");
assertThat(statut.getCode()).isEqualTo("planned");
assertThat(statut.getDescription()).isEqualTo("L'événement est planifié et en préparation");
assertThat(statut.getCouleur()).isEqualTo("#2196F3");
assertThat(statut.getIcone()).isEqualTo("event");
assertThat(statut.isEstFinal()).isFalse();
assertThat(statut.isEstEchec()).isFalse();
}
@Test
@DisplayName("Test propriétés CONFIRME")
void testProprieteConfirme() {
StatutEvenement statut = StatutEvenement.CONFIRME;
assertThat(statut.getLibelle()).isEqualTo("Confirmé");
assertThat(statut.getCode()).isEqualTo("confirmed");
assertThat(statut.getDescription()).isEqualTo("L'événement est confirmé et les inscriptions sont ouvertes");
assertThat(statut.getCouleur()).isEqualTo("#4CAF50");
assertThat(statut.getIcone()).isEqualTo("event_available");
assertThat(statut.isEstFinal()).isFalse();
assertThat(statut.isEstEchec()).isFalse();
}
@Test
@DisplayName("Test propriétés EN_COURS")
void testProprieteEnCours() {
StatutEvenement statut = StatutEvenement.EN_COURS;
assertThat(statut.getLibelle()).isEqualTo("En cours");
assertThat(statut.getCode()).isEqualTo("ongoing");
assertThat(statut.getDescription()).isEqualTo("L'événement est actuellement en cours");
assertThat(statut.getCouleur()).isEqualTo("#FF9800");
assertThat(statut.getIcone()).isEqualTo("play_circle");
assertThat(statut.isEstFinal()).isFalse();
assertThat(statut.isEstEchec()).isFalse();
}
@Test
@DisplayName("Test propriétés TERMINE")
void testProprieteTermine() {
StatutEvenement statut = StatutEvenement.TERMINE;
assertThat(statut.getLibelle()).isEqualTo("Terminé");
assertThat(statut.getCode()).isEqualTo("completed");
assertThat(statut.getDescription()).isEqualTo("L'événement s'est terminé avec succès");
assertThat(statut.getCouleur()).isEqualTo("#4CAF50");
assertThat(statut.getIcone()).isEqualTo("check_circle");
assertThat(statut.isEstFinal()).isTrue();
assertThat(statut.isEstEchec()).isFalse();
}
@Test
@DisplayName("Test propriétés ANNULE")
void testProprieteAnnule() {
StatutEvenement statut = StatutEvenement.ANNULE;
assertThat(statut.getLibelle()).isEqualTo("Annulé");
assertThat(statut.getCode()).isEqualTo("cancelled");
assertThat(statut.getDescription()).isEqualTo("L'événement a été annulé");
assertThat(statut.getCouleur()).isEqualTo("#F44336");
assertThat(statut.getIcone()).isEqualTo("cancel");
assertThat(statut.isEstFinal()).isTrue();
assertThat(statut.isEstEchec()).isTrue();
}
@Test
@DisplayName("Test propriétés REPORTE")
void testProprieteReporte() {
StatutEvenement statut = StatutEvenement.REPORTE;
assertThat(statut.getLibelle()).isEqualTo("Reporté");
assertThat(statut.getCode()).isEqualTo("postponed");
assertThat(statut.getDescription()).isEqualTo("L'événement a été reporté à une date ultérieure");
assertThat(statut.getCouleur()).isEqualTo("#FF5722");
assertThat(statut.getIcone()).isEqualTo("schedule");
assertThat(statut.isEstFinal()).isFalse();
assertThat(statut.isEstEchec()).isFalse();
}
}
@Nested
@DisplayName("Tests des méthodes métier")
class TestsMethodesMetier {
@Test
@DisplayName("Test permetModification - toutes les branches du switch")
void testPermetModification() {
// PLANIFIE, CONFIRME, REPORTE -> true
assertThat(StatutEvenement.PLANIFIE.permetModification()).isTrue();
assertThat(StatutEvenement.CONFIRME.permetModification()).isTrue();
assertThat(StatutEvenement.REPORTE.permetModification()).isTrue();
// EN_COURS, TERMINE, ANNULE -> false
assertThat(StatutEvenement.EN_COURS.permetModification()).isFalse();
assertThat(StatutEvenement.TERMINE.permetModification()).isFalse();
assertThat(StatutEvenement.ANNULE.permetModification()).isFalse();
}
@Test
@DisplayName("Test permetAnnulation - toutes les branches du switch")
void testPermetAnnulation() {
// PLANIFIE, CONFIRME, EN_COURS, REPORTE -> true
assertThat(StatutEvenement.PLANIFIE.permetAnnulation()).isTrue();
assertThat(StatutEvenement.CONFIRME.permetAnnulation()).isTrue();
assertThat(StatutEvenement.EN_COURS.permetAnnulation()).isTrue();
assertThat(StatutEvenement.REPORTE.permetAnnulation()).isTrue();
// TERMINE, ANNULE -> false
assertThat(StatutEvenement.TERMINE.permetAnnulation()).isFalse();
assertThat(StatutEvenement.ANNULE.permetAnnulation()).isFalse();
}
@Test
@DisplayName("Test isEnCours - toutes les branches")
void testIsEnCours() {
// Seul EN_COURS retourne true
assertThat(StatutEvenement.EN_COURS.isEnCours()).isTrue();
// Tous les autres retournent false
assertThat(StatutEvenement.PLANIFIE.isEnCours()).isFalse();
assertThat(StatutEvenement.CONFIRME.isEnCours()).isFalse();
assertThat(StatutEvenement.TERMINE.isEnCours()).isFalse();
assertThat(StatutEvenement.ANNULE.isEnCours()).isFalse();
assertThat(StatutEvenement.REPORTE.isEnCours()).isFalse();
}
@Test
@DisplayName("Test isSucces - toutes les branches")
void testIsSucces() {
// Seul TERMINE retourne true
assertThat(StatutEvenement.TERMINE.isSucces()).isTrue();
// Tous les autres retournent false
assertThat(StatutEvenement.PLANIFIE.isSucces()).isFalse();
assertThat(StatutEvenement.CONFIRME.isSucces()).isFalse();
assertThat(StatutEvenement.EN_COURS.isSucces()).isFalse();
assertThat(StatutEvenement.ANNULE.isSucces()).isFalse();
assertThat(StatutEvenement.REPORTE.isSucces()).isFalse();
}
@Test
@DisplayName("Test getNiveauPriorite - toutes les branches du switch")
void testGetNiveauPriorite() {
// EN_COURS -> 1
assertThat(StatutEvenement.EN_COURS.getNiveauPriorite()).isEqualTo(1);
// CONFIRME -> 2
assertThat(StatutEvenement.CONFIRME.getNiveauPriorite()).isEqualTo(2);
// PLANIFIE -> 3
assertThat(StatutEvenement.PLANIFIE.getNiveauPriorite()).isEqualTo(3);
// REPORTE -> 4
assertThat(StatutEvenement.REPORTE.getNiveauPriorite()).isEqualTo(4);
// TERMINE -> 5
assertThat(StatutEvenement.TERMINE.getNiveauPriorite()).isEqualTo(5);
// ANNULE -> 6
assertThat(StatutEvenement.ANNULE.getNiveauPriorite()).isEqualTo(6);
}
}
@Nested
@DisplayName("Tests des méthodes statiques")
class TestsMethodesStatiques {
@Test
@DisplayName("Test getStatutsFinaux")
void testGetStatutsFinaux() {
List<StatutEvenement> finaux = StatutEvenement.getStatutsFinaux();
// Vérifier que tous les statuts finaux sont inclus
assertThat(finaux).contains(
StatutEvenement.TERMINE,
StatutEvenement.ANNULE);
// Vérifier qu'aucun statut non final n'est inclus
assertThat(finaux).doesNotContain(
StatutEvenement.PLANIFIE,
StatutEvenement.CONFIRME,
StatutEvenement.EN_COURS,
StatutEvenement.REPORTE);
// Vérifier que tous les statuts retournés sont bien finaux
finaux.forEach(statut -> assertThat(statut.isEstFinal()).isTrue());
}
@Test
@DisplayName("Test getStatutsEchec")
void testGetStatutsEchec() {
List<StatutEvenement> echecs = StatutEvenement.getStatutsEchec();
// Vérifier que tous les statuts d'échec sont inclus
assertThat(echecs).contains(StatutEvenement.ANNULE);
// Vérifier qu'aucun statut non échec n'est inclus
assertThat(echecs).doesNotContain(
StatutEvenement.PLANIFIE,
StatutEvenement.CONFIRME,
StatutEvenement.EN_COURS,
StatutEvenement.TERMINE,
StatutEvenement.REPORTE);
// Vérifier que tous les statuts retournés sont bien des échecs
echecs.forEach(statut -> assertThat(statut.isEstEchec()).isTrue());
}
@Test
@DisplayName("Test getStatutsActifs")
void testGetStatutsActifs() {
StatutEvenement[] actifs = StatutEvenement.getStatutsActifs();
// Vérifier le contenu exact
assertThat(actifs).containsExactly(
StatutEvenement.PLANIFIE,
StatutEvenement.CONFIRME,
StatutEvenement.EN_COURS,
StatutEvenement.REPORTE);
// Vérifier qu'aucun statut final n'est inclus
assertThat(actifs).doesNotContain(
StatutEvenement.TERMINE,
StatutEvenement.ANNULE);
}
@Test
@DisplayName("Test fromCode - toutes les branches")
void testFromCode() {
// Codes valides
assertThat(StatutEvenement.fromCode("planned")).isEqualTo(StatutEvenement.PLANIFIE);
assertThat(StatutEvenement.fromCode("confirmed")).isEqualTo(StatutEvenement.CONFIRME);
assertThat(StatutEvenement.fromCode("ongoing")).isEqualTo(StatutEvenement.EN_COURS);
assertThat(StatutEvenement.fromCode("completed")).isEqualTo(StatutEvenement.TERMINE);
assertThat(StatutEvenement.fromCode("cancelled")).isEqualTo(StatutEvenement.ANNULE);
assertThat(StatutEvenement.fromCode("postponed")).isEqualTo(StatutEvenement.REPORTE);
// Code inexistant
assertThat(StatutEvenement.fromCode("inexistant")).isNull();
// Cas limites
assertThat(StatutEvenement.fromCode(null)).isNull();
assertThat(StatutEvenement.fromCode("")).isNull();
assertThat(StatutEvenement.fromCode(" ")).isNull();
}
@Test
@DisplayName("Test fromLibelle - toutes les branches")
void testFromLibelle() {
// Libellés valides
assertThat(StatutEvenement.fromLibelle("Planifié")).isEqualTo(StatutEvenement.PLANIFIE);
assertThat(StatutEvenement.fromLibelle("Confirmé")).isEqualTo(StatutEvenement.CONFIRME);
assertThat(StatutEvenement.fromLibelle("En cours")).isEqualTo(StatutEvenement.EN_COURS);
assertThat(StatutEvenement.fromLibelle("Terminé")).isEqualTo(StatutEvenement.TERMINE);
assertThat(StatutEvenement.fromLibelle("Annulé")).isEqualTo(StatutEvenement.ANNULE);
assertThat(StatutEvenement.fromLibelle("Reporté")).isEqualTo(StatutEvenement.REPORTE);
// Libellé inexistant
assertThat(StatutEvenement.fromLibelle("Inexistant")).isNull();
// Cas limites
assertThat(StatutEvenement.fromLibelle(null)).isNull();
assertThat(StatutEvenement.fromLibelle("")).isNull();
assertThat(StatutEvenement.fromLibelle(" ")).isNull();
}
}
@Nested
@DisplayName("Tests des méthodes complexes")
class TestsMethodesComplexes {
@Test
@DisplayName("Test peutTransitionnerVers - toutes les branches")
void testPeutTransitionnerVers() {
// Règles générales
// this == nouveauStatut -> false
assertThat(StatutEvenement.PLANIFIE.peutTransitionnerVers(StatutEvenement.PLANIFIE)).isFalse();
assertThat(StatutEvenement.CONFIRME.peutTransitionnerVers(StatutEvenement.CONFIRME)).isFalse();
// estFinal && nouveauStatut != REPORTE -> false
assertThat(StatutEvenement.TERMINE.peutTransitionnerVers(StatutEvenement.PLANIFIE)).isFalse();
assertThat(StatutEvenement.ANNULE.peutTransitionnerVers(StatutEvenement.CONFIRME)).isFalse();
// estFinal && nouveauStatut == REPORTE -> mais default false dans switch
// TERMINE et ANNULE ne sont pas dans le switch, donc default -> false
assertThat(StatutEvenement.TERMINE.peutTransitionnerVers(StatutEvenement.REPORTE)).isFalse();
assertThat(StatutEvenement.ANNULE.peutTransitionnerVers(StatutEvenement.REPORTE)).isFalse();
// PLANIFIE -> CONFIRME || ANNULE || REPORTE
assertThat(StatutEvenement.PLANIFIE.peutTransitionnerVers(StatutEvenement.CONFIRME)).isTrue();
assertThat(StatutEvenement.PLANIFIE.peutTransitionnerVers(StatutEvenement.ANNULE)).isTrue();
assertThat(StatutEvenement.PLANIFIE.peutTransitionnerVers(StatutEvenement.REPORTE)).isTrue();
assertThat(StatutEvenement.PLANIFIE.peutTransitionnerVers(StatutEvenement.EN_COURS)).isFalse();
assertThat(StatutEvenement.PLANIFIE.peutTransitionnerVers(StatutEvenement.TERMINE)).isFalse();
// CONFIRME -> EN_COURS || ANNULE || REPORTE
assertThat(StatutEvenement.CONFIRME.peutTransitionnerVers(StatutEvenement.EN_COURS)).isTrue();
assertThat(StatutEvenement.CONFIRME.peutTransitionnerVers(StatutEvenement.ANNULE)).isTrue();
assertThat(StatutEvenement.CONFIRME.peutTransitionnerVers(StatutEvenement.REPORTE)).isTrue();
assertThat(StatutEvenement.CONFIRME.peutTransitionnerVers(StatutEvenement.PLANIFIE)).isFalse();
assertThat(StatutEvenement.CONFIRME.peutTransitionnerVers(StatutEvenement.TERMINE)).isFalse();
// EN_COURS -> TERMINE || ANNULE
assertThat(StatutEvenement.EN_COURS.peutTransitionnerVers(StatutEvenement.TERMINE)).isTrue();
assertThat(StatutEvenement.EN_COURS.peutTransitionnerVers(StatutEvenement.ANNULE)).isTrue();
assertThat(StatutEvenement.EN_COURS.peutTransitionnerVers(StatutEvenement.PLANIFIE)).isFalse();
assertThat(StatutEvenement.EN_COURS.peutTransitionnerVers(StatutEvenement.CONFIRME)).isFalse();
assertThat(StatutEvenement.EN_COURS.peutTransitionnerVers(StatutEvenement.REPORTE)).isFalse();
// REPORTE -> PLANIFIE || ANNULE (pas CONFIRME selon le code)
assertThat(StatutEvenement.REPORTE.peutTransitionnerVers(StatutEvenement.PLANIFIE)).isTrue();
assertThat(StatutEvenement.REPORTE.peutTransitionnerVers(StatutEvenement.ANNULE)).isTrue();
assertThat(StatutEvenement.REPORTE.peutTransitionnerVers(StatutEvenement.CONFIRME)).isFalse();
assertThat(StatutEvenement.REPORTE.peutTransitionnerVers(StatutEvenement.EN_COURS)).isFalse();
assertThat(StatutEvenement.REPORTE.peutTransitionnerVers(StatutEvenement.TERMINE)).isFalse();
// default -> false (pour les statuts non couverts par le switch)
// Déjà testé avec les statuts finaux ci-dessus
}
@Test
@DisplayName("Test getTransitionsPossibles - toutes les branches du switch")
void testGetTransitionsPossibles() {
// PLANIFIE -> [CONFIRME, ANNULE, REPORTE]
StatutEvenement[] transitionsPlanifie = StatutEvenement.PLANIFIE.getTransitionsPossibles();
assertThat(transitionsPlanifie).containsExactly(
StatutEvenement.CONFIRME,
StatutEvenement.ANNULE,
StatutEvenement.REPORTE);
// CONFIRME -> [EN_COURS, ANNULE, REPORTE]
StatutEvenement[] transitionsConfirme = StatutEvenement.CONFIRME.getTransitionsPossibles();
assertThat(transitionsConfirme).containsExactly(
StatutEvenement.EN_COURS,
StatutEvenement.ANNULE,
StatutEvenement.REPORTE);
// EN_COURS -> [TERMINE, ANNULE]
StatutEvenement[] transitionsEnCours = StatutEvenement.EN_COURS.getTransitionsPossibles();
assertThat(transitionsEnCours).containsExactly(
StatutEvenement.TERMINE,
StatutEvenement.ANNULE);
// REPORTE -> [PLANIFIE, CONFIRME, ANNULE] (selon getTransitionsPossibles)
StatutEvenement[] transitionsReporte = StatutEvenement.REPORTE.getTransitionsPossibles();
assertThat(transitionsReporte).containsExactly(
StatutEvenement.PLANIFIE,
StatutEvenement.CONFIRME,
StatutEvenement.ANNULE);
// TERMINE, ANNULE -> [] (aucune transition)
StatutEvenement[] transitionsTermine = StatutEvenement.TERMINE.getTransitionsPossibles();
assertThat(transitionsTermine).isEmpty();
StatutEvenement[] transitionsAnnule = StatutEvenement.ANNULE.getTransitionsPossibles();
assertThat(transitionsAnnule).isEmpty();
}
}
@Test
@DisplayName("Test cohérence globale des données")
void testCoherenceGlobale() {
for (StatutEvenement statut : StatutEvenement.values()) {
// Tous les champs obligatoires non null
assertThat(statut.getLibelle()).isNotNull().isNotEmpty();
assertThat(statut.getCode()).isNotNull().isNotEmpty();
assertThat(statut.getDescription()).isNotNull().isNotEmpty();
assertThat(statut.getCouleur()).isNotNull().matches("#[0-9A-Fa-f]{6}");
assertThat(statut.getIcone()).isNotNull().isNotEmpty();
// Cohérence logique
if (statut.isEstFinal()) {
// Les statuts finaux ne permettent pas la modification
assertThat(statut.permetModification()).isFalse();
}
if (statut.isEstEchec()) {
// Les statuts d'échec ne sont pas des succès
assertThat(statut.isSucces()).isFalse();
// Les statuts d'échec sont finaux
assertThat(statut.isEstFinal()).isTrue();
}
if (statut.isSucces()) {
// Les statuts de succès ne sont pas des échecs
assertThat(statut.isEstEchec()).isFalse();
// Les statuts de succès sont finaux
assertThat(statut.isEstFinal()).isTrue();
}
// Niveau de priorité cohérent
int niveau = statut.getNiveauPriorite();
assertThat(niveau).isBetween(1, 6);
// Transitions cohérentes
assertThat(statut.peutTransitionnerVers(statut)).isFalse(); // Pas de transition vers soi-même
// Méthodes de recherche cohérentes
assertThat(StatutEvenement.fromCode(statut.getCode())).isEqualTo(statut);
assertThat(StatutEvenement.fromLibelle(statut.getLibelle())).isEqualTo(statut);
}
}
}

View File

@@ -0,0 +1,437 @@
package dev.lions.unionflow.server.api.enums.solidarite;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.within;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires EXHAUSTIFS pour PrioriteAide - Couverture 100%
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@DisplayName("Tests EXHAUSTIFS PrioriteAide")
class PrioriteAideTest {
@Nested
@DisplayName("Tests des valeurs enum et constructeur")
class TestsValeursEnum {
@Test
@DisplayName("Test toutes les valeurs enum avec propriétés exactes")
void testToutesValeursExactes() {
// CRITIQUE
assertThat(PrioriteAide.CRITIQUE.getLibelle()).isEqualTo("Critique");
assertThat(PrioriteAide.CRITIQUE.getCode()).isEqualTo("critical");
assertThat(PrioriteAide.CRITIQUE.getNiveau()).isEqualTo(1);
assertThat(PrioriteAide.CRITIQUE.getDescription()).isEqualTo("Situation critique nécessitant une intervention immédiate");
assertThat(PrioriteAide.CRITIQUE.getCouleur()).isEqualTo("#F44336");
assertThat(PrioriteAide.CRITIQUE.getIcone()).isEqualTo("emergency");
assertThat(PrioriteAide.CRITIQUE.getDelaiTraitementHeures()).isEqualTo(24);
assertThat(PrioriteAide.CRITIQUE.isNotificationImmediate()).isTrue();
assertThat(PrioriteAide.CRITIQUE.isEscaladeAutomatique()).isTrue();
// URGENTE
assertThat(PrioriteAide.URGENTE.getLibelle()).isEqualTo("Urgente");
assertThat(PrioriteAide.URGENTE.getCode()).isEqualTo("urgent");
assertThat(PrioriteAide.URGENTE.getNiveau()).isEqualTo(2);
assertThat(PrioriteAide.URGENTE.getDescription()).isEqualTo("Situation urgente nécessitant une réponse rapide");
assertThat(PrioriteAide.URGENTE.getCouleur()).isEqualTo("#FF5722");
assertThat(PrioriteAide.URGENTE.getIcone()).isEqualTo("priority_high");
assertThat(PrioriteAide.URGENTE.getDelaiTraitementHeures()).isEqualTo(72);
assertThat(PrioriteAide.URGENTE.isNotificationImmediate()).isTrue();
assertThat(PrioriteAide.URGENTE.isEscaladeAutomatique()).isFalse();
// ELEVEE
assertThat(PrioriteAide.ELEVEE.getLibelle()).isEqualTo("Élevée");
assertThat(PrioriteAide.ELEVEE.getCode()).isEqualTo("high");
assertThat(PrioriteAide.ELEVEE.getNiveau()).isEqualTo(3);
assertThat(PrioriteAide.ELEVEE.getDescription()).isEqualTo("Priorité élevée, traitement dans les meilleurs délais");
assertThat(PrioriteAide.ELEVEE.getCouleur()).isEqualTo("#FF9800");
assertThat(PrioriteAide.ELEVEE.getIcone()).isEqualTo("keyboard_arrow_up");
assertThat(PrioriteAide.ELEVEE.getDelaiTraitementHeures()).isEqualTo(168);
assertThat(PrioriteAide.ELEVEE.isNotificationImmediate()).isFalse();
assertThat(PrioriteAide.ELEVEE.isEscaladeAutomatique()).isFalse();
// NORMALE
assertThat(PrioriteAide.NORMALE.getLibelle()).isEqualTo("Normale");
assertThat(PrioriteAide.NORMALE.getCode()).isEqualTo("normal");
assertThat(PrioriteAide.NORMALE.getNiveau()).isEqualTo(4);
assertThat(PrioriteAide.NORMALE.getDescription()).isEqualTo("Priorité normale, traitement selon les délais standards");
assertThat(PrioriteAide.NORMALE.getCouleur()).isEqualTo("#2196F3");
assertThat(PrioriteAide.NORMALE.getIcone()).isEqualTo("remove");
assertThat(PrioriteAide.NORMALE.getDelaiTraitementHeures()).isEqualTo(336);
assertThat(PrioriteAide.NORMALE.isNotificationImmediate()).isFalse();
assertThat(PrioriteAide.NORMALE.isEscaladeAutomatique()).isFalse();
// FAIBLE
assertThat(PrioriteAide.FAIBLE.getLibelle()).isEqualTo("Faible");
assertThat(PrioriteAide.FAIBLE.getCode()).isEqualTo("low");
assertThat(PrioriteAide.FAIBLE.getNiveau()).isEqualTo(5);
assertThat(PrioriteAide.FAIBLE.getDescription()).isEqualTo("Priorité faible, traitement quand les ressources le permettent");
assertThat(PrioriteAide.FAIBLE.getCouleur()).isEqualTo("#4CAF50");
assertThat(PrioriteAide.FAIBLE.getIcone()).isEqualTo("keyboard_arrow_down");
assertThat(PrioriteAide.FAIBLE.getDelaiTraitementHeures()).isEqualTo(720);
assertThat(PrioriteAide.FAIBLE.isNotificationImmediate()).isFalse();
assertThat(PrioriteAide.FAIBLE.isEscaladeAutomatique()).isFalse();
}
@Test
@DisplayName("Test valueOf et values")
void testValueOfEtValues() {
PrioriteAide[] values = PrioriteAide.values();
assertThat(values).hasSize(5);
assertThat(values).containsExactly(
PrioriteAide.CRITIQUE,
PrioriteAide.URGENTE,
PrioriteAide.ELEVEE,
PrioriteAide.NORMALE,
PrioriteAide.FAIBLE);
assertThat(PrioriteAide.valueOf("CRITIQUE")).isEqualTo(PrioriteAide.CRITIQUE);
assertThat(PrioriteAide.valueOf("URGENTE")).isEqualTo(PrioriteAide.URGENTE);
assertThat(PrioriteAide.valueOf("ELEVEE")).isEqualTo(PrioriteAide.ELEVEE);
assertThat(PrioriteAide.valueOf("NORMALE")).isEqualTo(PrioriteAide.NORMALE);
assertThat(PrioriteAide.valueOf("FAIBLE")).isEqualTo(PrioriteAide.FAIBLE);
assertThatThrownBy(() -> PrioriteAide.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@Test
@DisplayName("Test ordinal et name")
void testOrdinalEtName() {
assertThat(PrioriteAide.CRITIQUE.ordinal()).isEqualTo(0);
assertThat(PrioriteAide.URGENTE.ordinal()).isEqualTo(1);
assertThat(PrioriteAide.ELEVEE.ordinal()).isEqualTo(2);
assertThat(PrioriteAide.NORMALE.ordinal()).isEqualTo(3);
assertThat(PrioriteAide.FAIBLE.ordinal()).isEqualTo(4);
assertThat(PrioriteAide.CRITIQUE.name()).isEqualTo("CRITIQUE");
assertThat(PrioriteAide.URGENTE.name()).isEqualTo("URGENTE");
assertThat(PrioriteAide.ELEVEE.name()).isEqualTo("ELEVEE");
assertThat(PrioriteAide.NORMALE.name()).isEqualTo("NORMALE");
assertThat(PrioriteAide.FAIBLE.name()).isEqualTo("FAIBLE");
}
@Test
@DisplayName("Test toString")
void testToString() {
assertThat(PrioriteAide.CRITIQUE.toString()).isEqualTo("CRITIQUE");
assertThat(PrioriteAide.URGENTE.toString()).isEqualTo("URGENTE");
assertThat(PrioriteAide.ELEVEE.toString()).isEqualTo("ELEVEE");
assertThat(PrioriteAide.NORMALE.toString()).isEqualTo("NORMALE");
assertThat(PrioriteAide.FAIBLE.toString()).isEqualTo("FAIBLE");
}
}
@Nested
@DisplayName("Tests des méthodes métier")
class TestsMethodesMetier {
@Test
@DisplayName("Test isUrgente - toutes les branches")
void testIsUrgente() {
// Priorités urgentes (this == CRITIQUE || this == URGENTE)
assertThat(PrioriteAide.CRITIQUE.isUrgente()).isTrue();
assertThat(PrioriteAide.URGENTE.isUrgente()).isTrue();
// Priorités non urgentes
assertThat(PrioriteAide.ELEVEE.isUrgente()).isFalse();
assertThat(PrioriteAide.NORMALE.isUrgente()).isFalse();
assertThat(PrioriteAide.FAIBLE.isUrgente()).isFalse();
}
@Test
@DisplayName("Test necessiteTraitementImmediat - toutes les branches")
void testNecessiteTraitementImmediat() {
// Niveau <= 2
assertThat(PrioriteAide.CRITIQUE.necessiteTraitementImmediat()).isTrue(); // niveau 1
assertThat(PrioriteAide.URGENTE.necessiteTraitementImmediat()).isTrue(); // niveau 2
// Niveau > 2
assertThat(PrioriteAide.ELEVEE.necessiteTraitementImmediat()).isFalse(); // niveau 3
assertThat(PrioriteAide.NORMALE.necessiteTraitementImmediat()).isFalse(); // niveau 4
assertThat(PrioriteAide.FAIBLE.necessiteTraitementImmediat()).isFalse(); // niveau 5
}
@Test
@DisplayName("Test getDateLimiteTraitement")
void testGetDateLimiteTraitement() {
LocalDateTime avant = LocalDateTime.now();
LocalDateTime dateLimite = PrioriteAide.CRITIQUE.getDateLimiteTraitement();
LocalDateTime apres = LocalDateTime.now();
// La date limite doit être maintenant + 24 heures (±1 seconde pour l'exécution)
LocalDateTime attendu = avant.plusHours(24);
assertThat(dateLimite).isBetween(attendu.minusSeconds(1), apres.plusHours(24).plusSeconds(1));
// Test avec URGENTE (72 heures)
dateLimite = PrioriteAide.URGENTE.getDateLimiteTraitement();
attendu = LocalDateTime.now().plusHours(72);
assertThat(dateLimite).isCloseTo(attendu, within(1, ChronoUnit.SECONDS));
}
@Test
@DisplayName("Test getPrioriteEscalade - toutes les branches du switch")
void testGetPrioriteEscalade() {
// Test toutes les branches du switch
assertThat(PrioriteAide.FAIBLE.getPrioriteEscalade()).isEqualTo(PrioriteAide.NORMALE);
assertThat(PrioriteAide.NORMALE.getPrioriteEscalade()).isEqualTo(PrioriteAide.ELEVEE);
assertThat(PrioriteAide.ELEVEE.getPrioriteEscalade()).isEqualTo(PrioriteAide.URGENTE);
assertThat(PrioriteAide.URGENTE.getPrioriteEscalade()).isEqualTo(PrioriteAide.CRITIQUE);
assertThat(PrioriteAide.CRITIQUE.getPrioriteEscalade()).isEqualTo(PrioriteAide.CRITIQUE); // Déjà au maximum
}
}
@Nested
@DisplayName("Tests des méthodes statiques")
class TestsMethodesStatiques {
@Test
@DisplayName("Test getPrioritesUrgentes")
void testGetPrioritesUrgentes() {
List<PrioriteAide> urgentes = PrioriteAide.getPrioritesUrgentes();
assertThat(urgentes).hasSize(2);
assertThat(urgentes).containsExactly(PrioriteAide.CRITIQUE, PrioriteAide.URGENTE);
// Vérifier que toutes les priorités retournées sont bien urgentes
urgentes.forEach(p -> assertThat(p.isUrgente()).isTrue());
}
@Test
@DisplayName("Test getParNiveauCroissant")
void testGetParNiveauCroissant() {
List<PrioriteAide> croissant = PrioriteAide.getParNiveauCroissant();
assertThat(croissant).hasSize(5);
assertThat(croissant).containsExactly(
PrioriteAide.CRITIQUE, // niveau 1
PrioriteAide.URGENTE, // niveau 2
PrioriteAide.ELEVEE, // niveau 3
PrioriteAide.NORMALE, // niveau 4
PrioriteAide.FAIBLE); // niveau 5
// Vérifier l'ordre croissant
for (int i = 0; i < croissant.size() - 1; i++) {
assertThat(croissant.get(i).getNiveau()).isLessThan(croissant.get(i + 1).getNiveau());
}
}
@Test
@DisplayName("Test getParNiveauDecroissant")
void testGetParNiveauDecroissant() {
List<PrioriteAide> decroissant = PrioriteAide.getParNiveauDecroissant();
assertThat(decroissant).hasSize(5);
assertThat(decroissant).containsExactly(
PrioriteAide.FAIBLE, // niveau 5
PrioriteAide.NORMALE, // niveau 4
PrioriteAide.ELEVEE, // niveau 3
PrioriteAide.URGENTE, // niveau 2
PrioriteAide.CRITIQUE); // niveau 1
// Vérifier l'ordre décroissant
for (int i = 0; i < decroissant.size() - 1; i++) {
assertThat(decroissant.get(i).getNiveau()).isGreaterThan(decroissant.get(i + 1).getNiveau());
}
}
@Test
@DisplayName("Test parCode - toutes les branches")
void testParCode() {
// Codes existants
assertThat(PrioriteAide.parCode("critical")).isEqualTo(PrioriteAide.CRITIQUE);
assertThat(PrioriteAide.parCode("urgent")).isEqualTo(PrioriteAide.URGENTE);
assertThat(PrioriteAide.parCode("high")).isEqualTo(PrioriteAide.ELEVEE);
assertThat(PrioriteAide.parCode("normal")).isEqualTo(PrioriteAide.NORMALE);
assertThat(PrioriteAide.parCode("low")).isEqualTo(PrioriteAide.FAIBLE);
// Code inexistant - retourne NORMALE par défaut
assertThat(PrioriteAide.parCode("inexistant")).isEqualTo(PrioriteAide.NORMALE);
assertThat(PrioriteAide.parCode("")).isEqualTo(PrioriteAide.NORMALE);
assertThat(PrioriteAide.parCode(null)).isEqualTo(PrioriteAide.NORMALE);
}
@Test
@DisplayName("Test determinerPriorite - toutes les branches")
void testDeterminerPriorite() {
// Types urgents avec switch spécifique
assertThat(PrioriteAide.determinerPriorite(TypeAide.AIDE_FINANCIERE_URGENTE))
.isEqualTo(PrioriteAide.CRITIQUE);
assertThat(PrioriteAide.determinerPriorite(TypeAide.AIDE_FRAIS_MEDICAUX))
.isEqualTo(PrioriteAide.CRITIQUE);
assertThat(PrioriteAide.determinerPriorite(TypeAide.HEBERGEMENT_URGENCE))
.isEqualTo(PrioriteAide.URGENTE);
assertThat(PrioriteAide.determinerPriorite(TypeAide.AIDE_ALIMENTAIRE))
.isEqualTo(PrioriteAide.URGENTE);
// Type urgent avec default du switch
assertThat(PrioriteAide.determinerPriorite(TypeAide.PRET_SANS_INTERET))
.isEqualTo(PrioriteAide.ELEVEE); // urgent mais pas dans les cas spécifiques
// Type avec priorité "important" (non urgent)
assertThat(PrioriteAide.determinerPriorite(TypeAide.AIDE_FRAIS_SCOLARITE))
.isEqualTo(PrioriteAide.ELEVEE); // priorité "important"
// Type normal (ni urgent ni important)
assertThat(PrioriteAide.determinerPriorite(TypeAide.DON_MATERIEL))
.isEqualTo(PrioriteAide.NORMALE); // priorité "normal"
assertThat(PrioriteAide.determinerPriorite(TypeAide.AIDE_COTISATION))
.isEqualTo(PrioriteAide.NORMALE); // priorité "normal"
}
}
@Nested
@DisplayName("Tests des méthodes de calcul et temporelles")
class TestsCalculsTemporels {
@Test
@DisplayName("Test getScorePriorite - toutes les branches")
void testGetScorePriorite() {
// CRITIQUE: niveau=1, notificationImmediate=true, escaladeAutomatique=true, delai=24h
// Score = 1 - 0.5 - 0.3 = 0.2
assertThat(PrioriteAide.CRITIQUE.getScorePriorite()).isEqualTo(0.2);
// URGENTE: niveau=2, notificationImmediate=true, escaladeAutomatique=false, delai=72h
// Score = 2 - 0.5 = 1.5
assertThat(PrioriteAide.URGENTE.getScorePriorite()).isEqualTo(1.5);
// ELEVEE: niveau=3, notificationImmediate=false, escaladeAutomatique=false, delai=168h
// Score = 3 (pas de bonus/malus car délai = 168h exactement)
assertThat(PrioriteAide.ELEVEE.getScorePriorite()).isEqualTo(3.0);
// NORMALE: niveau=4, notificationImmediate=false, escaladeAutomatique=false, delai=336h
// Score = 4 + 0.2 = 4.2 (malus car délai > 168h)
assertThat(PrioriteAide.NORMALE.getScorePriorite()).isEqualTo(4.2);
// FAIBLE: niveau=5, notificationImmediate=false, escaladeAutomatique=false, delai=720h
// Score = 5 + 0.2 = 5.2 (malus car délai > 168h)
assertThat(PrioriteAide.FAIBLE.getScorePriorite()).isEqualTo(5.2);
}
@Test
@DisplayName("Test isDelaiDepasse - toutes les branches")
void testIsDelaiDepasse() {
LocalDateTime maintenant = LocalDateTime.now();
// Délai non dépassé
LocalDateTime dateCreationRecente = maintenant.minusHours(1);
assertThat(PrioriteAide.CRITIQUE.isDelaiDepasse(dateCreationRecente)).isFalse(); // 1h < 24h
// Délai dépassé
LocalDateTime dateCreationAncienne = maintenant.minusHours(25);
assertThat(PrioriteAide.CRITIQUE.isDelaiDepasse(dateCreationAncienne)).isTrue(); // 25h > 24h
// Test limite exacte
LocalDateTime dateCreationLimite = maintenant.minusHours(24);
assertThat(PrioriteAide.CRITIQUE.isDelaiDepasse(dateCreationLimite)).isFalse(); // 24h = 24h (pas après)
// Test avec URGENTE
dateCreationAncienne = maintenant.minusHours(73);
assertThat(PrioriteAide.URGENTE.isDelaiDepasse(dateCreationAncienne)).isTrue(); // 73h > 72h
}
@Test
@DisplayName("Test getPourcentageTempsEcoule - toutes les branches")
void testGetPourcentageTempsEcoule() {
LocalDateTime maintenant = LocalDateTime.now();
// 0% écoulé (juste créé)
LocalDateTime dateCreation = maintenant;
double pourcentage = PrioriteAide.CRITIQUE.getPourcentageTempsEcoule(dateCreation);
assertThat(pourcentage).isCloseTo(0.0, within(1.0));
// 50% écoulé (12h sur 24h)
dateCreation = maintenant.minusHours(12);
pourcentage = PrioriteAide.CRITIQUE.getPourcentageTempsEcoule(dateCreation);
assertThat(pourcentage).isCloseTo(50.0, within(1.0));
// 100% écoulé (24h sur 24h)
dateCreation = maintenant.minusHours(24);
pourcentage = PrioriteAide.CRITIQUE.getPourcentageTempsEcoule(dateCreation);
assertThat(pourcentage).isCloseTo(100.0, within(1.0));
// Plus de 100% écoulé (30h sur 24h) - plafonné à 100%
dateCreation = maintenant.minusHours(30);
pourcentage = PrioriteAide.CRITIQUE.getPourcentageTempsEcoule(dateCreation);
assertThat(pourcentage).isEqualTo(100.0);
// Test cas limite: date future (dureeEcoulee négative)
dateCreation = maintenant.plusHours(1);
pourcentage = PrioriteAide.CRITIQUE.getPourcentageTempsEcoule(dateCreation);
// dateCreation = maintenant + 1h, dateLimite = dateCreation + 24h = maintenant + 25h
// dureeTotal = 24h = 1440 min (positif), dureeEcoulee = -1h = -60 min (négatif)
// Calcul: (-60 * 100) / 1440 = -4.166..., puis Math.min(100, -4.166) = -4.166
assertThat(pourcentage).isCloseTo(-4.166666666666667, within(0.001));
}
@Test
@DisplayName("Test getMessageAlerte - toutes les branches")
void testGetMessageAlerte() {
LocalDateTime maintenant = LocalDateTime.now();
// Aucun message (< 60%)
LocalDateTime dateCreation = maintenant.minusHours(10); // ~42% pour CRITIQUE
String message = PrioriteAide.CRITIQUE.getMessageAlerte(dateCreation);
assertThat(message).isNull();
// Plus de la moitié du délai écoulé (60% <= x < 80%)
dateCreation = maintenant.minusHours(15); // ~62% pour CRITIQUE
message = PrioriteAide.CRITIQUE.getMessageAlerte(dateCreation);
assertThat(message).isEqualTo("Plus de la moitié du délai écoulé");
// Délai bientôt dépassé (80% <= x < 100%)
dateCreation = maintenant.minusHours(20); // ~83% pour CRITIQUE
message = PrioriteAide.CRITIQUE.getMessageAlerte(dateCreation);
assertThat(message).isEqualTo("Délai de traitement bientôt dépassé");
// Délai dépassé (>= 100%)
dateCreation = maintenant.minusHours(25); // > 100% pour CRITIQUE
message = PrioriteAide.CRITIQUE.getMessageAlerte(dateCreation);
assertThat(message).isEqualTo("Délai de traitement dépassé !");
}
}
@Test
@DisplayName("Test cohérence globale des données")
void testCoherenceGlobale() {
for (PrioriteAide priorite : PrioriteAide.values()) {
// Tous les champs obligatoires non null
assertThat(priorite.getLibelle()).isNotNull().isNotEmpty();
assertThat(priorite.getCode()).isNotNull().isNotEmpty();
assertThat(priorite.getDescription()).isNotNull().isNotEmpty();
assertThat(priorite.getCouleur()).isNotNull().matches("#[0-9A-Fa-f]{6}");
assertThat(priorite.getIcone()).isNotNull().isNotEmpty();
assertThat(priorite.getNiveau()).isPositive();
assertThat(priorite.getDelaiTraitementHeures()).isPositive();
// Cohérence logique
if (priorite.getNiveau() <= 2) {
assertThat(priorite.necessiteTraitementImmediat()).isTrue();
}
if (priorite == PrioriteAide.CRITIQUE || priorite == PrioriteAide.URGENTE) {
assertThat(priorite.isUrgente()).isTrue();
}
// Score de priorité cohérent (plus bas = plus prioritaire)
double score = priorite.getScorePriorite();
assertThat(score).isPositive();
// Les méthodes temporelles fonctionnent
LocalDateTime maintenant = LocalDateTime.now();
assertThat(priorite.getDateLimiteTraitement()).isAfter(maintenant);
assertThat(priorite.getPourcentageTempsEcoule(maintenant.minusHours(1))).isBetween(0.0, 100.0);
}
}
}

View File

@@ -0,0 +1,663 @@
package dev.lions.unionflow.server.api.enums.solidarite;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires EXHAUSTIFS pour StatutAide - Couverture 100%
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@DisplayName("Tests EXHAUSTIFS StatutAide")
class StatutAideTest {
@Nested
@DisplayName("Tests des valeurs enum et constructeur")
class TestsValeursEnum {
@Test
@DisplayName("Test toutes les valeurs enum avec propriétés exactes")
void testToutesValeursExactes() {
// STATUTS INITIAUX
assertThat(StatutAide.BROUILLON.getLibelle()).isEqualTo("Brouillon");
assertThat(StatutAide.BROUILLON.getCode()).isEqualTo("draft");
assertThat(StatutAide.BROUILLON.getDescription()).isEqualTo("La demande est en cours de rédaction");
assertThat(StatutAide.BROUILLON.getCouleur()).isEqualTo("#9E9E9E");
assertThat(StatutAide.BROUILLON.getIcone()).isEqualTo("edit");
assertThat(StatutAide.BROUILLON.isEstFinal()).isFalse();
assertThat(StatutAide.BROUILLON.isEstEchec()).isFalse();
assertThat(StatutAide.SOUMISE.getLibelle()).isEqualTo("Soumise");
assertThat(StatutAide.SOUMISE.getCode()).isEqualTo("submitted");
assertThat(StatutAide.SOUMISE.getDescription()).isEqualTo("La demande a été soumise et attend validation");
assertThat(StatutAide.SOUMISE.getCouleur()).isEqualTo("#FF9800");
assertThat(StatutAide.SOUMISE.getIcone()).isEqualTo("send");
assertThat(StatutAide.SOUMISE.isEstFinal()).isFalse();
assertThat(StatutAide.SOUMISE.isEstEchec()).isFalse();
// STATUTS D'ÉVALUATION
assertThat(StatutAide.EN_ATTENTE.getLibelle()).isEqualTo("En attente");
assertThat(StatutAide.EN_ATTENTE.getCode()).isEqualTo("pending");
assertThat(StatutAide.EN_ATTENTE.getDescription()).isEqualTo("La demande est en attente d'évaluation");
assertThat(StatutAide.EN_ATTENTE.getCouleur()).isEqualTo("#2196F3");
assertThat(StatutAide.EN_ATTENTE.getIcone()).isEqualTo("hourglass_empty");
assertThat(StatutAide.EN_ATTENTE.isEstFinal()).isFalse();
assertThat(StatutAide.EN_ATTENTE.isEstEchec()).isFalse();
assertThat(StatutAide.EN_COURS_EVALUATION.getLibelle()).isEqualTo("En cours d'évaluation");
assertThat(StatutAide.EN_COURS_EVALUATION.getCode()).isEqualTo("under_review");
assertThat(StatutAide.EN_COURS_EVALUATION.getDescription()).isEqualTo("La demande est en cours d'évaluation");
assertThat(StatutAide.EN_COURS_EVALUATION.getCouleur()).isEqualTo("#FF9800");
assertThat(StatutAide.EN_COURS_EVALUATION.getIcone()).isEqualTo("rate_review");
assertThat(StatutAide.EN_COURS_EVALUATION.isEstFinal()).isFalse();
assertThat(StatutAide.EN_COURS_EVALUATION.isEstEchec()).isFalse();
assertThat(StatutAide.INFORMATIONS_REQUISES.getLibelle()).isEqualTo("Informations requises");
assertThat(StatutAide.INFORMATIONS_REQUISES.getCode()).isEqualTo("info_required");
assertThat(StatutAide.INFORMATIONS_REQUISES.getDescription()).isEqualTo("Des informations complémentaires sont requises");
assertThat(StatutAide.INFORMATIONS_REQUISES.getCouleur()).isEqualTo("#FF5722");
assertThat(StatutAide.INFORMATIONS_REQUISES.getIcone()).isEqualTo("info");
assertThat(StatutAide.INFORMATIONS_REQUISES.isEstFinal()).isFalse();
assertThat(StatutAide.INFORMATIONS_REQUISES.isEstEchec()).isFalse();
// STATUTS DE DÉCISION
assertThat(StatutAide.APPROUVEE.getLibelle()).isEqualTo("Approuvée");
assertThat(StatutAide.APPROUVEE.getCode()).isEqualTo("approved");
assertThat(StatutAide.APPROUVEE.getDescription()).isEqualTo("La demande a été approuvée");
assertThat(StatutAide.APPROUVEE.getCouleur()).isEqualTo("#4CAF50");
assertThat(StatutAide.APPROUVEE.getIcone()).isEqualTo("check_circle");
assertThat(StatutAide.APPROUVEE.isEstFinal()).isTrue();
assertThat(StatutAide.APPROUVEE.isEstEchec()).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.getLibelle()).isEqualTo("Approuvée partiellement");
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.getCode()).isEqualTo("partially_approved");
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.getDescription()).isEqualTo("La demande a été approuvée partiellement");
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.getCouleur()).isEqualTo("#8BC34A");
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.getIcone()).isEqualTo("check_circle_outline");
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.isEstFinal()).isTrue();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.isEstEchec()).isFalse();
assertThat(StatutAide.REJETEE.getLibelle()).isEqualTo("Rejetée");
assertThat(StatutAide.REJETEE.getCode()).isEqualTo("rejected");
assertThat(StatutAide.REJETEE.getDescription()).isEqualTo("La demande a été rejetée");
assertThat(StatutAide.REJETEE.getCouleur()).isEqualTo("#F44336");
assertThat(StatutAide.REJETEE.getIcone()).isEqualTo("cancel");
assertThat(StatutAide.REJETEE.isEstFinal()).isTrue();
assertThat(StatutAide.REJETEE.isEstEchec()).isTrue();
// STATUTS DE TRAITEMENT
assertThat(StatutAide.EN_COURS_TRAITEMENT.getLibelle()).isEqualTo("En cours de traitement");
assertThat(StatutAide.EN_COURS_TRAITEMENT.getCode()).isEqualTo("processing");
assertThat(StatutAide.EN_COURS_TRAITEMENT.getDescription()).isEqualTo("La demande approuvée est en cours de traitement");
assertThat(StatutAide.EN_COURS_TRAITEMENT.getCouleur()).isEqualTo("#9C27B0");
assertThat(StatutAide.EN_COURS_TRAITEMENT.getIcone()).isEqualTo("settings");
assertThat(StatutAide.EN_COURS_TRAITEMENT.isEstFinal()).isFalse();
assertThat(StatutAide.EN_COURS_TRAITEMENT.isEstEchec()).isFalse();
assertThat(StatutAide.EN_COURS_VERSEMENT.getLibelle()).isEqualTo("En cours de versement");
assertThat(StatutAide.EN_COURS_VERSEMENT.getCode()).isEqualTo("payment_processing");
assertThat(StatutAide.EN_COURS_VERSEMENT.getDescription()).isEqualTo("Le versement est en cours");
assertThat(StatutAide.EN_COURS_VERSEMENT.getCouleur()).isEqualTo("#3F51B5");
assertThat(StatutAide.EN_COURS_VERSEMENT.getIcone()).isEqualTo("payment");
assertThat(StatutAide.EN_COURS_VERSEMENT.isEstFinal()).isFalse();
assertThat(StatutAide.EN_COURS_VERSEMENT.isEstEchec()).isFalse();
// STATUTS FINAUX
assertThat(StatutAide.VERSEE.getLibelle()).isEqualTo("Versée");
assertThat(StatutAide.VERSEE.getCode()).isEqualTo("paid");
assertThat(StatutAide.VERSEE.getDescription()).isEqualTo("L'aide a été versée avec succès");
assertThat(StatutAide.VERSEE.getCouleur()).isEqualTo("#4CAF50");
assertThat(StatutAide.VERSEE.getIcone()).isEqualTo("paid");
assertThat(StatutAide.VERSEE.isEstFinal()).isTrue();
assertThat(StatutAide.VERSEE.isEstEchec()).isFalse();
assertThat(StatutAide.LIVREE.getLibelle()).isEqualTo("Livrée");
assertThat(StatutAide.LIVREE.getCode()).isEqualTo("delivered");
assertThat(StatutAide.LIVREE.getDescription()).isEqualTo("L'aide matérielle a été livrée");
assertThat(StatutAide.LIVREE.getCouleur()).isEqualTo("#4CAF50");
assertThat(StatutAide.LIVREE.getIcone()).isEqualTo("local_shipping");
assertThat(StatutAide.LIVREE.isEstFinal()).isTrue();
assertThat(StatutAide.LIVREE.isEstEchec()).isFalse();
assertThat(StatutAide.TERMINEE.getLibelle()).isEqualTo("Terminée");
assertThat(StatutAide.TERMINEE.getCode()).isEqualTo("completed");
assertThat(StatutAide.TERMINEE.getDescription()).isEqualTo("L'aide a été fournie avec succès");
assertThat(StatutAide.TERMINEE.getCouleur()).isEqualTo("#4CAF50");
assertThat(StatutAide.TERMINEE.getIcone()).isEqualTo("done_all");
assertThat(StatutAide.TERMINEE.isEstFinal()).isTrue();
assertThat(StatutAide.TERMINEE.isEstEchec()).isFalse();
// STATUTS D'EXCEPTION
assertThat(StatutAide.ANNULEE.getLibelle()).isEqualTo("Annulée");
assertThat(StatutAide.ANNULEE.getCode()).isEqualTo("cancelled");
assertThat(StatutAide.ANNULEE.getDescription()).isEqualTo("La demande a été annulée");
assertThat(StatutAide.ANNULEE.getCouleur()).isEqualTo("#9E9E9E");
assertThat(StatutAide.ANNULEE.getIcone()).isEqualTo("cancel");
assertThat(StatutAide.ANNULEE.isEstFinal()).isTrue();
assertThat(StatutAide.ANNULEE.isEstEchec()).isTrue();
assertThat(StatutAide.SUSPENDUE.getLibelle()).isEqualTo("Suspendue");
assertThat(StatutAide.SUSPENDUE.getCode()).isEqualTo("suspended");
assertThat(StatutAide.SUSPENDUE.getDescription()).isEqualTo("La demande a été suspendue temporairement");
assertThat(StatutAide.SUSPENDUE.getCouleur()).isEqualTo("#FF5722");
assertThat(StatutAide.SUSPENDUE.getIcone()).isEqualTo("pause_circle");
assertThat(StatutAide.SUSPENDUE.isEstFinal()).isFalse();
assertThat(StatutAide.SUSPENDUE.isEstEchec()).isFalse();
assertThat(StatutAide.EXPIREE.getLibelle()).isEqualTo("Expirée");
assertThat(StatutAide.EXPIREE.getCode()).isEqualTo("expired");
assertThat(StatutAide.EXPIREE.getDescription()).isEqualTo("La demande a expiré");
assertThat(StatutAide.EXPIREE.getCouleur()).isEqualTo("#795548");
assertThat(StatutAide.EXPIREE.getIcone()).isEqualTo("schedule");
assertThat(StatutAide.EXPIREE.isEstFinal()).isTrue();
assertThat(StatutAide.EXPIREE.isEstEchec()).isTrue();
// STATUTS DE SUIVI
assertThat(StatutAide.EN_SUIVI.getLibelle()).isEqualTo("En suivi");
assertThat(StatutAide.EN_SUIVI.getCode()).isEqualTo("follow_up");
assertThat(StatutAide.EN_SUIVI.getDescription()).isEqualTo("L'aide fait l'objet d'un suivi");
assertThat(StatutAide.EN_SUIVI.getCouleur()).isEqualTo("#607D8B");
assertThat(StatutAide.EN_SUIVI.getIcone()).isEqualTo("track_changes");
assertThat(StatutAide.EN_SUIVI.isEstFinal()).isFalse();
assertThat(StatutAide.EN_SUIVI.isEstEchec()).isFalse();
assertThat(StatutAide.CLOTUREE.getLibelle()).isEqualTo("Clôturée");
assertThat(StatutAide.CLOTUREE.getCode()).isEqualTo("closed");
assertThat(StatutAide.CLOTUREE.getDescription()).isEqualTo("Le dossier d'aide est clôturé");
assertThat(StatutAide.CLOTUREE.getCouleur()).isEqualTo("#9E9E9E");
assertThat(StatutAide.CLOTUREE.getIcone()).isEqualTo("folder");
assertThat(StatutAide.CLOTUREE.isEstFinal()).isTrue();
assertThat(StatutAide.CLOTUREE.isEstEchec()).isFalse();
}
@Test
@DisplayName("Test valueOf et values")
void testValueOfEtValues() {
StatutAide[] values = StatutAide.values();
assertThat(values).hasSize(18);
assertThat(values).containsExactly(
StatutAide.BROUILLON,
StatutAide.SOUMISE,
StatutAide.EN_ATTENTE,
StatutAide.EN_COURS_EVALUATION,
StatutAide.INFORMATIONS_REQUISES,
StatutAide.APPROUVEE,
StatutAide.APPROUVEE_PARTIELLEMENT,
StatutAide.REJETEE,
StatutAide.EN_COURS_TRAITEMENT,
StatutAide.EN_COURS_VERSEMENT,
StatutAide.VERSEE,
StatutAide.LIVREE,
StatutAide.TERMINEE,
StatutAide.ANNULEE,
StatutAide.SUSPENDUE,
StatutAide.EXPIREE,
StatutAide.EN_SUIVI,
StatutAide.CLOTUREE);
// Test valueOf pour quelques valeurs
assertThat(StatutAide.valueOf("BROUILLON")).isEqualTo(StatutAide.BROUILLON);
assertThat(StatutAide.valueOf("EN_COURS_EVALUATION")).isEqualTo(StatutAide.EN_COURS_EVALUATION);
assertThat(StatutAide.valueOf("APPROUVEE_PARTIELLEMENT")).isEqualTo(StatutAide.APPROUVEE_PARTIELLEMENT);
assertThatThrownBy(() -> StatutAide.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@Test
@DisplayName("Test ordinal, name et toString")
void testOrdinalNameToString() {
assertThat(StatutAide.BROUILLON.ordinal()).isEqualTo(0);
assertThat(StatutAide.SOUMISE.ordinal()).isEqualTo(1);
assertThat(StatutAide.CLOTUREE.ordinal()).isEqualTo(17);
assertThat(StatutAide.BROUILLON.name()).isEqualTo("BROUILLON");
assertThat(StatutAide.EN_COURS_EVALUATION.name()).isEqualTo("EN_COURS_EVALUATION");
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.name()).isEqualTo("APPROUVEE_PARTIELLEMENT");
assertThat(StatutAide.BROUILLON.toString()).isEqualTo("BROUILLON");
assertThat(StatutAide.EN_COURS_EVALUATION.toString()).isEqualTo("EN_COURS_EVALUATION");
}
}
@Nested
@DisplayName("Tests des méthodes métier")
class TestsMethodesMetier {
@Test
@DisplayName("Test isSucces - toutes les branches")
void testIsSucces() {
// Statuts de succès (this == VERSEE || this == LIVREE || this == TERMINEE)
assertThat(StatutAide.VERSEE.isSucces()).isTrue();
assertThat(StatutAide.LIVREE.isSucces()).isTrue();
assertThat(StatutAide.TERMINEE.isSucces()).isTrue();
// Tous les autres statuts ne sont pas des succès
assertThat(StatutAide.BROUILLON.isSucces()).isFalse();
assertThat(StatutAide.SOUMISE.isSucces()).isFalse();
assertThat(StatutAide.EN_ATTENTE.isSucces()).isFalse();
assertThat(StatutAide.EN_COURS_EVALUATION.isSucces()).isFalse();
assertThat(StatutAide.INFORMATIONS_REQUISES.isSucces()).isFalse();
assertThat(StatutAide.APPROUVEE.isSucces()).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.isSucces()).isFalse();
assertThat(StatutAide.REJETEE.isSucces()).isFalse();
assertThat(StatutAide.EN_COURS_TRAITEMENT.isSucces()).isFalse();
assertThat(StatutAide.EN_COURS_VERSEMENT.isSucces()).isFalse();
assertThat(StatutAide.ANNULEE.isSucces()).isFalse();
assertThat(StatutAide.SUSPENDUE.isSucces()).isFalse();
assertThat(StatutAide.EXPIREE.isSucces()).isFalse();
assertThat(StatutAide.EN_SUIVI.isSucces()).isFalse();
assertThat(StatutAide.CLOTUREE.isSucces()).isFalse();
}
@Test
@DisplayName("Test isEnCours - toutes les branches")
void testIsEnCours() {
// Statuts en cours (this == EN_COURS_EVALUATION || this == EN_COURS_TRAITEMENT || this == EN_COURS_VERSEMENT)
assertThat(StatutAide.EN_COURS_EVALUATION.isEnCours()).isTrue();
assertThat(StatutAide.EN_COURS_TRAITEMENT.isEnCours()).isTrue();
assertThat(StatutAide.EN_COURS_VERSEMENT.isEnCours()).isTrue();
// Tous les autres statuts ne sont pas en cours
assertThat(StatutAide.BROUILLON.isEnCours()).isFalse();
assertThat(StatutAide.SOUMISE.isEnCours()).isFalse();
assertThat(StatutAide.EN_ATTENTE.isEnCours()).isFalse();
assertThat(StatutAide.INFORMATIONS_REQUISES.isEnCours()).isFalse();
assertThat(StatutAide.APPROUVEE.isEnCours()).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.isEnCours()).isFalse();
assertThat(StatutAide.REJETEE.isEnCours()).isFalse();
assertThat(StatutAide.VERSEE.isEnCours()).isFalse();
assertThat(StatutAide.LIVREE.isEnCours()).isFalse();
assertThat(StatutAide.TERMINEE.isEnCours()).isFalse();
assertThat(StatutAide.ANNULEE.isEnCours()).isFalse();
assertThat(StatutAide.SUSPENDUE.isEnCours()).isFalse();
assertThat(StatutAide.EXPIREE.isEnCours()).isFalse();
assertThat(StatutAide.EN_SUIVI.isEnCours()).isFalse();
assertThat(StatutAide.CLOTUREE.isEnCours()).isFalse();
}
@Test
@DisplayName("Test permetModification - toutes les branches")
void testPermetModification() {
// Statuts qui permettent modification (this == BROUILLON || this == INFORMATIONS_REQUISES)
assertThat(StatutAide.BROUILLON.permetModification()).isTrue();
assertThat(StatutAide.INFORMATIONS_REQUISES.permetModification()).isTrue();
// Tous les autres statuts ne permettent pas la modification
assertThat(StatutAide.SOUMISE.permetModification()).isFalse();
assertThat(StatutAide.EN_ATTENTE.permetModification()).isFalse();
assertThat(StatutAide.EN_COURS_EVALUATION.permetModification()).isFalse();
assertThat(StatutAide.APPROUVEE.permetModification()).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.permetModification()).isFalse();
assertThat(StatutAide.REJETEE.permetModification()).isFalse();
assertThat(StatutAide.EN_COURS_TRAITEMENT.permetModification()).isFalse();
assertThat(StatutAide.EN_COURS_VERSEMENT.permetModification()).isFalse();
assertThat(StatutAide.VERSEE.permetModification()).isFalse();
assertThat(StatutAide.LIVREE.permetModification()).isFalse();
assertThat(StatutAide.TERMINEE.permetModification()).isFalse();
assertThat(StatutAide.ANNULEE.permetModification()).isFalse();
assertThat(StatutAide.SUSPENDUE.permetModification()).isFalse();
assertThat(StatutAide.EXPIREE.permetModification()).isFalse();
assertThat(StatutAide.EN_SUIVI.permetModification()).isFalse();
assertThat(StatutAide.CLOTUREE.permetModification()).isFalse();
}
@Test
@DisplayName("Test permetAnnulation - toutes les branches")
void testPermetAnnulation() {
// Permet annulation si (!estFinal && this != ANNULEE)
// Statuts non finaux et non annulés = permettent annulation
assertThat(StatutAide.BROUILLON.permetAnnulation()).isTrue();
assertThat(StatutAide.SOUMISE.permetAnnulation()).isTrue();
assertThat(StatutAide.EN_ATTENTE.permetAnnulation()).isTrue();
assertThat(StatutAide.EN_COURS_EVALUATION.permetAnnulation()).isTrue();
assertThat(StatutAide.INFORMATIONS_REQUISES.permetAnnulation()).isTrue();
assertThat(StatutAide.EN_COURS_TRAITEMENT.permetAnnulation()).isTrue();
assertThat(StatutAide.EN_COURS_VERSEMENT.permetAnnulation()).isTrue();
assertThat(StatutAide.SUSPENDUE.permetAnnulation()).isTrue();
assertThat(StatutAide.EN_SUIVI.permetAnnulation()).isTrue();
// Statuts finaux = ne permettent pas annulation
assertThat(StatutAide.APPROUVEE.permetAnnulation()).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.permetAnnulation()).isFalse();
assertThat(StatutAide.REJETEE.permetAnnulation()).isFalse();
assertThat(StatutAide.VERSEE.permetAnnulation()).isFalse();
assertThat(StatutAide.LIVREE.permetAnnulation()).isFalse();
assertThat(StatutAide.TERMINEE.permetAnnulation()).isFalse();
assertThat(StatutAide.EXPIREE.permetAnnulation()).isFalse();
assertThat(StatutAide.CLOTUREE.permetAnnulation()).isFalse();
// ANNULEE = ne permet pas annulation (déjà annulé)
assertThat(StatutAide.ANNULEE.permetAnnulation()).isFalse();
}
}
@Nested
@DisplayName("Tests des méthodes statiques")
class TestsMethodesStatiques {
@Test
@DisplayName("Test getStatutsFinaux")
void testGetStatutsFinaux() {
List<StatutAide> finaux = StatutAide.getStatutsFinaux();
// Vérifier que tous les statuts finaux sont inclus
assertThat(finaux).contains(
StatutAide.APPROUVEE,
StatutAide.APPROUVEE_PARTIELLEMENT,
StatutAide.REJETEE,
StatutAide.VERSEE,
StatutAide.LIVREE,
StatutAide.TERMINEE,
StatutAide.ANNULEE,
StatutAide.EXPIREE,
StatutAide.CLOTUREE);
// Vérifier qu'aucun statut non final n'est inclus
assertThat(finaux).doesNotContain(
StatutAide.BROUILLON,
StatutAide.SOUMISE,
StatutAide.EN_ATTENTE,
StatutAide.EN_COURS_EVALUATION,
StatutAide.INFORMATIONS_REQUISES,
StatutAide.EN_COURS_TRAITEMENT,
StatutAide.EN_COURS_VERSEMENT,
StatutAide.SUSPENDUE,
StatutAide.EN_SUIVI);
// Vérifier que tous les statuts retournés sont bien finaux
finaux.forEach(statut -> assertThat(statut.isEstFinal()).isTrue());
}
@Test
@DisplayName("Test getStatutsEchec")
void testGetStatutsEchec() {
List<StatutAide> echecs = StatutAide.getStatutsEchec();
// Vérifier que tous les statuts d'échec sont inclus
assertThat(echecs).contains(
StatutAide.REJETEE,
StatutAide.ANNULEE,
StatutAide.EXPIREE);
// Vérifier qu'aucun statut non échec n'est inclus
assertThat(echecs).doesNotContain(
StatutAide.BROUILLON,
StatutAide.SOUMISE,
StatutAide.EN_ATTENTE,
StatutAide.EN_COURS_EVALUATION,
StatutAide.INFORMATIONS_REQUISES,
StatutAide.APPROUVEE,
StatutAide.APPROUVEE_PARTIELLEMENT,
StatutAide.EN_COURS_TRAITEMENT,
StatutAide.EN_COURS_VERSEMENT,
StatutAide.VERSEE,
StatutAide.LIVREE,
StatutAide.TERMINEE,
StatutAide.SUSPENDUE,
StatutAide.EN_SUIVI,
StatutAide.CLOTUREE);
// Vérifier que tous les statuts retournés sont bien des échecs
echecs.forEach(statut -> assertThat(statut.isEstEchec()).isTrue());
}
@Test
@DisplayName("Test getStatutsSucces")
void testGetStatutsSucces() {
List<StatutAide> succes = StatutAide.getStatutsSucces();
// Vérifier que tous les statuts de succès sont inclus
assertThat(succes).contains(
StatutAide.VERSEE,
StatutAide.LIVREE,
StatutAide.TERMINEE);
// Vérifier qu'aucun statut non succès n'est inclus
assertThat(succes).doesNotContain(
StatutAide.BROUILLON,
StatutAide.SOUMISE,
StatutAide.EN_ATTENTE,
StatutAide.EN_COURS_EVALUATION,
StatutAide.INFORMATIONS_REQUISES,
StatutAide.APPROUVEE,
StatutAide.APPROUVEE_PARTIELLEMENT,
StatutAide.REJETEE,
StatutAide.EN_COURS_TRAITEMENT,
StatutAide.EN_COURS_VERSEMENT,
StatutAide.ANNULEE,
StatutAide.SUSPENDUE,
StatutAide.EXPIREE,
StatutAide.EN_SUIVI,
StatutAide.CLOTUREE);
// Vérifier que tous les statuts retournés sont bien des succès
succes.forEach(statut -> assertThat(statut.isSucces()).isTrue());
}
@Test
@DisplayName("Test getStatutsEnCours")
void testGetStatutsEnCours() {
List<StatutAide> enCours = StatutAide.getStatutsEnCours();
// Vérifier que tous les statuts en cours sont inclus
assertThat(enCours).contains(
StatutAide.EN_COURS_EVALUATION,
StatutAide.EN_COURS_TRAITEMENT,
StatutAide.EN_COURS_VERSEMENT);
// Vérifier qu'aucun statut non en cours n'est inclus
assertThat(enCours).doesNotContain(
StatutAide.BROUILLON,
StatutAide.SOUMISE,
StatutAide.EN_ATTENTE,
StatutAide.INFORMATIONS_REQUISES,
StatutAide.APPROUVEE,
StatutAide.APPROUVEE_PARTIELLEMENT,
StatutAide.REJETEE,
StatutAide.VERSEE,
StatutAide.LIVREE,
StatutAide.TERMINEE,
StatutAide.ANNULEE,
StatutAide.SUSPENDUE,
StatutAide.EXPIREE,
StatutAide.EN_SUIVI,
StatutAide.CLOTUREE);
// Vérifier que tous les statuts retournés sont bien en cours
enCours.forEach(statut -> assertThat(statut.isEnCours()).isTrue());
}
}
@Nested
@DisplayName("Tests des méthodes complexes")
class TestsMethodesComplexes {
@Test
@DisplayName("Test peutTransitionnerVers - toutes les branches du switch")
void testPeutTransitionnerVers() {
// Règles générales
// this == nouveauStatut -> false
assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.BROUILLON)).isFalse();
assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
// estFinal && nouveauStatut != EN_SUIVI -> false
assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.BROUILLON)).isFalse();
assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
assertThat(StatutAide.REJETEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
// estFinal && nouveauStatut == EN_SUIVI -> mais default false dans switch
// Les statuts finaux ne sont pas dans le switch, donc default -> false
assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
assertThat(StatutAide.REJETEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
// BROUILLON -> SOUMISE || ANNULEE
assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.SOUMISE)).isTrue();
assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
// SOUMISE -> EN_ATTENTE || ANNULEE
assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isTrue();
assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.BROUILLON)).isFalse();
assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
// EN_ATTENTE -> EN_COURS_EVALUATION || ANNULEE
assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION)).isTrue();
assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.SOUMISE)).isFalse();
assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
// EN_COURS_EVALUATION -> APPROUVEE || APPROUVEE_PARTIELLEMENT || REJETEE || INFORMATIONS_REQUISES || SUSPENDUE
assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.APPROUVEE)).isTrue();
assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.APPROUVEE_PARTIELLEMENT)).isTrue();
assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.REJETEE)).isTrue();
assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.INFORMATIONS_REQUISES)).isTrue();
assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.SUSPENDUE)).isTrue();
assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
// INFORMATIONS_REQUISES -> EN_COURS_EVALUATION || ANNULEE
assertThat(StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION)).isTrue();
assertThat(StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
assertThat(StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
assertThat(StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.BROUILLON)).isFalse();
// APPROUVEE, APPROUVEE_PARTIELLEMENT sont estFinal=true, donc condition estFinal bloque
// Même si le switch permet ces transitions, la condition estFinal prend le dessus
assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isFalse();
assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.SUSPENDUE)).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.SUSPENDUE)).isFalse();
assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.REJETEE)).isFalse();
// EN_COURS_TRAITEMENT -> EN_COURS_VERSEMENT || LIVREE || TERMINEE || SUSPENDUE
assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.EN_COURS_VERSEMENT)).isTrue();
assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.LIVREE)).isTrue();
assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.TERMINEE)).isTrue();
assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.SUSPENDUE)).isTrue();
assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.REJETEE)).isFalse();
// EN_COURS_VERSEMENT -> VERSEE || SUSPENDUE
assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.VERSEE)).isTrue();
assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.SUSPENDUE)).isTrue();
assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.LIVREE)).isFalse();
// SUSPENDUE -> EN_COURS_EVALUATION || ANNULEE
assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION)).isTrue();
assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
// default -> false (pour les statuts non couverts par le switch)
// EN_SUIVI n'est pas dans le switch, donc default -> false
assertThat(StatutAide.EN_SUIVI.peutTransitionnerVers(StatutAide.CLOTUREE)).isFalse();
assertThat(StatutAide.EN_SUIVI.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
// Autres statuts finaux (déjà testés avec règle estFinal)
assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse(); // Statut final, sauf EN_SUIVI
assertThat(StatutAide.LIVREE.peutTransitionnerVers(StatutAide.VERSEE)).isFalse(); // Statut final, sauf EN_SUIVI
}
@Test
@DisplayName("Test getNiveauPriorite - toutes les branches du switch")
void testGetNiveauPriorite() {
// INFORMATIONS_REQUISES -> 1
assertThat(StatutAide.INFORMATIONS_REQUISES.getNiveauPriorite()).isEqualTo(1);
// EN_COURS_EVALUATION, EN_COURS_TRAITEMENT, EN_COURS_VERSEMENT -> 2
assertThat(StatutAide.EN_COURS_EVALUATION.getNiveauPriorite()).isEqualTo(2);
assertThat(StatutAide.EN_COURS_TRAITEMENT.getNiveauPriorite()).isEqualTo(2);
assertThat(StatutAide.EN_COURS_VERSEMENT.getNiveauPriorite()).isEqualTo(2);
// APPROUVEE, APPROUVEE_PARTIELLEMENT -> 3
assertThat(StatutAide.APPROUVEE.getNiveauPriorite()).isEqualTo(3);
assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.getNiveauPriorite()).isEqualTo(3);
// EN_ATTENTE, SOUMISE -> 4
assertThat(StatutAide.EN_ATTENTE.getNiveauPriorite()).isEqualTo(4);
assertThat(StatutAide.SOUMISE.getNiveauPriorite()).isEqualTo(4);
// SUSPENDUE -> 5
assertThat(StatutAide.SUSPENDUE.getNiveauPriorite()).isEqualTo(5);
// BROUILLON -> 6
assertThat(StatutAide.BROUILLON.getNiveauPriorite()).isEqualTo(6);
// EN_SUIVI -> 7
assertThat(StatutAide.EN_SUIVI.getNiveauPriorite()).isEqualTo(7);
// default -> 8 (Statuts finaux)
assertThat(StatutAide.REJETEE.getNiveauPriorite()).isEqualTo(8);
assertThat(StatutAide.VERSEE.getNiveauPriorite()).isEqualTo(8);
assertThat(StatutAide.LIVREE.getNiveauPriorite()).isEqualTo(8);
assertThat(StatutAide.TERMINEE.getNiveauPriorite()).isEqualTo(8);
assertThat(StatutAide.ANNULEE.getNiveauPriorite()).isEqualTo(8);
assertThat(StatutAide.EXPIREE.getNiveauPriorite()).isEqualTo(8);
assertThat(StatutAide.CLOTUREE.getNiveauPriorite()).isEqualTo(8);
}
}
@Test
@DisplayName("Test cohérence globale des données")
void testCoherenceGlobale() {
for (StatutAide statut : StatutAide.values()) {
// Tous les champs obligatoires non null
assertThat(statut.getLibelle()).isNotNull().isNotEmpty();
assertThat(statut.getCode()).isNotNull().isNotEmpty();
assertThat(statut.getDescription()).isNotNull().isNotEmpty();
assertThat(statut.getCouleur()).isNotNull().matches("#[0-9A-Fa-f]{6}");
assertThat(statut.getIcone()).isNotNull().isNotEmpty();
// Cohérence logique
if (statut.isEstFinal()) {
// Les statuts finaux ne permettent pas la modification
assertThat(statut.permetModification()).isFalse();
// Les statuts finaux ne permettent pas l'annulation (sauf transition vers EN_SUIVI)
assertThat(statut.permetAnnulation()).isFalse();
}
if (statut.isEstEchec()) {
// Les statuts d'échec ne sont pas des succès
assertThat(statut.isSucces()).isFalse();
// Les statuts d'échec sont finaux
assertThat(statut.isEstFinal()).isTrue();
}
if (statut.isSucces()) {
// Les statuts de succès ne sont pas des échecs
assertThat(statut.isEstEchec()).isFalse();
// Les statuts de succès sont finaux
assertThat(statut.isEstFinal()).isTrue();
}
if (statut.isEnCours()) {
// Les statuts en cours ne sont pas finaux
assertThat(statut.isEstFinal()).isFalse();
// Les statuts en cours ne sont ni succès ni échec
assertThat(statut.isSucces()).isFalse();
assertThat(statut.isEstEchec()).isFalse();
}
// Niveau de priorité cohérent
int niveau = statut.getNiveauPriorite();
assertThat(niveau).isBetween(1, 8);
// Transitions cohérentes
assertThat(statut.peutTransitionnerVers(statut)).isFalse(); // Pas de transition vers soi-même
}
}
}

View File

@@ -0,0 +1,554 @@
package dev.lions.unionflow.server.api.enums.solidarite;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.within;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires EXHAUSTIFS pour TypeAide - Couverture 100%
*
* @author UnionFlow Team
* @version 1.0
* @since 2025-01-16
*/
@DisplayName("Tests EXHAUSTIFS TypeAide")
class TypeAideTest {
@Nested
@DisplayName("Tests des valeurs enum et constructeur")
class TestsValeursEnum {
@Test
@DisplayName("Test valueOf et values")
void testValueOfEtValues() {
TypeAide[] values = TypeAide.values();
assertThat(values).hasSize(24);
assertThat(values).containsExactly(
TypeAide.AIDE_FINANCIERE_URGENTE,
TypeAide.PRET_SANS_INTERET,
TypeAide.AIDE_COTISATION,
TypeAide.AIDE_FRAIS_MEDICAUX,
TypeAide.AIDE_FRAIS_SCOLARITE,
TypeAide.DON_MATERIEL,
TypeAide.PRET_MATERIEL,
TypeAide.AIDE_DEMENAGEMENT,
TypeAide.AIDE_TRAVAUX,
TypeAide.AIDE_RECHERCHE_EMPLOI,
TypeAide.FORMATION_PROFESSIONNELLE,
TypeAide.CONSEIL_JURIDIQUE,
TypeAide.AIDE_CREATION_ENTREPRISE,
TypeAide.GARDE_ENFANTS,
TypeAide.AIDE_PERSONNES_AGEES,
TypeAide.TRANSPORT,
TypeAide.AIDE_ADMINISTRATIVE,
TypeAide.HEBERGEMENT_URGENCE,
TypeAide.AIDE_ALIMENTAIRE,
TypeAide.AIDE_VESTIMENTAIRE,
TypeAide.SOUTIEN_PSYCHOLOGIQUE,
TypeAide.AIDE_NUMERIQUE,
TypeAide.TRADUCTION,
TypeAide.AUTRE);
// Test valueOf pour quelques valeurs
assertThat(TypeAide.valueOf("AIDE_FINANCIERE_URGENTE")).isEqualTo(TypeAide.AIDE_FINANCIERE_URGENTE);
assertThat(TypeAide.valueOf("HEBERGEMENT_URGENCE")).isEqualTo(TypeAide.HEBERGEMENT_URGENCE);
assertThat(TypeAide.valueOf("SOUTIEN_PSYCHOLOGIQUE")).isEqualTo(TypeAide.SOUTIEN_PSYCHOLOGIQUE);
assertThatThrownBy(() -> TypeAide.valueOf("INEXISTANT"))
.isInstanceOf(IllegalArgumentException.class);
}
@Test
@DisplayName("Test ordinal, name et toString")
void testOrdinalNameToString() {
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.ordinal()).isEqualTo(0);
assertThat(TypeAide.PRET_SANS_INTERET.ordinal()).isEqualTo(1);
assertThat(TypeAide.AUTRE.ordinal()).isEqualTo(23);
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.name()).isEqualTo("AIDE_FINANCIERE_URGENTE");
assertThat(TypeAide.HEBERGEMENT_URGENCE.name()).isEqualTo("HEBERGEMENT_URGENCE");
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.toString()).isEqualTo("AIDE_FINANCIERE_URGENTE");
assertThat(TypeAide.SOUTIEN_PSYCHOLOGIQUE.toString()).isEqualTo("SOUTIEN_PSYCHOLOGIQUE");
}
@Test
@DisplayName("Test propriétés AIDE_FINANCIERE_URGENTE")
void testProprietesAideFinanciereUrgente() {
TypeAide type = TypeAide.AIDE_FINANCIERE_URGENTE;
assertThat(type.getLibelle()).isEqualTo("Aide financière urgente");
assertThat(type.getCategorie()).isEqualTo("financiere");
assertThat(type.getPriorite()).isEqualTo("urgent");
assertThat(type.getDescription()).isEqualTo("Aide financière pour situation d'urgence");
assertThat(type.getIcone()).isEqualTo("emergency_fund");
assertThat(type.getCouleur()).isEqualTo("#F44336");
assertThat(type.isNecessiteMontant()).isTrue();
assertThat(type.isNecessiteValidation()).isTrue();
assertThat(type.getMontantMin()).isEqualTo(5000.0);
assertThat(type.getMontantMax()).isEqualTo(50000.0);
assertThat(type.getDelaiReponseJours()).isEqualTo(7);
}
@Test
@DisplayName("Test propriétés PRET_SANS_INTERET")
void testProprietesPreSansInteret() {
TypeAide type = TypeAide.PRET_SANS_INTERET;
assertThat(type.getLibelle()).isEqualTo("Prêt sans intérêt");
assertThat(type.getCategorie()).isEqualTo("financiere");
assertThat(type.getPriorite()).isEqualTo("important");
assertThat(type.getDescription()).isEqualTo("Prêt sans intérêt entre membres");
assertThat(type.getIcone()).isEqualTo("account_balance");
assertThat(type.getCouleur()).isEqualTo("#FF9800");
assertThat(type.isNecessiteMontant()).isTrue();
assertThat(type.isNecessiteValidation()).isTrue();
assertThat(type.getMontantMin()).isEqualTo(10000.0);
assertThat(type.getMontantMax()).isEqualTo(100000.0);
assertThat(type.getDelaiReponseJours()).isEqualTo(30);
}
@Test
@DisplayName("Test propriétés DON_MATERIEL")
void testProprietesDoMateriel() {
TypeAide type = TypeAide.DON_MATERIEL;
assertThat(type.getLibelle()).isEqualTo("Don de matériel");
assertThat(type.getCategorie()).isEqualTo("materielle");
assertThat(type.getPriorite()).isEqualTo("normal");
assertThat(type.getDescription()).isEqualTo("Don d'objets, équipements ou matériel");
assertThat(type.getIcone()).isEqualTo("inventory");
assertThat(type.getCouleur()).isEqualTo("#4CAF50");
assertThat(type.isNecessiteMontant()).isFalse();
assertThat(type.isNecessiteValidation()).isFalse();
assertThat(type.getMontantMin()).isNull();
assertThat(type.getMontantMax()).isNull();
assertThat(type.getDelaiReponseJours()).isEqualTo(14);
}
@Test
@DisplayName("Test propriétés HEBERGEMENT_URGENCE")
void testProprietesHebergementUrgence() {
TypeAide type = TypeAide.HEBERGEMENT_URGENCE;
assertThat(type.getLibelle()).isEqualTo("Hébergement d'urgence");
assertThat(type.getCategorie()).isEqualTo("urgence");
assertThat(type.getPriorite()).isEqualTo("urgent");
assertThat(type.getDescription()).isEqualTo("Hébergement temporaire d'urgence");
assertThat(type.getIcone()).isEqualTo("home");
assertThat(type.getCouleur()).isEqualTo("#F44336");
assertThat(type.isNecessiteMontant()).isFalse();
assertThat(type.isNecessiteValidation()).isTrue();
assertThat(type.getMontantMin()).isNull();
assertThat(type.getMontantMax()).isNull();
assertThat(type.getDelaiReponseJours()).isEqualTo(7);
}
@Test
@DisplayName("Test propriétés AIDE_ALIMENTAIRE")
void testProprietesAideAlimentaire() {
TypeAide type = TypeAide.AIDE_ALIMENTAIRE;
assertThat(type.getLibelle()).isEqualTo("Aide alimentaire");
assertThat(type.getCategorie()).isEqualTo("urgence");
assertThat(type.getPriorite()).isEqualTo("urgent");
assertThat(type.getDescription()).isEqualTo("Aide alimentaire d'urgence");
assertThat(type.getIcone()).isEqualTo("restaurant");
assertThat(type.getCouleur()).isEqualTo("#FF5722");
assertThat(type.isNecessiteMontant()).isFalse();
assertThat(type.isNecessiteValidation()).isTrue();
assertThat(type.getMontantMin()).isNull();
assertThat(type.getMontantMax()).isNull();
assertThat(type.getDelaiReponseJours()).isEqualTo(3);
}
@Test
@DisplayName("Test propriétés SOUTIEN_PSYCHOLOGIQUE")
void testProprieteSoutienPsychologique() {
TypeAide type = TypeAide.SOUTIEN_PSYCHOLOGIQUE;
assertThat(type.getLibelle()).isEqualTo("Soutien psychologique");
assertThat(type.getCategorie()).isEqualTo("specialisee");
assertThat(type.getPriorite()).isEqualTo("important");
assertThat(type.getDescription()).isEqualTo("Soutien et écoute psychologique");
assertThat(type.getIcone()).isEqualTo("psychology");
assertThat(type.getCouleur()).isEqualTo("#E91E63");
assertThat(type.isNecessiteMontant()).isFalse();
assertThat(type.isNecessiteValidation()).isTrue();
assertThat(type.getMontantMin()).isNull();
assertThat(type.getMontantMax()).isNull();
assertThat(type.getDelaiReponseJours()).isEqualTo(30);
}
@Test
@DisplayName("Test propriétés AUTRE")
void testProprietesAutre() {
TypeAide type = TypeAide.AUTRE;
assertThat(type.getLibelle()).isEqualTo("Autre");
assertThat(type.getCategorie()).isEqualTo("autre");
assertThat(type.getPriorite()).isEqualTo("normal");
assertThat(type.getDescription()).isEqualTo("Autre type d'aide non catégorisé");
assertThat(type.getIcone()).isEqualTo("help");
assertThat(type.getCouleur()).isEqualTo("#9E9E9E");
assertThat(type.isNecessiteMontant()).isFalse();
assertThat(type.isNecessiteValidation()).isFalse();
assertThat(type.getMontantMin()).isNull();
assertThat(type.getMontantMax()).isNull();
assertThat(type.getDelaiReponseJours()).isEqualTo(14);
}
}
@Nested
@DisplayName("Tests des méthodes métier")
class TestsMethodesMetier {
@Test
@DisplayName("Test isUrgent - toutes les branches")
void testIsUrgent() {
// Types urgents (priorite == "urgent")
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isUrgent()).isTrue();
assertThat(TypeAide.AIDE_FRAIS_MEDICAUX.isUrgent()).isTrue();
assertThat(TypeAide.HEBERGEMENT_URGENCE.isUrgent()).isTrue();
assertThat(TypeAide.AIDE_ALIMENTAIRE.isUrgent()).isTrue();
// Types non urgents
assertThat(TypeAide.PRET_SANS_INTERET.isUrgent()).isFalse(); // "important"
assertThat(TypeAide.DON_MATERIEL.isUrgent()).isFalse(); // "normal"
assertThat(TypeAide.AIDE_RECHERCHE_EMPLOI.isUrgent()).isFalse(); // "important"
assertThat(TypeAide.FORMATION_PROFESSIONNELLE.isUrgent()).isFalse(); // "normal"
assertThat(TypeAide.AUTRE.isUrgent()).isFalse(); // "normal"
}
@Test
@DisplayName("Test isFinancier - toutes les branches")
void testIsFinancier() {
// Types financiers (categorie == "financiere")
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isFinancier()).isTrue();
assertThat(TypeAide.PRET_SANS_INTERET.isFinancier()).isTrue();
assertThat(TypeAide.AIDE_COTISATION.isFinancier()).isTrue();
assertThat(TypeAide.AIDE_FRAIS_MEDICAUX.isFinancier()).isTrue();
assertThat(TypeAide.AIDE_FRAIS_SCOLARITE.isFinancier()).isTrue();
// Types non financiers
assertThat(TypeAide.DON_MATERIEL.isFinancier()).isFalse(); // "materielle"
assertThat(TypeAide.AIDE_RECHERCHE_EMPLOI.isFinancier()).isFalse(); // "professionnelle"
assertThat(TypeAide.GARDE_ENFANTS.isFinancier()).isFalse(); // "sociale"
assertThat(TypeAide.HEBERGEMENT_URGENCE.isFinancier()).isFalse(); // "urgence"
assertThat(TypeAide.SOUTIEN_PSYCHOLOGIQUE.isFinancier()).isFalse(); // "specialisee"
assertThat(TypeAide.AUTRE.isFinancier()).isFalse(); // "autre"
}
@Test
@DisplayName("Test isMateriel - toutes les branches")
void testIsMateriel() {
// Types matériels (categorie == "materielle")
assertThat(TypeAide.DON_MATERIEL.isMateriel()).isTrue();
assertThat(TypeAide.PRET_MATERIEL.isMateriel()).isTrue();
assertThat(TypeAide.AIDE_DEMENAGEMENT.isMateriel()).isTrue();
assertThat(TypeAide.AIDE_TRAVAUX.isMateriel()).isTrue();
// Types non matériels
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isMateriel()).isFalse(); // "financiere"
assertThat(TypeAide.AIDE_RECHERCHE_EMPLOI.isMateriel()).isFalse(); // "professionnelle"
assertThat(TypeAide.GARDE_ENFANTS.isMateriel()).isFalse(); // "sociale"
assertThat(TypeAide.HEBERGEMENT_URGENCE.isMateriel()).isFalse(); // "urgence"
assertThat(TypeAide.SOUTIEN_PSYCHOLOGIQUE.isMateriel()).isFalse(); // "specialisee"
assertThat(TypeAide.AUTRE.isMateriel()).isFalse(); // "autre"
}
@Test
@DisplayName("Test isMontantValide - toutes les branches")
void testIsMontantValide() {
// Type qui ne nécessite pas de montant -> toujours valide
assertThat(TypeAide.DON_MATERIEL.isMontantValide(null)).isTrue();
assertThat(TypeAide.DON_MATERIEL.isMontantValide(1000.0)).isTrue();
assertThat(TypeAide.DON_MATERIEL.isMontantValide(-1000.0)).isTrue();
// Type qui nécessite un montant mais montant null -> valide
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isMontantValide(null)).isTrue();
// Type avec montant min/max : AIDE_FINANCIERE_URGENTE (5000-50000)
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isMontantValide(4999.0)).isFalse(); // < min
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isMontantValide(5000.0)).isTrue(); // = min
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isMontantValide(25000.0)).isTrue(); // dans la fourchette
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isMontantValide(50000.0)).isTrue(); // = max
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.isMontantValide(50001.0)).isFalse(); // > max
// Type avec montant min/max : PRET_SANS_INTERET (10000-100000)
assertThat(TypeAide.PRET_SANS_INTERET.isMontantValide(9999.0)).isFalse(); // < min
assertThat(TypeAide.PRET_SANS_INTERET.isMontantValide(10000.0)).isTrue(); // = min
assertThat(TypeAide.PRET_SANS_INTERET.isMontantValide(50000.0)).isTrue(); // dans la fourchette
assertThat(TypeAide.PRET_SANS_INTERET.isMontantValide(100000.0)).isTrue(); // = max
assertThat(TypeAide.PRET_SANS_INTERET.isMontantValide(100001.0)).isFalse(); // > max
}
@Test
@DisplayName("Test getNiveauPriorite - toutes les branches du switch")
void testGetNiveauPriorite() {
// "urgent" -> 1
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getNiveauPriorite()).isEqualTo(1);
assertThat(TypeAide.AIDE_FRAIS_MEDICAUX.getNiveauPriorite()).isEqualTo(1);
assertThat(TypeAide.HEBERGEMENT_URGENCE.getNiveauPriorite()).isEqualTo(1);
assertThat(TypeAide.AIDE_ALIMENTAIRE.getNiveauPriorite()).isEqualTo(1);
// "important" -> 2
assertThat(TypeAide.PRET_SANS_INTERET.getNiveauPriorite()).isEqualTo(2);
assertThat(TypeAide.AIDE_FRAIS_SCOLARITE.getNiveauPriorite()).isEqualTo(2);
assertThat(TypeAide.AIDE_RECHERCHE_EMPLOI.getNiveauPriorite()).isEqualTo(2);
assertThat(TypeAide.CONSEIL_JURIDIQUE.getNiveauPriorite()).isEqualTo(2);
assertThat(TypeAide.AIDE_PERSONNES_AGEES.getNiveauPriorite()).isEqualTo(2);
assertThat(TypeAide.SOUTIEN_PSYCHOLOGIQUE.getNiveauPriorite()).isEqualTo(2);
// "normal" -> 3
assertThat(TypeAide.AIDE_COTISATION.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.DON_MATERIEL.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.FORMATION_PROFESSIONNELLE.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.GARDE_ENFANTS.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.TRANSPORT.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.AIDE_ADMINISTRATIVE.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.AIDE_VESTIMENTAIRE.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.AIDE_NUMERIQUE.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.TRADUCTION.getNiveauPriorite()).isEqualTo(3);
assertThat(TypeAide.AUTRE.getNiveauPriorite()).isEqualTo(3);
// default -> 3 (pour toute autre valeur)
// Pas de test direct possible car toutes les valeurs sont couvertes
}
@Test
@DisplayName("Test getDateLimiteReponse")
void testGetDateLimiteReponse() {
LocalDateTime avant = LocalDateTime.now();
// AIDE_FINANCIERE_URGENTE : 7 jours
LocalDateTime dateLimite = TypeAide.AIDE_FINANCIERE_URGENTE.getDateLimiteReponse();
LocalDateTime attendu = avant.plusDays(7);
assertThat(dateLimite).isCloseTo(attendu, within(1, ChronoUnit.SECONDS));
// AIDE_ALIMENTAIRE : 3 jours
dateLimite = TypeAide.AIDE_ALIMENTAIRE.getDateLimiteReponse();
attendu = LocalDateTime.now().plusDays(3);
assertThat(dateLimite).isCloseTo(attendu, within(1, ChronoUnit.SECONDS));
// FORMATION_PROFESSIONNELLE : 60 jours
dateLimite = TypeAide.FORMATION_PROFESSIONNELLE.getDateLimiteReponse();
attendu = LocalDateTime.now().plusDays(60);
assertThat(dateLimite).isCloseTo(attendu, within(1, ChronoUnit.SECONDS));
}
}
@Nested
@DisplayName("Tests des méthodes statiques")
class TestsMethodesStatiques {
@Test
@DisplayName("Test getParCategorie")
void testGetParCategorie() {
// Catégorie "financiere"
List<TypeAide> financiers = TypeAide.getParCategorie("financiere");
assertThat(financiers).contains(
TypeAide.AIDE_FINANCIERE_URGENTE,
TypeAide.PRET_SANS_INTERET,
TypeAide.AIDE_COTISATION,
TypeAide.AIDE_FRAIS_MEDICAUX,
TypeAide.AIDE_FRAIS_SCOLARITE);
assertThat(financiers).doesNotContain(TypeAide.DON_MATERIEL, TypeAide.GARDE_ENFANTS);
// Catégorie "materielle"
List<TypeAide> materiels = TypeAide.getParCategorie("materielle");
assertThat(materiels).contains(
TypeAide.DON_MATERIEL,
TypeAide.PRET_MATERIEL,
TypeAide.AIDE_DEMENAGEMENT,
TypeAide.AIDE_TRAVAUX);
assertThat(materiels).doesNotContain(TypeAide.AIDE_FINANCIERE_URGENTE, TypeAide.GARDE_ENFANTS);
// Catégorie "urgence"
List<TypeAide> urgences = TypeAide.getParCategorie("urgence");
assertThat(urgences).contains(
TypeAide.HEBERGEMENT_URGENCE,
TypeAide.AIDE_ALIMENTAIRE,
TypeAide.AIDE_VESTIMENTAIRE);
assertThat(urgences).doesNotContain(TypeAide.AIDE_FINANCIERE_URGENTE, TypeAide.DON_MATERIEL);
// Catégorie inexistante
List<TypeAide> inexistante = TypeAide.getParCategorie("inexistante");
assertThat(inexistante).isEmpty();
}
@Test
@DisplayName("Test getUrgents")
void testGetUrgents() {
List<TypeAide> urgents = TypeAide.getUrgents();
// Vérifier que tous les types urgents sont inclus
assertThat(urgents).contains(
TypeAide.AIDE_FINANCIERE_URGENTE,
TypeAide.AIDE_FRAIS_MEDICAUX,
TypeAide.HEBERGEMENT_URGENCE,
TypeAide.AIDE_ALIMENTAIRE);
// Vérifier qu'aucun type non urgent n'est inclus
assertThat(urgents).doesNotContain(
TypeAide.PRET_SANS_INTERET, // "important"
TypeAide.DON_MATERIEL, // "normal"
TypeAide.AIDE_RECHERCHE_EMPLOI, // "important"
TypeAide.FORMATION_PROFESSIONNELLE); // "normal"
// Vérifier que tous les types retournés sont bien urgents
urgents.forEach(type -> assertThat(type.isUrgent()).isTrue());
}
@Test
@DisplayName("Test getFinanciers")
void testGetFinanciers() {
List<TypeAide> financiers = TypeAide.getFinanciers();
// Vérifier que tous les types financiers sont inclus
assertThat(financiers).contains(
TypeAide.AIDE_FINANCIERE_URGENTE,
TypeAide.PRET_SANS_INTERET,
TypeAide.AIDE_COTISATION,
TypeAide.AIDE_FRAIS_MEDICAUX,
TypeAide.AIDE_FRAIS_SCOLARITE);
// Vérifier qu'aucun type non financier n'est inclus
assertThat(financiers).doesNotContain(
TypeAide.DON_MATERIEL, // "materielle"
TypeAide.AIDE_RECHERCHE_EMPLOI, // "professionnelle"
TypeAide.GARDE_ENFANTS, // "sociale"
TypeAide.HEBERGEMENT_URGENCE); // "urgence"
// Vérifier que tous les types retournés sont bien financiers
financiers.forEach(type -> assertThat(type.isFinancier()).isTrue());
}
@Test
@DisplayName("Test getCategories")
void testGetCategories() {
Set<String> categories = TypeAide.getCategories();
// Vérifier que toutes les catégories sont présentes
assertThat(categories).contains(
"financiere",
"materielle",
"professionnelle",
"sociale",
"urgence",
"specialisee",
"autre");
// Vérifier qu'il n'y a pas de doublons (Set)
assertThat(categories).hasSize(7);
}
}
@Nested
@DisplayName("Tests des méthodes complexes")
class TestsMethodesComplexes {
@Test
@DisplayName("Test getLibelleCategorie - toutes les branches du switch")
void testGetLibelleCategorie() {
// Toutes les branches du switch
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getLibelleCategorie()).isEqualTo("Aide financière");
assertThat(TypeAide.DON_MATERIEL.getLibelleCategorie()).isEqualTo("Aide matérielle");
assertThat(TypeAide.AIDE_RECHERCHE_EMPLOI.getLibelleCategorie()).isEqualTo("Aide professionnelle");
assertThat(TypeAide.GARDE_ENFANTS.getLibelleCategorie()).isEqualTo("Aide sociale");
assertThat(TypeAide.HEBERGEMENT_URGENCE.getLibelleCategorie()).isEqualTo("Aide d'urgence");
assertThat(TypeAide.SOUTIEN_PSYCHOLOGIQUE.getLibelleCategorie()).isEqualTo("Aide spécialisée");
assertThat(TypeAide.AUTRE.getLibelleCategorie()).isEqualTo("Autre");
// default -> retourne la catégorie telle quelle
// Pas de test direct possible car toutes les catégories sont couvertes
}
@Test
@DisplayName("Test getUniteMontant - toutes les branches")
void testGetUniteMontant() {
// Types qui nécessitent un montant -> "FCFA"
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getUniteMontant()).isEqualTo("FCFA");
assertThat(TypeAide.PRET_SANS_INTERET.getUniteMontant()).isEqualTo("FCFA");
assertThat(TypeAide.AIDE_COTISATION.getUniteMontant()).isEqualTo("FCFA");
// Types qui ne nécessitent pas de montant -> null
assertThat(TypeAide.DON_MATERIEL.getUniteMontant()).isNull();
assertThat(TypeAide.HEBERGEMENT_URGENCE.getUniteMontant()).isNull();
assertThat(TypeAide.GARDE_ENFANTS.getUniteMontant()).isNull();
}
@Test
@DisplayName("Test getMessageValidationMontant - toutes les branches")
void testGetMessageValidationMontant() {
// Type qui ne nécessite pas de montant -> null
assertThat(TypeAide.DON_MATERIEL.getMessageValidationMontant(1000.0)).isNull();
assertThat(TypeAide.DON_MATERIEL.getMessageValidationMontant(null)).isNull();
// Type qui nécessite un montant mais montant null -> message obligatoire
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getMessageValidationMontant(null))
.isEqualTo("Le montant est obligatoire");
// Montant < min -> message minimum
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getMessageValidationMontant(4999.0))
.isEqualTo("Le montant minimum est de 5000 FCFA");
// Montant > max -> message maximum
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getMessageValidationMontant(50001.0))
.isEqualTo("Le montant maximum est de 50000 FCFA");
// Montant valide -> null
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getMessageValidationMontant(25000.0)).isNull();
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getMessageValidationMontant(5000.0)).isNull();
assertThat(TypeAide.AIDE_FINANCIERE_URGENTE.getMessageValidationMontant(50000.0)).isNull();
}
}
@Test
@DisplayName("Test cohérence globale des données")
void testCoherenceGlobale() {
for (TypeAide type : TypeAide.values()) {
// Tous les champs obligatoires non null
assertThat(type.getLibelle()).isNotNull().isNotEmpty();
assertThat(type.getCategorie()).isNotNull().isNotEmpty();
assertThat(type.getPriorite()).isNotNull().isNotEmpty();
assertThat(type.getDescription()).isNotNull().isNotEmpty();
assertThat(type.getIcone()).isNotNull().isNotEmpty();
assertThat(type.getCouleur()).isNotNull().matches("#[0-9A-Fa-f]{6}");
assertThat(type.getDelaiReponseJours()).isPositive();
// Cohérence logique
if (type.isNecessiteMontant()) {
assertThat(type.getUniteMontant()).isEqualTo("FCFA");
} else {
assertThat(type.getUniteMontant()).isNull();
assertThat(type.getMontantMin()).isNull();
assertThat(type.getMontantMax()).isNull();
}
if (type.getMontantMin() != null && type.getMontantMax() != null) {
assertThat(type.getMontantMax()).isGreaterThanOrEqualTo(type.getMontantMin());
}
// Priorité cohérente
assertThat(type.getPriorite()).isIn("urgent", "important", "normal");
assertThat(type.getNiveauPriorite()).isBetween(1, 3);
// Catégorie cohérente
assertThat(type.getCategorie()).isIn("financiere", "materielle", "professionnelle",
"sociale", "urgence", "specialisee", "autre");
assertThat(type.getLibelleCategorie()).isNotNull().isNotEmpty();
// Méthodes temporelles fonctionnent
assertThat(type.getDateLimiteReponse()).isAfter(LocalDateTime.now());
// Validation de montant cohérente
if (type.isNecessiteMontant()) {
assertThat(type.getMessageValidationMontant(null)).isEqualTo("Le montant est obligatoire");
} else {
assertThat(type.getMessageValidationMontant(null)).isNull();
}
}
}
}

View File

@@ -0,0 +1,207 @@
package dev.lions.unionflow.server.api.validation;
import static org.assertj.core.api.Assertions.assertThat;
import java.lang.reflect.Constructor;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
/**
* Tests unitaires pour ValidationConstants - Couverture 100%
*
* @author UnionFlow Team
* @version 2.0
* @since 2025-01-16
*/
@DisplayName("Tests ValidationConstants")
class ValidationConstantsTest {
@Test
@DisplayName("Test constructeur privé")
void testConstructeurPrive() throws Exception {
Constructor<ValidationConstants> constructor = ValidationConstants.class.getDeclaredConstructor();
constructor.setAccessible(true);
// Le constructeur doit être accessible et créer une instance
ValidationConstants instance = constructor.newInstance();
assertThat(instance).isNotNull();
}
@Nested
@DisplayName("Tests des constantes de taille")
class TestsConstantesTaille {
@Test
@DisplayName("Test constantes titre")
void testConstantesTitre() {
assertThat(ValidationConstants.TITRE_MIN_LENGTH).isEqualTo(5);
assertThat(ValidationConstants.TITRE_MAX_LENGTH).isEqualTo(100);
assertThat(ValidationConstants.TITRE_SIZE_MESSAGE).contains("5").contains("100").contains("titre");
}
@Test
@DisplayName("Test constantes nom organisation")
void testConstantesNomOrganisation() {
assertThat(ValidationConstants.NOM_ORGANISATION_MIN_LENGTH).isEqualTo(2);
assertThat(ValidationConstants.NOM_ORGANISATION_MAX_LENGTH).isEqualTo(200);
assertThat(ValidationConstants.NOM_ORGANISATION_SIZE_MESSAGE)
.contains("2")
.contains("200")
.contains("nom");
}
@Test
@DisplayName("Test constantes description")
void testConstantesDescription() {
assertThat(ValidationConstants.DESCRIPTION_MIN_LENGTH).isEqualTo(20);
assertThat(ValidationConstants.DESCRIPTION_MAX_LENGTH).isEqualTo(2000);
assertThat(ValidationConstants.DESCRIPTION_SIZE_MESSAGE)
.contains("20")
.contains("2000")
.contains("description");
}
@Test
@DisplayName("Test constantes description courte")
void testConstantesDescriptionCourte() {
assertThat(ValidationConstants.DESCRIPTION_COURTE_MAX_LENGTH).isEqualTo(1000);
assertThat(ValidationConstants.DESCRIPTION_COURTE_SIZE_MESSAGE)
.contains("1000")
.contains("description");
}
@Test
@DisplayName("Test constantes justification")
void testConstantesJustification() {
assertThat(ValidationConstants.JUSTIFICATION_MAX_LENGTH).isEqualTo(1000);
assertThat(ValidationConstants.JUSTIFICATION_SIZE_MESSAGE)
.contains("1000")
.contains("justification");
}
@Test
@DisplayName("Test constantes commentaires")
void testConstantesCommentaires() {
assertThat(ValidationConstants.COMMENTAIRES_MAX_LENGTH).isEqualTo(1000);
assertThat(ValidationConstants.COMMENTAIRES_SIZE_MESSAGE)
.contains("1000")
.contains("commentaires");
}
@Test
@DisplayName("Test constantes raison rejet")
void testConstantesRaisonRejet() {
assertThat(ValidationConstants.RAISON_REJET_MAX_LENGTH).isEqualTo(500);
assertThat(ValidationConstants.RAISON_REJET_SIZE_MESSAGE).contains("500").contains("rejet");
}
@Test
@DisplayName("Test constantes email")
void testConstantesEmail() {
assertThat(ValidationConstants.EMAIL_MAX_LENGTH).isEqualTo(100);
assertThat(ValidationConstants.EMAIL_SIZE_MESSAGE).contains("100").contains("email");
}
@Test
@DisplayName("Test constantes nom et prénom")
void testConstantesNomPrenom() {
assertThat(ValidationConstants.NOM_PRENOM_MIN_LENGTH).isEqualTo(2);
assertThat(ValidationConstants.NOM_PRENOM_MAX_LENGTH).isEqualTo(50);
assertThat(ValidationConstants.NOM_SIZE_MESSAGE).contains("2").contains("50").contains("nom");
assertThat(ValidationConstants.PRENOM_SIZE_MESSAGE).contains("2").contains("50").contains("prénom");
}
}
@Nested
@DisplayName("Tests des patterns de validation")
class TestsPatternsValidation {
@Test
@DisplayName("Test patterns téléphone")
void testPatternsTelephone() {
assertThat(ValidationConstants.TELEPHONE_PATTERN).isNotNull();
assertThat(ValidationConstants.TELEPHONE_MESSAGE).contains("téléphone");
}
@Test
@DisplayName("Test patterns devise")
void testPatternsDevise() {
assertThat(ValidationConstants.DEVISE_PATTERN).isNotNull();
assertThat(ValidationConstants.DEVISE_MESSAGE).contains("devise");
}
@Test
@DisplayName("Test patterns référence aide")
void testPatternsReferenceAide() {
assertThat(ValidationConstants.REFERENCE_AIDE_PATTERN).isNotNull();
assertThat(ValidationConstants.REFERENCE_AIDE_MESSAGE).contains("référence");
}
@Test
@DisplayName("Test patterns numéro membre")
void testPatternsNumeroMembre() {
assertThat(ValidationConstants.NUMERO_MEMBRE_PATTERN).isNotNull();
assertThat(ValidationConstants.NUMERO_MEMBRE_MESSAGE).contains("numéro");
}
@Test
@DisplayName("Test patterns couleur hexadécimale")
void testPatternsCouleurHex() {
assertThat(ValidationConstants.COULEUR_HEX_PATTERN).isNotNull();
assertThat(ValidationConstants.COULEUR_HEX_MESSAGE).contains("couleur");
}
}
@Nested
@DisplayName("Tests des messages obligatoires")
class TestsMessagesObligatoires {
@Test
@DisplayName("Test message obligatoire")
void testMessageObligatoire() {
assertThat(ValidationConstants.OBLIGATOIRE_MESSAGE).contains("obligatoire");
}
@Test
@DisplayName("Test message email format")
void testMessageEmailFormat() {
assertThat(ValidationConstants.EMAIL_FORMAT_MESSAGE).contains("email");
}
@Test
@DisplayName("Test messages de date")
void testMessagesDate() {
assertThat(ValidationConstants.DATE_PASSEE_MESSAGE).contains("passé");
assertThat(ValidationConstants.DATE_FUTURE_MESSAGE).contains("futur");
}
}
@Nested
@DisplayName("Tests des constantes numériques")
class TestsConstantesNumeriques {
@Test
@DisplayName("Test constantes montant")
void testConstantesMontant() {
assertThat(ValidationConstants.MONTANT_MIN_VALUE).isEqualTo("0.0");
assertThat(ValidationConstants.MONTANT_INTEGER_DIGITS).isEqualTo(10);
assertThat(ValidationConstants.MONTANT_FRACTION_DIGITS).isEqualTo(2);
assertThat(ValidationConstants.MONTANT_DIGITS_MESSAGE).contains("10").contains("2");
assertThat(ValidationConstants.MONTANT_POSITIF_MESSAGE).contains("positif");
}
}
@Test
@DisplayName("Test toutes les constantes sont non nulles")
void testToutesConstantesNonNulles() {
// Vérification que toutes les constantes String sont non nulles
assertThat(ValidationConstants.TITRE_SIZE_MESSAGE).isNotNull();
assertThat(ValidationConstants.NOM_ORGANISATION_SIZE_MESSAGE).isNotNull();
assertThat(ValidationConstants.DESCRIPTION_SIZE_MESSAGE).isNotNull();
assertThat(ValidationConstants.TELEPHONE_PATTERN).isNotNull();
assertThat(ValidationConstants.DEVISE_PATTERN).isNotNull();
assertThat(ValidationConstants.OBLIGATOIRE_MESSAGE).isNotNull();
assertThat(ValidationConstants.EMAIL_FORMAT_MESSAGE).isNotNull();
}
}