org.apache.maven.plugins
maven-compiler-plugin
- 3.11.0
+ 3.13.0
- 17
- 17
+ 21
UTF-8
org.projectlombok
lombok
- 1.18.30
+ 1.18.36
diff --git a/script/publish-api.sh b/script/publish-api.sh
index 422c15a..a42ceb2 100644
--- a/script/publish-api.sh
+++ b/script/publish-api.sh
@@ -16,7 +16,7 @@ echo "[1/2] Publication du parent pom..."
mvn deploy:deploy-file \
-DgroupId=dev.lions.unionflow \
-DartifactId=unionflow-parent \
- -Dversion=1.0.0 \
+ -Dversion=1.0.5 \
-Dpackaging=pom \
-Dfile=parent-pom.xml \
-DrepositoryId="${REGISTRY_ID}" \
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierRequest.java
new file mode 100644
index 0000000..f1d777a
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierRequest.java
@@ -0,0 +1,54 @@
+package dev.lions.unionflow.server.api.dto.kyc;
+
+import dev.lions.unionflow.server.api.enums.membre.TypePieceIdentite;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+/**
+ * DTO de création ou mise à jour d'un dossier KYC/AML.
+ */
+@Data
+@Builder
+public class KycDossierRequest {
+
+ @NotNull
+ private String membreId;
+
+ @NotNull
+ private TypePieceIdentite typePiece;
+
+ @NotBlank
+ @Size(max = 50)
+ private String numeroPiece;
+
+ /** Date d'expiration de la pièce d'identité. */
+ private LocalDate dateExpirationPiece;
+
+ /** Justificatif de domicile — ID du fichier stocké (MinIO/S3). */
+ @Size(max = 500)
+ private String justifDomicileFileId;
+
+ /** Pièce d'identité recto — ID du fichier stocké. */
+ @Size(max = 500)
+ private String pieceIdentiteRectoFileId;
+
+ /** Pièce d'identité verso — ID du fichier stocké. */
+ @Size(max = 500)
+ private String pieceIdentiteVersoFileId;
+
+ /** Notes du validateur lors d'une approbation/refus manuel. */
+ @Size(max = 1000)
+ private String notesValidateur;
+
+ /** Indique si le membre est une Personne Exposée Politiquement (PEP). */
+ private Boolean estPep;
+
+ /** Nationalité déclarée (ISO 3166-1 alpha-2). */
+ @Size(max = 5)
+ private String nationalite;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierResponse.java
new file mode 100644
index 0000000..bed3a83
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierResponse.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.kyc;
+
+import dev.lions.unionflow.server.api.dto.base.BaseDTO;
+import dev.lions.unionflow.server.api.enums.membre.NiveauRisqueKyc;
+import dev.lions.unionflow.server.api.enums.membre.StatutKyc;
+import dev.lions.unionflow.server.api.enums.membre.TypePieceIdentite;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+/**
+ * DTO de réponse pour un dossier KYC/AML.
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class KycDossierResponse extends BaseDTO {
+
+ private UUID membreId;
+ private String membreNomComplet;
+ private String membreEmail;
+
+ private TypePieceIdentite typePiece;
+ private String numeroPiece;
+ private LocalDate dateExpirationPiece;
+
+ private String justifDomicileFileId;
+ private String pieceIdentiteRectoFileId;
+ private String pieceIdentiteVersoFileId;
+
+ private StatutKyc statut;
+ private NiveauRisqueKyc niveauRisque;
+ private int scoreRisque;
+
+ private boolean estPep;
+ private String nationalite;
+
+ private LocalDateTime dateVerification;
+ private UUID validateurId;
+ private String notesValidateur;
+
+ /** Année de référence pour la rétention (partitionnement logique). */
+ private int anneeReference;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/BloquerMembreRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/BloquerMembreRequest.java
new file mode 100644
index 0000000..0931e9b
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/BloquerMembreRequest.java
@@ -0,0 +1,30 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import jakarta.validation.constraints.NotNull;
+import java.util.UUID;
+import lombok.Builder;
+
+/**
+ * Requête pour bloquer un membre dans une organisation.
+ *
+ * Le blocage est unilatéral et limité à une organisation.
+ * Le membre bloqué ne peut plus envoyer de messages au bloqueur
+ * dans cette organisation.
+ *
+ * @param membreABloquerId ID du membre à bloquer (obligatoire)
+ * @param organisationId Organisation dans laquelle le blocage s'applique (obligatoire)
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record BloquerMembreRequest(
+
+ @NotNull(message = "L'ID du membre à bloquer est obligatoire")
+ UUID membreABloquerId,
+
+ @NotNull(message = "L'ID de l'organisation est obligatoire")
+ UUID organisationId
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationDirecteRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationDirecteRequest.java
new file mode 100644
index 0000000..98216af
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationDirecteRequest.java
@@ -0,0 +1,35 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import java.util.UUID;
+import lombok.Builder;
+
+/**
+ * Démarre une conversation directe 1-1 entre le membre connecté
+ * et un autre membre de la même organisation.
+ *
+ *
Si une conversation directe entre ces deux membres existe déjà
+ * dans l'organisation, elle est réutilisée (idempotente).
+ *
+ * @param destinataireId ID du membre destinataire (obligatoire)
+ * @param organisationId ID de l'organisation commune (obligatoire)
+ * @param contenuInitial Premier message optionnel
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record DemarrerConversationDirecteRequest(
+
+ @NotNull(message = "L'ID du destinataire est obligatoire")
+ UUID destinataireId,
+
+ @NotNull(message = "L'ID de l'organisation est obligatoire")
+ UUID organisationId,
+
+ @Size(max = 2000, message = "Le message initial ne doit pas dépasser 2000 caractères")
+ String contenuInitial
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationRoleRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationRoleRequest.java
new file mode 100644
index 0000000..cf35901
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationRoleRequest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import java.util.UUID;
+import lombok.Builder;
+
+/**
+ * Démarre une conversation avec un rôle officiel de l'organisation.
+ *
+ *
Le membre ne contacte pas une personne spécifique mais le "canal"
+ * du rôle (ex: "Contacter le Trésorier"). Tous les membres portant ce
+ * rôle voient et peuvent répondre — si le trésorier change, la conversation
+ * continue avec le nouveau trésorier.
+ *
+ *
Si un canal pour ce rôle existe déjà dans l'organisation, il est réutilisé.
+ *
+ * @param organisationId ID de l'organisation (obligatoire)
+ * @param roleCible Rôle visé : PRESIDENT | TRESORIER | SECRETAIRE | VICE_PRESIDENT | ADMIN
+ * @param contenuInitial Premier message (obligatoire pour un canal rôle)
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record DemarrerConversationRoleRequest(
+
+ @NotNull(message = "L'ID de l'organisation est obligatoire")
+ UUID organisationId,
+
+ @NotBlank(message = "Le rôle cible est obligatoire")
+ @Pattern(
+ regexp = "^(PRESIDENT|TRESORIER|SECRETAIRE|VICE_PRESIDENT|ADMIN|ADMIN_ORGANISATION)$",
+ message = "Rôle invalide. Valeurs : PRESIDENT, TRESORIER, SECRETAIRE, VICE_PRESIDENT, ADMIN, ADMIN_ORGANISATION"
+ )
+ String roleCible,
+
+ @NotBlank(message = "Le message initial est obligatoire pour contacter un rôle")
+ @Size(max = 2000, message = "Le message ne doit pas dépasser 2000 caractères")
+ String contenuInitial
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/EnvoyerMessageRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/EnvoyerMessageRequest.java
new file mode 100644
index 0000000..7f032aa
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/EnvoyerMessageRequest.java
@@ -0,0 +1,47 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import java.util.UUID;
+import lombok.Builder;
+
+/**
+ * Requête pour envoyer un message dans une conversation existante.
+ *
+ *
La validation contextuelle (contenu OU urlFichier selon le type)
+ * est effectuée dans le service.
+ *
+ * @param typeMessage TEXTE (défaut) | VOCAL | IMAGE | SYSTEME
+ * @param contenu Texte du message (obligatoire pour TEXTE)
+ * @param urlFichier URL du fichier (obligatoire pour VOCAL/IMAGE)
+ * @param dureeAudio Durée en secondes (obligatoire pour VOCAL)
+ * @param messageParentId ID du message auquel on répond (optionnel)
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record EnvoyerMessageRequest(
+
+ @Pattern(
+ regexp = "^(TEXTE|VOCAL|IMAGE|SYSTEME)$",
+ message = "Type de message invalide. Valeurs : TEXTE, VOCAL, IMAGE, SYSTEME"
+ )
+ String typeMessage,
+
+ @Size(max = 4000, message = "Le message ne doit pas dépasser 4000 caractères")
+ String contenu,
+
+ @Size(max = 500, message = "L'URL du fichier ne doit pas dépasser 500 caractères")
+ String urlFichier,
+
+ @Min(value = 1, message = "La durée audio doit être supérieure à 0")
+ @Max(value = 300, message = "La durée audio ne peut pas dépasser 300 secondes")
+ Integer dureeAudio,
+
+ UUID messageParentId
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/MettreAJourPolitiqueRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/MettreAJourPolitiqueRequest.java
new file mode 100644
index 0000000..b6bb571
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/request/MettreAJourPolitiqueRequest.java
@@ -0,0 +1,34 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import jakarta.validation.constraints.Pattern;
+import lombok.Builder;
+
+/**
+ * Mise à jour de la politique de communication d'une organisation.
+ * Réservée aux administrateurs.
+ *
+ * @param typePolitique OUVERT | BUREAU_SEULEMENT | GROUPES_INTERNES
+ * @param autoriserMembreVersMembre Autorise les échanges entre membres
+ * @param autoriserMembreVersRole Autorise les échanges vers les rôles du bureau
+ * @param autoriserNotesVocales Autorise les notes vocales
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record MettreAJourPolitiqueRequest(
+
+ @Pattern(
+ regexp = "^(OUVERT|BUREAU_SEULEMENT|GROUPES_INTERNES)$",
+ message = "Politique invalide. Valeurs : OUVERT, BUREAU_SEULEMENT, GROUPES_INTERNES"
+ )
+ String typePolitique,
+
+ Boolean autoriserMembreVersMembre,
+
+ Boolean autoriserMembreVersRole,
+
+ Boolean autoriserNotesVocales
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ContactPolicyResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ContactPolicyResponse.java
new file mode 100644
index 0000000..10f60ae
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ContactPolicyResponse.java
@@ -0,0 +1,31 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * DTO de réponse pour la politique de communication d'une organisation.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContactPolicyResponse {
+
+ private UUID id;
+ private UUID organisationId;
+
+ /** OUVERT | BUREAU_SEULEMENT | GROUPES_INTERNES */
+ private String typePolitique;
+
+ private boolean autoriserMembreVersMembre;
+ private boolean autoriserMembreVersRole;
+ private boolean autoriserNotesVocales;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationResponse.java
new file mode 100644
index 0000000..65fc437
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationResponse.java
@@ -0,0 +1,68 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * DTO de réponse complète pour une conversation.
+ * Inclut les derniers messages et la liste des participants.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ConversationResponse {
+
+ private UUID id;
+
+ /** DIRECTE | ROLE_CANAL | GROUPE */
+ private String typeConversation;
+
+ /** Titre affiché (nom de l'autre participant ou du rôle). */
+ private String titre;
+
+ /** ACTIVE | ARCHIVEE */
+ private String statut;
+
+ /** Rôle cible pour les canaux rôle. */
+ private String roleCible;
+
+ private UUID organisationId;
+ private String organisationNom;
+
+ private LocalDateTime dateCreation;
+ private LocalDateTime dernierMessageAt;
+ private int nombreMessages;
+
+ /** Participants de la conversation. */
+ private List participants;
+
+ /** Derniers messages (page 0). */
+ private List messages;
+
+ /** Nombre de messages non lus pour le membre connecté. */
+ private long nonLus;
+
+ // ── DTO interne pour les participants ─────────────────────────────────────
+
+ @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ public static class ParticipantResponse {
+ private UUID membreId;
+ private String prenom;
+ private String nom;
+ private String roleDansConversation;
+ private LocalDateTime luJusqua;
+ }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationSummaryResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationSummaryResponse.java
new file mode 100644
index 0000000..72692fd
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationSummaryResponse.java
@@ -0,0 +1,52 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * DTO résumé d'une conversation — utilisé dans la liste des conversations.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ConversationSummaryResponse {
+
+ private UUID id;
+
+ /** DIRECTE | ROLE_CANAL | GROUPE */
+ private String typeConversation;
+
+ /**
+ * Titre affiché dans la liste :
+ * - Pour DIRECTE : "Prénom Nom" de l'autre participant
+ * - Pour ROLE_CANAL : "Trésorier", "Président", etc.
+ */
+ private String titre;
+
+ /** Statut : ACTIVE | ARCHIVEE */
+ private String statut;
+
+ /** Aperçu du dernier message (max 100 caractères). */
+ private String dernierMessageApercu;
+
+ /** Type du dernier message (pour afficher l'icône vocal/image). */
+ private String dernierMessageType;
+
+ /** Horodatage du dernier message. */
+ private LocalDateTime dernierMessageAt;
+
+ /** Nombre de messages non lus pour le membre connecté. */
+ private long nonLus;
+
+ /** ID de l'organisation de la conversation. */
+ private UUID organisationId;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/MessageResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/MessageResponse.java
new file mode 100644
index 0000000..3c41838
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/messagerie/response/MessageResponse.java
@@ -0,0 +1,52 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * DTO de réponse pour un message.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class MessageResponse {
+
+ private UUID id;
+
+ /** TEXTE | VOCAL | IMAGE | SYSTEME */
+ private String typeMessage;
+
+ /** Texte du message (null si VOCAL/IMAGE). */
+ private String contenu;
+
+ /** URL du fichier audio ou image. */
+ private String urlFichier;
+
+ /** Durée en secondes (notes vocales uniquement). */
+ private Integer dureeAudio;
+
+ /** True si le message a été supprimé par son auteur. */
+ private boolean supprime;
+
+ // ── Expéditeur ────────────────────────────────────────────────────────────
+ private UUID expediteurId;
+ private String expediteurNom;
+ private String expediteurPrenom;
+
+ // ── Réponse à un message ──────────────────────────────────────────────────
+ private UUID messageParentId;
+ /** Aperçu du message parent (premiers 100 caractères). */
+ private String messageParentApercu;
+
+ // ── Horodatage ────────────────────────────────────────────────────────────
+ private LocalDateTime dateEnvoi;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellRequest.java
new file mode 100644
index 0000000..5ac7f81
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellRequest.java
@@ -0,0 +1,50 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.financier;
+
+import jakarta.validation.constraints.DecimalMax;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.eclipse.microprofile.openapi.annotations.media.Schema;
+
+import java.math.BigDecimal;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Schema(description = "Paramètres financiers de la mutuelle")
+public class ParametresFinanciersMutuellRequest {
+
+ @NotBlank
+ @Schema(description = "UUID de l'organisation")
+ private String organisationId;
+
+ @NotNull
+ @DecimalMin(value = "1.0")
+ @Schema(description = "Valeur nominale par défaut d'une part sociale (XOF)", example = "5000")
+ private BigDecimal valeurNominaleParDefaut;
+
+ @NotNull
+ @DecimalMin(value = "0.0")
+ @DecimalMax(value = "1.0")
+ @Schema(description = "Taux d'intérêt annuel sur l'épargne (ex: 0.03 = 3%)", example = "0.03")
+ private BigDecimal tauxInteretAnnuelEpargne;
+
+ @NotNull
+ @DecimalMin(value = "0.0")
+ @DecimalMax(value = "1.0")
+ @Schema(description = "Taux de dividende annuel sur les parts sociales (ex: 0.05 = 5%)", example = "0.05")
+ private BigDecimal tauxDividendePartsAnnuel;
+
+ @NotBlank
+ @Schema(description = "Périodicité du calcul des intérêts: MENSUEL, TRIMESTRIEL, ANNUEL", example = "MENSUEL")
+ private String periodiciteCalcul;
+
+ @DecimalMin(value = "0.0")
+ @Schema(description = "Solde minimum pour bénéficier des intérêts sur épargne", example = "10000")
+ private BigDecimal seuilMinEpargneInterets;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellResponse.java
new file mode 100644
index 0000000..52dda27
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellResponse.java
@@ -0,0 +1,34 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.financier;
+
+import dev.lions.unionflow.server.api.dto.base.BaseDTO;
+import lombok.*;
+import org.eclipse.microprofile.openapi.annotations.media.Schema;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Schema(description = "Paramètres financiers d'une mutuelle")
+public class ParametresFinanciersMutuellResponse extends BaseDTO {
+
+ private String organisationId;
+ private String organisationNom;
+ private BigDecimal valeurNominaleParDefaut;
+ private BigDecimal tauxInteretAnnuelEpargne;
+ private BigDecimal tauxDividendePartsAnnuel;
+ private String periodiciteCalcul;
+ private BigDecimal seuilMinEpargneInterets;
+
+ @Schema(description = "Date du prochain calcul automatique des intérêts")
+ private LocalDate prochaineCalculInterets;
+
+ @Schema(description = "Date du dernier calcul effectué")
+ private LocalDate dernierCalculInterets;
+
+ @Schema(description = "Nombre de comptes épargne traités lors du dernier calcul")
+ private Integer dernierNbComptesTraites;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesRequest.java
new file mode 100644
index 0000000..7754cbd
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesRequest.java
@@ -0,0 +1,41 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.eclipse.microprofile.openapi.annotations.media.Schema;
+
+import java.math.BigDecimal;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Schema(description = "Ouverture d'un compte de parts sociales")
+public class ComptePartsSocialesRequest {
+
+ @NotBlank
+ @Schema(description = "UUID du membre souscripteur")
+ private String membreId;
+
+ @NotBlank
+ @Schema(description = "UUID de l'organisation / mutuelle")
+ private String organisationId;
+
+ @NotNull
+ @Min(0)
+ @Schema(description = "Nombre de parts souscrites à l'ouverture (0 = compte sans parts initiales)", example = "1")
+ private Integer nombreParts;
+
+ @Schema(description = "Valeur nominale par part (XOF). Si absent, utilise la valeur configurée pour l'organisation.")
+ @DecimalMin(value = "1.0")
+ private BigDecimal valeurNominale;
+
+ @Schema(description = "Notes d'ouverture")
+ private String notes;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesResponse.java
new file mode 100644
index 0000000..8cc29ae
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesResponse.java
@@ -0,0 +1,42 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import dev.lions.unionflow.server.api.dto.base.BaseDTO;
+import dev.lions.unionflow.server.api.enums.mutuelle.parts.StatutComptePartsSociales;
+import lombok.*;
+import org.eclipse.microprofile.openapi.annotations.media.Schema;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Schema(description = "Compte de parts sociales d'un membre")
+public class ComptePartsSocialesResponse extends BaseDTO {
+
+ private String membreId;
+ private String membreNomComplet;
+ private String organisationId;
+
+ @Schema(description = "Numéro de compte (ex: PS-MEG-00042)")
+ private String numeroCompte;
+
+ @Schema(description = "Nombre de parts actuellement détenues")
+ private Integer nombreParts;
+
+ @Schema(description = "Valeur nominale par part en devise de l'organisation")
+ private BigDecimal valeurNominale;
+
+ @Schema(description = "Montant total du capital = nombreParts × valeurNominale")
+ private BigDecimal montantTotal;
+
+ @Schema(description = "Cumul des dividendes reçus")
+ private BigDecimal totalDividendesRecus;
+
+ private StatutComptePartsSociales statut;
+ private LocalDate dateOuverture;
+ private LocalDate dateDerniereOperation;
+ private String notes;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesRequest.java
new file mode 100644
index 0000000..528a62f
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesRequest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.parts.TypeTransactionPartsSociales;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.eclipse.microprofile.openapi.annotations.media.Schema;
+
+import java.math.BigDecimal;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Schema(description = "Transaction sur un compte de parts sociales")
+public class TransactionPartsSocialesRequest {
+
+ @NotBlank
+ @Schema(description = "UUID du compte de parts sociales cible")
+ private String compteId;
+
+ @NotNull
+ private TypeTransactionPartsSociales typeTransaction;
+
+ @NotNull
+ @Min(1)
+ @Schema(description = "Nombre de parts concernées par la transaction")
+ private Integer nombreParts;
+
+ @Schema(description = "Montant total en devise. Si absent, calculé depuis nombreParts × valeurNominale du compte.")
+ @DecimalMin(value = "0.01")
+ private BigDecimal montant;
+
+ @Schema(description = "Motif / libellé de la transaction")
+ private String motif;
+
+ @Schema(description = "Référence externe (n° de reçu, bordereau, etc.)")
+ private String referenceExterne;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesResponse.java
new file mode 100644
index 0000000..7a7eb1b
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesResponse.java
@@ -0,0 +1,39 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import dev.lions.unionflow.server.api.dto.base.BaseDTO;
+import dev.lions.unionflow.server.api.enums.mutuelle.parts.TypeTransactionPartsSociales;
+import lombok.*;
+import org.eclipse.microprofile.openapi.annotations.media.Schema;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Schema(description = "Transaction sur un compte de parts sociales")
+public class TransactionPartsSocialesResponse extends BaseDTO {
+
+ private String compteId;
+ private String numeroCompte;
+ private TypeTransactionPartsSociales typeTransaction;
+ private String typeTransactionLibelle;
+
+ @Schema(description = "Nombre de parts impliquées")
+ private Integer nombreParts;
+
+ @Schema(description = "Montant en devise")
+ private BigDecimal montant;
+
+ @Schema(description = "Solde en parts avant la transaction")
+ private Integer soldePartsAvant;
+
+ @Schema(description = "Solde en parts après la transaction")
+ private Integer soldePartsApres;
+
+ private String motif;
+ private String referenceExterne;
+ private LocalDateTime dateTransaction;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequest.java
index ebcd531..6ba1016 100644
--- a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequest.java
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequest.java
@@ -3,29 +3,34 @@ package dev.lions.unionflow.server.api.dto.paiement.request;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.util.UUID;
-
import lombok.Builder;
/**
- * Requete de création d'un paiement.
+ * Requête de création d'un paiement.
*
* @author UnionFlow Team
* @version 3.0
+ * @since 2025-01-29
*/
@Builder
public record CreatePaiementRequest(
- @NotBlank(message = "Le numéro de référence est obligatoire") String numeroReference,
- @NotNull(message = "Le montant est obligatoire") @DecimalMin(value = "0.0", message = "Le montant doit être positif") BigDecimal montant,
+ @NotBlank(message = "Le numéro de référence est obligatoire")
+ String numeroReference,
- @NotBlank(message = "Le code devise est obligatoire") @Pattern(regexp = "^[A-Z]{3}$", message = "Le code devise doit être un code ISO à 3 lettres") String codeDevise,
+ @NotNull(message = "Le montant est obligatoire")
+ @DecimalMin(value = "0.01", message = "Le montant doit être supérieur à 0")
+ BigDecimal montant,
- @NotBlank(message = "La méthode de paiement est obligatoire") String methodePaiement,
+ @NotBlank(message = "Le code devise est obligatoire")
+ String codeDevise,
- String commentaire,
+ @NotBlank(message = "La méthode de paiement est obligatoire")
+ String methodePaiement,
- @NotNull(message = "Le membre payeur est obligatoire") UUID membreId) {
-}
+ String commentaire,
+
+ UUID membreId
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequest.java
index 902a12a..6637b43 100644
--- a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequest.java
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequest.java
@@ -2,45 +2,25 @@ package dev.lions.unionflow.server.api.dto.paiement.request;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
-import jakarta.validation.constraints.Size;
import java.util.UUID;
-import lombok.Builder;
/**
- * Requête pour déclarer un paiement manuel (espèces, virement, chèque).
- * Le paiement est créé avec le statut EN_ATTENTE_VALIDATION.
- * Le trésorier devra le valider via une page admin.
- *
- * @param cotisationId ID de la cotisation payée
- * @param methodePaiement Méthode de paiement (ESPECES, VIREMENT, CHEQUE, AUTRE)
- * @param reference Référence du paiement (numéro de transaction, numéro de chèque, etc.)
- * @param commentaire Commentaire optionnel
- * @param origineFonds Origine des fonds (LCB-FT) — obligatoire au-dessus du seuil configuré
- * @param justificationLcbFt Justification complémentaire LCB-FT si nécessaire
+ * Requête de déclaration d'un paiement manuel (espèces, virement, chèque).
*
* @author UnionFlow Team
- * @version 1.0
- * @since 2026-03-02
+ * @version 3.0
+ * @since 2025-01-29
*/
-@Builder
public record DeclarerPaiementManuelRequest(
+
@NotNull(message = "L'ID de la cotisation est obligatoire")
UUID cotisationId,
@NotBlank(message = "La méthode de paiement est obligatoire")
- @Pattern(regexp = "^(ESPECES|VIREMENT|CHEQUE|AUTRE)$",
- message = "Méthode de paiement invalide. Valeurs autorisées : ESPECES, VIREMENT, CHEQUE, AUTRE")
String methodePaiement,
- @Size(max = 100, message = "La référence ne doit pas dépasser 100 caractères")
+ /** Référence externe (numéro de chèque, référence virement, etc.) */
String reference,
- @Size(max = 500, message = "Le commentaire ne doit pas dépasser 500 caractères")
- String commentaire,
-
- String origineFonds,
-
- String justificationLcbFt
-) {
-}
+ String commentaire
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequest.java
index 42e9d47..7bcfb34 100644
--- a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequest.java
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequest.java
@@ -1,40 +1,22 @@
package dev.lions.unionflow.server.api.dto.paiement.request;
-import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
import java.util.UUID;
-import lombok.Builder;
/**
- * Requête pour initier un paiement en ligne via un gateway (Wave, Orange, Free Money, Carte).
- *
- * @param cotisationId ID de la cotisation à payer
- * @param methodePaiement Méthode de paiement (WAVE, ORANGE_MONEY, FREE_MONEY, CARTE_BANCAIRE)
- * @param numeroTelephone Numéro de téléphone pour Wave/Orange/Free (format: 221771234567)
- * @param origineFonds Origine des fonds (LCB-FT) — obligatoire au-dessus du seuil configuré
- * @param justificationLcbFt Justification complémentaire LCB-FT si nécessaire
+ * Requête d'initiation de paiement en ligne via Wave, Orange Money, Free Money ou carte bancaire.
*
* @author UnionFlow Team
- * @version 1.0
- * @since 2026-03-02
+ * @version 3.0
+ * @since 2025-01-29
*/
-@Builder
public record InitierPaiementEnLigneRequest(
+
@NotNull(message = "L'ID de la cotisation est obligatoire")
UUID cotisationId,
- @NotBlank(message = "La méthode de paiement est obligatoire")
- @Pattern(regexp = "^(WAVE|ORANGE_MONEY|FREE_MONEY|CARTE_BANCAIRE)$",
- message = "Méthode de paiement invalide. Valeurs autorisées : WAVE, ORANGE_MONEY, FREE_MONEY, CARTE_BANCAIRE")
+ @NotNull(message = "La méthode de paiement est obligatoire")
String methodePaiement,
- /** Optionnel sur le web (QR code sans restriction de payeur). Obligatoire sur mobile. */
- @Pattern(regexp = "^\\d{9,15}$", message = "Numéro de téléphone invalide (9-15 chiffres)")
- String numeroTelephone,
-
- String origineFonds,
-
- String justificationLcbFt
-) {
-}
+ String numeroTelephone
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponse.java
index 0ec38de..db57e61 100644
--- a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponse.java
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponse.java
@@ -1,31 +1,53 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
+import java.math.BigDecimal;
+import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
-import java.math.BigDecimal;
-import java.util.UUID;
-
/**
- * Réponse du polling de statut d'une IntentionPaiement Wave.
- * Utilisée par le web pour savoir si le paiement est confirmé.
+ * Réponse au polling du statut d'une intention de paiement Wave.
+ *
+ * Utilisée par le deep link de retour (mobile) et le polling web (QR code).
+ * Quand {@code statut} vaut {@code COMPLETEE}, la cotisation est automatiquement
+ * marquée PAYEE et {@code confirme} vaut {@code true}.
+ *
+ * @author UnionFlow Team
+ * @version 3.0
+ * @since 2026-04-13
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class IntentionStatutResponse {
+
+ /** UUID de l'intention de paiement (clé de polling) */
private UUID intentionId;
+
/** INITIEE | EN_COURS | COMPLETEE | EXPIREE | ECHOUEE */
private String statut;
- /** URL à encoder en QR code (wave_launch_url Wave Checkout) */
+
+ /** Raccourci : {@code true} si statut == COMPLETEE */
+ private boolean confirme;
+
+ /** URL Wave — pour régénérer le QR code si la session est toujours active */
private String waveLaunchUrl;
+
+ /** ID de session Wave (cos-xxx) */
private String waveCheckoutSessionId;
+
/** ID de transaction Wave (TCN...) — disponible quand COMPLETEE */
private String waveTransactionId;
+
+ /** Montant du paiement */
private BigDecimal montant;
+
+ /** Référence de la cotisation concernée */
private String referenceCotisation;
+
+ /** Message lisible pour l'utilisateur */
private String message;
}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponse.java
index a38cc51..8c8fa90 100644
--- a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponse.java
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponse.java
@@ -2,76 +2,45 @@ package dev.lions.unionflow.server.api.dto.paiement.response;
import java.math.BigDecimal;
import java.util.UUID;
-import lombok.AllArgsConstructor;
import lombok.Builder;
-import lombok.EqualsAndHashCode;
import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
/**
- * DTO de réponse pour l'initiation d'un paiement en ligne via un gateway.
- * Retourne l'URL de redirection vers le gateway (Wave, Orange, Free Money, Carte).
+ * DTO de réponse pour l'initiation d'un paiement en ligne (Wave, Orange Money, etc.).
*
* @author UnionFlow Team
- * @version 1.0
- * @since 2026-03-02
+ * @version 3.0
+ * @since 2025-01-29
*/
@Getter
-@Setter
@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@EqualsAndHashCode
public class PaiementGatewayResponse {
- /**
- * ID de la transaction créée
- */
+
+ /** ID interne du paiement ou de l'intention créé. */
private UUID transactionId;
- /**
- * URL de redirection vers le gateway de paiement
- */
+ /** URL de redirection vers la page de paiement du gateway. */
private String redirectUrl;
- /**
- * Montant à payer (en FCFA)
- */
- private BigDecimal montant;
-
- /**
- * Statut de la transaction (EN_ATTENTE, VALIDE, ECHOUE)
- */
- private String statut;
-
- /**
- * Méthode de paiement (WAVE, ORANGE_MONEY, FREE_MONEY, CARTE_BANCAIRE)
- */
- private String methodePaiement;
-
- /**
- * Référence de la cotisation
- */
- private String referenceCotisation;
-
- /**
- * Message d'information pour l'utilisateur
- */
- private String message;
-
- /**
- * URL Wave pour ouvrir l'app Wave (redirection automatique membre).
- * Présent lorsque methodePaiement = WAVE.
- */
+ /** URL spécifique Wave (wave_launch_url) pour deep-link vers l'app Wave. */
private String waveLaunchUrl;
- /**
- * ID de session Checkout Wave (cos-xxx). Pour réconciliation / webhook.
- */
+ /** ID de la session Wave Checkout. */
private String waveCheckoutSessionId;
- /**
- * Référence client (UUID intention) pour le deep link de retour.
- */
+ /** Référence client envoyée à Wave (intention UUID). */
private String clientReference;
+
+ private BigDecimal montant;
+
+ /** Statut initial (EN_ATTENTE). */
+ private String statut;
+
+ private String methodePaiement;
+
+ /** Numéro de référence de la cotisation associée. */
+ private String referenceCotisation;
+
+ /** Message d'information à afficher à l'utilisateur. */
+ private String message;
}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementResponse.java
index 77a08b8..67044e3 100644
--- a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementResponse.java
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementResponse.java
@@ -16,36 +16,39 @@ import lombok.Setter;
*
* @author UnionFlow Team
* @version 3.0
+ * @since 2025-01-29
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
+@EqualsAndHashCode(callSuper = false)
public class PaiementResponse extends BaseResponse {
+
private String numeroReference;
+
private BigDecimal montant;
private String codeDevise;
+
private String methodePaiement;
private String methodePaiementLibelle;
+
private String statutPaiement;
private String statutPaiementLibelle;
private String statutPaiementSeverity;
+
private LocalDateTime datePaiement;
private LocalDateTime dateValidation;
+
private String validateur;
+
private String referenceExterne;
private String urlPreuve;
private String commentaire;
- // Informations relatives au payeur
private UUID membreId;
private String membreNom;
- // Intégration Wave
private UUID transactionWaveId;
-
- // LCB-FT (Lutte Contre le Blanchiment et Financement du Terrorisme)
- private String origineFonds;
- private String justificationLcbFt;
}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponse.java
index e95a1fd..4c3ef52 100644
--- a/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponse.java
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponse.java
@@ -1,31 +1,24 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
/**
- * DTO de réponse résumé pour un paiement.
- * Utilisé principalement pour l'affichage de listes.
+ * DTO résumé pour les listes de paiements.
*
* @author UnionFlow Team
* @version 3.0
+ * @since 2025-01-29
*/
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-public class PaiementSummaryResponse {
- private UUID id;
- private String numeroReference;
- private BigDecimal montant;
- private String codeDevise;
- private String methodePaiementLibelle;
- private String statutPaiement;
- private String statutPaiementLibelle;
- private String statutPaiementSeverity;
- private LocalDateTime datePaiement;
-}
+public record PaiementSummaryResponse(
+ UUID id,
+ String numeroReference,
+ BigDecimal montant,
+ String codeDevise,
+ String methodePaiementLibelle,
+ String statutPaiement,
+ String statutPaiementLibelle,
+ String statutPaiementSeverity,
+ LocalDateTime datePaiement
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/DeclarerVersementManuelRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/DeclarerVersementManuelRequest.java
new file mode 100644
index 0000000..2534a12
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/DeclarerVersementManuelRequest.java
@@ -0,0 +1,50 @@
+package dev.lions.unionflow.server.api.dto.versement.request;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import java.util.UUID;
+import lombok.Builder;
+
+/**
+ * Requête pour déclarer un versement manuel (espèces, virement, chèque).
+ *
+ *
Le versement est créé avec le statut {@code EN_ATTENTE_VALIDATION}.
+ * Le trésorier de l'organisation devra le valider via la page admin.
+ *
+ * @param cotisationId ID de la cotisation réglée (obligatoire)
+ * @param methodePaiement Mode de règlement : ESPECES | VIREMENT | CHEQUE | AUTRE
+ * @param reference Référence libre (numéro de chèque, bordereau de virement…)
+ * @param commentaire Commentaire optionnel
+ * @param origineFonds Origine des fonds — obligatoire au-delà du seuil LCB-FT
+ * @param justificationLcbFt Justification complémentaire LCB-FT si nécessaire
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record DeclarerVersementManuelRequest(
+
+ @NotNull(message = "L'ID de la cotisation est obligatoire")
+ UUID cotisationId,
+
+ @NotBlank(message = "La méthode de règlement est obligatoire")
+ @Pattern(
+ regexp = "^(ESPECES|VIREMENT|CHEQUE|AUTRE)$",
+ message = "Méthode invalide. Valeurs autorisées : ESPECES, VIREMENT, CHEQUE, AUTRE"
+ )
+ String methodePaiement,
+
+ @Size(max = 100, message = "La référence ne doit pas dépasser 100 caractères")
+ String reference,
+
+ @Size(max = 500, message = "Le commentaire ne doit pas dépasser 500 caractères")
+ String commentaire,
+
+ String origineFonds,
+
+ String justificationLcbFt
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/InitierDepotEpargneRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/InitierDepotEpargneRequest.java
new file mode 100644
index 0000000..948fa6b
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/InitierDepotEpargneRequest.java
@@ -0,0 +1,43 @@
+package dev.lions.unionflow.server.api.dto.versement.request;
+
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import java.math.BigDecimal;
+import java.util.UUID;
+import lombok.Builder;
+
+/**
+ * Requête pour initier un dépôt sur compte épargne via Wave.
+ *
+ *
Même flux que le versement de cotisation : Wave s'ouvre sur le même téléphone,
+ * le membre confirme avec son PIN Wave, puis retour automatique dans UnionFlow.
+ *
+ * @param compteId ID du compte épargne cible (obligatoire)
+ * @param montant Montant à déposer, en FCFA (obligatoire, > 0)
+ * @param numeroTelephone Numéro Wave du membre, pré-rempli depuis le profil
+ * @param origineFonds Origine des fonds — obligatoire au-delà du seuil LCB-FT
+ * @param justificationLcbFt Justification complémentaire LCB-FT si nécessaire
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record InitierDepotEpargneRequest(
+
+ @NotNull(message = "L'ID du compte épargne est obligatoire")
+ UUID compteId,
+
+ @NotNull(message = "Le montant est obligatoire")
+ @DecimalMin(value = "0.01", message = "Le montant doit être supérieur à 0")
+ BigDecimal montant,
+
+ @Pattern(regexp = "^\\d{9,15}$", message = "Numéro de téléphone invalide (9-15 chiffres)")
+ String numeroTelephone,
+
+ String origineFonds,
+
+ String justificationLcbFt
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/InitierVersementWaveRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/InitierVersementWaveRequest.java
new file mode 100644
index 0000000..f5ef7d2
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/versement/request/InitierVersementWaveRequest.java
@@ -0,0 +1,39 @@
+package dev.lions.unionflow.server.api.dto.versement.request;
+
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import java.util.UUID;
+import lombok.Builder;
+
+/**
+ * Requête pour initier un versement via Wave Mobile Money.
+ *
+ *
Wave est la seule méthode de paiement en ligne active. Le numéro de
+ * téléphone est pré-rempli depuis le profil du membre (même téléphone qu'UnionFlow),
+ * ce qui permet à Wave de s'ouvrir directement avec toutes les informations.
+ *
+ * @param cotisationId ID de la cotisation à régler (obligatoire)
+ * @param numeroTelephone Numéro Wave du membre, pré-rempli depuis le profil
+ * (9-15 chiffres, optionnel sur web QR code)
+ * @param origineFonds Origine des fonds — obligatoire au-delà du seuil LCB-FT
+ * @param justificationLcbFt Justification complémentaire LCB-FT si nécessaire
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Builder
+public record InitierVersementWaveRequest(
+
+ @NotNull(message = "L'ID de la cotisation est obligatoire")
+ UUID cotisationId,
+
+ /** Optionnel sur web (QR code sans restriction de payeur). Obligatoire sur mobile. */
+ @Pattern(regexp = "^\\d{9,15}$", message = "Numéro de téléphone invalide (9-15 chiffres)")
+ String numeroTelephone,
+
+ String origineFonds,
+
+ String justificationLcbFt
+
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementGatewayResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementGatewayResponse.java
new file mode 100644
index 0000000..f3bcfdb
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementGatewayResponse.java
@@ -0,0 +1,59 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Réponse à l'initiation d'un versement Wave.
+ *
+ *
Contient le {@code waveLaunchUrl} permettant à {@code url_launcher}
+ * d'ouvrir l'application Wave directement sur le téléphone du membre avec
+ * le montant et le numéro pré-remplis. Le {@code clientReference} (UUID
+ * de l'intention) est utilisé dans le deep link de retour :
+ * {@code unionflow://payment?result=success&ref={clientReference}}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode
+public class VersementGatewayResponse {
+
+ /** ID du versement créé */
+ private UUID versementId;
+
+ /** URL Wave pour {@code url_launcher} — ouvre l'app Wave sur le même téléphone */
+ private String waveLaunchUrl;
+
+ /** ID de session Checkout Wave (cos-xxx) — pour le polling et la réconciliation webhook */
+ private String waveCheckoutSessionId;
+
+ /**
+ * UUID de l'intention — utilisé comme paramètre {@code ref} dans le deep link retour
+ * {@code unionflow://payment?result=success&ref={clientReference}}
+ */
+ private String clientReference;
+
+ /** Montant du versement en FCFA */
+ private BigDecimal montant;
+
+ /** Statut initial : EN_ATTENTE */
+ private String statut;
+
+ /** Référence de la cotisation concernée */
+ private String referenceCotisation;
+
+ /** Message d'information pour l'utilisateur */
+ private String message;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementResponse.java
new file mode 100644
index 0000000..6908d37
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementResponse.java
@@ -0,0 +1,85 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import dev.lions.unionflow.server.api.dto.base.BaseResponse;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * DTO de réponse détaillée pour un versement.
+ *
+ *
Un versement est l'acte de régler une cotisation. Il peut être effectué
+ * via Wave (deep link natif) ou manuellement (espèces, virement, chèque).
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class VersementResponse extends BaseResponse {
+
+ /** Référence unique du versement (ex: VRS-2026-XXXXXXXXXXXX) */
+ private String numeroReference;
+
+ // ── Montant ───────────────────────────────────────────────────────────────
+
+ private BigDecimal montant;
+ private String codeDevise;
+
+ // ── Méthode ───────────────────────────────────────────────────────────────
+
+ /** WAVE | ESPECES | VIREMENT | CHEQUE | AUTRE */
+ private String methodePaiement;
+ private String methodePaiementLibelle;
+
+ // ── Statut ────────────────────────────────────────────────────────────────
+
+ /** EN_ATTENTE | EN_COURS | CONFIRME | ECHEC | EN_ATTENTE_VALIDATION | ANNULE */
+ private String statutPaiement;
+ private String statutPaiementLibelle;
+ private String statutPaiementSeverity;
+
+ // ── Dates ─────────────────────────────────────────────────────────────────
+
+ private LocalDateTime datePaiement;
+ private LocalDateTime dateValidation;
+
+ // ── Validation (paiement manuel) ──────────────────────────────────────────
+
+ private String validateur;
+
+ // ── Traçabilité ───────────────────────────────────────────────────────────
+
+ /** ID transaction Wave (TCN...) ou référence chèque/virement */
+ private String referenceExterne;
+ private String urlPreuve;
+ private String commentaire;
+
+ // ── Payeur ────────────────────────────────────────────────────────────────
+
+ private UUID membreId;
+ private String membreNom;
+
+ /** Numéro Wave utilisé pour ce versement */
+ private String numeroTelephone;
+
+ // ── Intégration Wave ─────────────────────────────────────────────────────
+
+ private UUID transactionWaveId;
+
+ // ── LCB-FT ───────────────────────────────────────────────────────────────
+
+ private String origineFonds;
+ private String justificationLcbFt;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementStatutResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementStatutResponse.java
new file mode 100644
index 0000000..d63ab4b
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementStatutResponse.java
@@ -0,0 +1,53 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Réponse au polling du statut d'un versement Wave.
+ *
+ *
Utilisée par le deep link de retour (mobile) et le polling web.
+ * Quand {@code statut} vaut {@code COMPLETEE}, la cotisation est automatiquement
+ * marquée PAYEE et {@code confirme} vaut {@code true}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class VersementStatutResponse {
+
+ /** UUID de l'intention Wave (clé de polling) */
+ private UUID intentionId;
+
+ /** INITIEE | EN_COURS | COMPLETEE | EXPIREE | ECHOUEE */
+ private String statut;
+
+ /** Raccourci : {@code true} si statut == COMPLETEE */
+ private boolean confirme;
+
+ /** URL Wave — pour régénérer le QR code si la session est toujours active */
+ private String waveLaunchUrl;
+
+ /** ID de session Wave (cos-xxx) */
+ private String waveCheckoutSessionId;
+
+ /** ID de transaction Wave (TCN...) — disponible quand COMPLETEE */
+ private String waveTransactionId;
+
+ /** Montant du versement */
+ private BigDecimal montant;
+
+ /** Référence de la cotisation concernée */
+ private String referenceCotisation;
+
+ /** Message lisible pour l'utilisateur */
+ private String message;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementSummaryResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementSummaryResponse.java
new file mode 100644
index 0000000..120fd08
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/dto/versement/response/VersementSummaryResponse.java
@@ -0,0 +1,30 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * DTO résumé d'un versement — utilisé dans les listes.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class VersementSummaryResponse {
+ private UUID id;
+ private String numeroReference;
+ private BigDecimal montant;
+ private String codeDevise;
+ private String methodePaiementLibelle;
+ private String statutPaiement;
+ private String statutPaiementLibelle;
+ private String statutPaiementSeverity;
+ private LocalDateTime datePaiement;
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/membre/NiveauRisqueKyc.java b/src/main/java/dev/lions/unionflow/server/api/enums/membre/NiveauRisqueKyc.java
new file mode 100644
index 0000000..f9c784e
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/membre/NiveauRisqueKyc.java
@@ -0,0 +1,43 @@
+package dev.lions.unionflow.server.api.enums.membre;
+
+/**
+ * Niveau de risque LCB-FT calculé par le service KYC/AML.
+ * Détermine les contrôles additionnels applicables au membre.
+ */
+public enum NiveauRisqueKyc {
+
+ /** Risque faible — profil standard, pas de signalement. */
+ FAIBLE("Risque faible", 0, 39),
+
+ /** Risque moyen — surveillance accrue, revue annuelle. */
+ MOYEN("Risque moyen", 40, 69),
+
+ /** Risque élevé — due diligence renforcée, approbation manuelle. */
+ ELEVE("Risque élevé", 70, 89),
+
+ /** Risque très élevé — blocage automatique, signalement GIABA. */
+ CRITIQUE("Risque critique", 90, 100);
+
+ private final String libelle;
+ private final int scoreMin;
+ private final int scoreMax;
+
+ NiveauRisqueKyc(String libelle, int scoreMin, int scoreMax) {
+ this.libelle = libelle;
+ this.scoreMin = scoreMin;
+ this.scoreMax = scoreMax;
+ }
+
+ public String getLibelle() { return libelle; }
+ public int getScoreMin() { return scoreMin; }
+ public int getScoreMax() { return scoreMax; }
+
+ public static NiveauRisqueKyc fromScore(int score) {
+ for (NiveauRisqueKyc niveau : values()) {
+ if (score >= niveau.scoreMin && score <= niveau.scoreMax) {
+ return niveau;
+ }
+ }
+ return CRITIQUE;
+ }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/membre/TypePieceIdentite.java b/src/main/java/dev/lions/unionflow/server/api/enums/membre/TypePieceIdentite.java
new file mode 100644
index 0000000..99c9684
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/membre/TypePieceIdentite.java
@@ -0,0 +1,24 @@
+package dev.lions.unionflow.server.api.enums.membre;
+
+/**
+ * Type de pièce d'identité pour le dossier KYC — conformité GIABA/BCEAO LCB-FT.
+ */
+public enum TypePieceIdentite {
+
+ CNI("Carte Nationale d'Identité"),
+ PASSEPORT("Passeport"),
+ TITRE_SEJOUR("Titre de séjour"),
+ CARTE_CONSULAIRE("Carte consulaire"),
+ PERMIS_CONDUIRE("Permis de conduire"),
+ AUTRE("Autre pièce officielle");
+
+ private final String libelle;
+
+ TypePieceIdentite(String libelle) {
+ this.libelle = libelle;
+ }
+
+ public String getLibelle() {
+ return libelle;
+ }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/StatutConversation.java b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/StatutConversation.java
new file mode 100644
index 0000000..03c9c6b
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/StatutConversation.java
@@ -0,0 +1,17 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+/**
+ * Statut d'une conversation.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+public enum StatutConversation {
+
+ /** Conversation active — messages entrants autorisés. */
+ ACTIVE,
+
+ /** Conversation archivée — lecture seule, plus de nouveaux messages. */
+ ARCHIVEE
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypeContenu.java b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypeContenu.java
new file mode 100644
index 0000000..fbe8acc
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypeContenu.java
@@ -0,0 +1,35 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+/**
+ * Type de contenu d'un message.
+ *
+ *
Les notes vocales (VOCAL) sont critiques pour l'inclusivité :
+ * les membres analphabètes peuvent communiquer par audio exactement
+ * comme sur WhatsApp (bouton maintenir pour parler).
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+public enum TypeContenu {
+
+ /** Message texte classique. */
+ TEXTE,
+
+ /**
+ * Note vocale — fichier audio Opus/AAC stocké sur object storage.
+ * Champs associés : {@code urlFichier} + {@code dureeAudio} (secondes).
+ */
+ VOCAL,
+
+ /**
+ * Image — JPEG/PNG stockée sur object storage.
+ * Champ associé : {@code urlFichier}.
+ */
+ IMAGE,
+
+ /**
+ * Message système généré automatiquement (ex: "La conversation a été archivée").
+ */
+ SYSTEME
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypeConversation.java b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypeConversation.java
new file mode 100644
index 0000000..fdb4df4
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypeConversation.java
@@ -0,0 +1,31 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+/**
+ * Type de conversation dans la messagerie instantanée.
+ *
+ *
La politique de l'organisation détermine quels types sont autorisés.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+public enum TypeConversation {
+
+ /**
+ * Conversation directe 1-1 entre deux membres de la même organisation.
+ * Autorisée par défaut dans toutes les organisations.
+ */
+ DIRECTE,
+
+ /**
+ * Canal vers un rôle officiel (PRESIDENT, TRESORIER, SECRETAIRE…).
+ * Le membre contacte la "boîte" du rôle, pas une personne spécifique.
+ * Tous les membres du rôle voient et peuvent répondre.
+ */
+ ROLE_CANAL,
+
+ /**
+ * Conversation de groupe — réservé V2.
+ */
+ GROUPE
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypePolitiqueCommunication.java b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypePolitiqueCommunication.java
new file mode 100644
index 0000000..4a7e194
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/messagerie/TypePolitiqueCommunication.java
@@ -0,0 +1,38 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+/**
+ * Politique de communication configurable par l'administrateur d'organisation.
+ *
+ *
Valeurs par défaut selon le type d'organisation :
+ *
+ * Tontine (≤30 membres) → {@code OUVERT}
+ * Association (30–500) → {@code OUVERT}
+ * Mutuelle (50–5000) → {@code BUREAU_SEULEMENT}
+ * Coopérative → {@code OUVERT}
+ *
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+public enum TypePolitiqueCommunication {
+
+ /**
+ * Tous les membres peuvent se contacter entre eux et contacter le bureau.
+ * Mode par défaut pour les petites structures (tontines, associations).
+ */
+ OUVERT,
+
+ /**
+ * Les membres ne peuvent contacter que les rôles du bureau
+ * (Président, Trésorier, Secrétaire).
+ * Recommandé pour les mutuelles et grandes organisations.
+ */
+ BUREAU_SEULEMENT,
+
+ /**
+ * Communication uniquement au sein des groupes/comités internes.
+ * Pour les coopératives avec plusieurs sections.
+ */
+ GROUPES_INTERNES
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/StatutComptePartsSociales.java b/src/main/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/StatutComptePartsSociales.java
new file mode 100644
index 0000000..5bf14b6
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/StatutComptePartsSociales.java
@@ -0,0 +1,12 @@
+package dev.lions.unionflow.server.api.enums.mutuelle.parts;
+
+public enum StatutComptePartsSociales {
+ ACTIF("Compte actif"),
+ SUSPENDU("Compte suspendu"),
+ CLOS("Compte clôturé — parts rachetées");
+
+ private final String libelle;
+
+ StatutComptePartsSociales(String libelle) { this.libelle = libelle; }
+ public String getLibelle() { return libelle; }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/TypeTransactionPartsSociales.java b/src/main/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/TypeTransactionPartsSociales.java
new file mode 100644
index 0000000..8295041
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/TypeTransactionPartsSociales.java
@@ -0,0 +1,15 @@
+package dev.lions.unionflow.server.api.enums.mutuelle.parts;
+
+public enum TypeTransactionPartsSociales {
+ SOUSCRIPTION("Souscription de parts sociales"),
+ SOUSCRIPTION_IMPORT("Import historique — souscription"),
+ CESSION_PARTIELLE("Cession partielle de parts"),
+ RACHAT_TOTAL("Rachat total (clôture)"),
+ PAIEMENT_DIVIDENDE("Versement de dividendes / intérêts sur parts"),
+ CORRECTION("Correction administrative");
+
+ private final String libelle;
+
+ TypeTransactionPartsSociales(String libelle) { this.libelle = libelle; }
+ public String getLibelle() { return libelle; }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/payment/CheckoutRequest.java b/src/main/java/dev/lions/unionflow/server/api/payment/CheckoutRequest.java
new file mode 100644
index 0000000..5f65763
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/payment/CheckoutRequest.java
@@ -0,0 +1,25 @@
+package dev.lions.unionflow.server.api.payment;
+
+import java.math.BigDecimal;
+import java.util.Map;
+
+/**
+ * Requête d'initiation d'un checkout — abstraction provider-agnostique.
+ */
+public record CheckoutRequest(
+ BigDecimal amount,
+ String currency,
+ String customerPhone,
+ String customerEmail,
+ /** Référence interne UnionFlow (souscription, cotisation, transaction épargne...). */
+ String reference,
+ String successUrl,
+ String cancelUrl,
+ Map metadata
+) {
+ public CheckoutRequest {
+ if (amount == null || amount.signum() <= 0) throw new IllegalArgumentException("amount doit être positif");
+ if (currency == null || currency.isBlank()) throw new IllegalArgumentException("currency obligatoire");
+ if (reference == null || reference.isBlank()) throw new IllegalArgumentException("reference obligatoire");
+ }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/payment/CheckoutSession.java b/src/main/java/dev/lions/unionflow/server/api/payment/CheckoutSession.java
new file mode 100644
index 0000000..d6e62a6
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/payment/CheckoutSession.java
@@ -0,0 +1,14 @@
+package dev.lions.unionflow.server.api.payment;
+
+import java.time.Instant;
+import java.util.Map;
+
+/**
+ * Résultat d'une initiation de session de paiement.
+ */
+public record CheckoutSession(
+ String externalId,
+ String checkoutUrl,
+ Instant expiresAt,
+ Map providerMetadata
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/payment/PaymentEvent.java b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentEvent.java
new file mode 100644
index 0000000..df7996a
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentEvent.java
@@ -0,0 +1,16 @@
+package dev.lions.unionflow.server.api.payment;
+
+import java.math.BigDecimal;
+import java.time.Instant;
+
+/**
+ * Événement de paiement normalisé reçu via webhook ou polling.
+ */
+public record PaymentEvent(
+ String externalId,
+ String reference,
+ PaymentStatus status,
+ BigDecimal amountConfirmed,
+ String transactionCode,
+ Instant occurredAt
+) {}
diff --git a/src/main/java/dev/lions/unionflow/server/api/payment/PaymentException.java b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentException.java
new file mode 100644
index 0000000..a1ede75
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentException.java
@@ -0,0 +1,25 @@
+package dev.lions.unionflow.server.api.payment;
+
+/**
+ * Exception levée par les implémentations PaymentProvider.
+ */
+public class PaymentException extends RuntimeException {
+
+ private final String providerCode;
+ private final int httpStatus;
+
+ public PaymentException(String providerCode, String message, int httpStatus) {
+ super("[" + providerCode + "] " + message);
+ this.providerCode = providerCode;
+ this.httpStatus = httpStatus;
+ }
+
+ public PaymentException(String providerCode, String message, int httpStatus, Throwable cause) {
+ super("[" + providerCode + "] " + message, cause);
+ this.providerCode = providerCode;
+ this.httpStatus = httpStatus;
+ }
+
+ public String getProviderCode() { return providerCode; }
+ public int getHttpStatus() { return httpStatus; }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/payment/PaymentProvider.java b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentProvider.java
new file mode 100644
index 0000000..a5f041a
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentProvider.java
@@ -0,0 +1,55 @@
+package dev.lions.unionflow.server.api.payment;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Abstraction unifiée pour tous les providers de paiement UnionFlow.
+ *
+ * Implémentations disponibles : Wave, Orange Money, MTN MoMo, Moov Money, PI-SPI (BCEAO).
+ * Chaque provider est un bean CDI {@code @ApplicationScoped} découvert via
+ * {@code @Any Instance} dans le registry.
+ */
+public interface PaymentProvider {
+
+ /** Code unique du provider — utilisé comme discriminant dans la config et les routes webhook. */
+ String getProviderCode();
+
+ /**
+ * Initie une session de paiement et retourne l'URL de checkout.
+ *
+ * @throws PaymentException si le provider est indisponible ou la requête invalide
+ */
+ CheckoutSession initiateCheckout(CheckoutRequest request) throws PaymentException;
+
+ /**
+ * Interroge le statut d'un paiement par son identifiant provider.
+ *
+ * @throws PaymentException si le provider est indisponible
+ */
+ PaymentStatus getStatus(String externalId) throws PaymentException;
+
+ /**
+ * Traite un webhook entrant et vérifie sa signature.
+ *
+ * @param rawBody payload brut HTTP body
+ * @param headers en-têtes HTTP (inclut la signature)
+ * @throws PaymentException si la signature est invalide ou le payload malformé
+ */
+ PaymentEvent processWebhook(String rawBody, Map headers) throws PaymentException;
+
+ /** Devises supportées — par défaut XOF uniquement. */
+ default Set getSupportedCurrencies() {
+ return Set.of("XOF");
+ }
+
+ /** Indique si ce provider supporte les remboursements. */
+ default boolean supportsRefund() {
+ return false;
+ }
+
+ /** Health check rapide (ping API provider). */
+ default boolean isAvailable() {
+ return true;
+ }
+}
diff --git a/src/main/java/dev/lions/unionflow/server/api/payment/PaymentStatus.java b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentStatus.java
new file mode 100644
index 0000000..af192b1
--- /dev/null
+++ b/src/main/java/dev/lions/unionflow/server/api/payment/PaymentStatus.java
@@ -0,0 +1,10 @@
+package dev.lions.unionflow.server.api.payment;
+
+public enum PaymentStatus {
+ INITIATED,
+ PROCESSING,
+ SUCCESS,
+ FAILED,
+ CANCELLED,
+ EXPIRED
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/agricole/CampagneAgricoleDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/agricole/CampagneAgricoleDTOTest.java
new file mode 100644
index 0000000..d2b3d3a
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/agricole/CampagneAgricoleDTOTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.agricole;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.agricole.StatutCampagneAgricole;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class CampagneAgricoleDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CampagneAgricoleDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CampagneAgricoleDTO dto = new CampagneAgricoleDTO();
+ dto.setOrganisationCoopId("org-1");
+ dto.setDesignation("Campagne Arachide 2026");
+ dto.setTypeCulturePrincipale("Arachide");
+ dto.setSurfaceTotaleEstimeeHectares(new BigDecimal("100.5"));
+ dto.setVolumePrevisionnelTonnes(new BigDecimal("50"));
+ dto.setVolumeReelTonnes(new BigDecimal("48"));
+ dto.setStatut(StatutCampagneAgricole.RECOLTE);
+
+ assertThat(dto.getOrganisationCoopId()).isEqualTo("org-1");
+ assertThat(dto.getDesignation()).isEqualTo("Campagne Arachide 2026");
+ assertThat(dto.getTypeCulturePrincipale()).isEqualTo("Arachide");
+ assertThat(dto.getSurfaceTotaleEstimeeHectares()).isEqualByComparingTo("100.5");
+ assertThat(dto.getVolumePrevisionnelTonnes()).isEqualByComparingTo("50");
+ assertThat(dto.getVolumeReelTonnes()).isEqualByComparingTo("48");
+ assertThat(dto.getStatut()).isEqualTo(StatutCampagneAgricole.RECOLTE);
+ }
+
+ @Test
+ void testBuilder() {
+ CampagneAgricoleDTO dto = CampagneAgricoleDTO.builder()
+ .designation("Test")
+ .statut(StatutCampagneAgricole.PREPARATION)
+ .build();
+ assertThat(dto.getDesignation()).isEqualTo("Test");
+ assertThat(dto.getStatut()).isEqualTo(StatutCampagneAgricole.PREPARATION);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/ayantdroit/AyantDroitRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/ayantdroit/AyantDroitRequestTest.java
new file mode 100644
index 0000000..6c3162b
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/ayantdroit/AyantDroitRequestTest.java
@@ -0,0 +1,53 @@
+package dev.lions.unionflow.server.api.dto.ayantdroit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.ayantdroit.LienParente;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class AyantDroitRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new AyantDroitRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ AyantDroitRequest req = new AyantDroitRequest();
+ req.setMembrePrincipalId("m-1");
+ req.setPrenom("Alice");
+ req.setNom("Dupont");
+ req.setDateNaissance(LocalDate.of(2000, 1, 15));
+ req.setSexe("F");
+ req.setPieceIdentite("CNI-123");
+ req.setLienParente(LienParente.CONJOINT);
+ req.setJustificatifLienId("doc-1");
+
+ assertThat(req.getMembrePrincipalId()).isEqualTo("m-1");
+ assertThat(req.getPrenom()).isEqualTo("Alice");
+ assertThat(req.getNom()).isEqualTo("Dupont");
+ assertThat(req.getDateNaissance()).isEqualTo(LocalDate.of(2000, 1, 15));
+ assertThat(req.getSexe()).isEqualTo("F");
+ assertThat(req.getLienParente()).isEqualTo(LienParente.CONJOINT);
+ }
+
+ @Test
+ void testBuilder() {
+ AyantDroitRequest req = AyantDroitRequest.builder()
+ .membrePrincipalId("m-2")
+ .prenom("Bob")
+ .lienParente(LienParente.ENFANT)
+ .build();
+ assertThat(req.getMembrePrincipalId()).isEqualTo("m-2");
+ assertThat(req.getLienParente()).isEqualTo(LienParente.ENFANT);
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ AyantDroitRequest r1 = AyantDroitRequest.builder().membrePrincipalId("x").prenom("A").build();
+ AyantDroitRequest r2 = AyantDroitRequest.builder().membrePrincipalId("x").prenom("A").build();
+ assertThat(r1).isEqualTo(r2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/ayantdroit/AyantDroitResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/ayantdroit/AyantDroitResponseTest.java
new file mode 100644
index 0000000..e9e9e15
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/ayantdroit/AyantDroitResponseTest.java
@@ -0,0 +1,48 @@
+package dev.lions.unionflow.server.api.dto.ayantdroit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.ayantdroit.LienParente;
+import dev.lions.unionflow.server.api.enums.ayantdroit.StatutAyantDroit;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class AyantDroitResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new AyantDroitResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ AyantDroitResponse resp = new AyantDroitResponse();
+ resp.setMembrePrincipalId("m-1");
+ resp.setNumeroCarteBeneficiaire("CB-001");
+ resp.setPrenom("Alice");
+ resp.setNom("Dupont");
+ resp.setDateNaissance(LocalDate.of(2000, 1, 1));
+ resp.setAgeActuel(26);
+ resp.setLienParente(LienParente.ENFANT);
+ resp.setPourcentageCouvertureSante(new BigDecimal("80.0"));
+ resp.setStatut(StatutAyantDroit.ACTIF);
+
+ assertThat(resp.getMembrePrincipalId()).isEqualTo("m-1");
+ assertThat(resp.getNumeroCarteBeneficiaire()).isEqualTo("CB-001");
+ assertThat(resp.getPrenom()).isEqualTo("Alice");
+ assertThat(resp.getAgeActuel()).isEqualTo(26);
+ assertThat(resp.getLienParente()).isEqualTo(LienParente.ENFANT);
+ assertThat(resp.getStatut()).isEqualTo(StatutAyantDroit.ACTIF);
+ }
+
+ @Test
+ void testBuilder() {
+ AyantDroitResponse resp = AyantDroitResponse.builder()
+ .prenom("Bob")
+ .statut(StatutAyantDroit.INACTIF)
+ .build();
+ assertThat(resp.getPrenom()).isEqualTo("Bob");
+ assertThat(resp.getStatut()).isEqualTo(StatutAyantDroit.INACTIF);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/CreateBackupRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/CreateBackupRequestTest.java
new file mode 100644
index 0000000..1431b8b
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/CreateBackupRequestTest.java
@@ -0,0 +1,53 @@
+package dev.lions.unionflow.server.api.dto.backup.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests CreateBackupRequest")
+class CreateBackupRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CreateBackupRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CreateBackupRequest req = new CreateBackupRequest();
+ req.setName("backup-2026");
+ req.setDescription("Full backup");
+ req.setType("MANUAL");
+ req.setIncludeDatabase(true);
+ req.setIncludeFiles(false);
+ req.setIncludeConfiguration(true);
+
+ assertThat(req.getName()).isEqualTo("backup-2026");
+ assertThat(req.getDescription()).isEqualTo("Full backup");
+ assertThat(req.getType()).isEqualTo("MANUAL");
+ assertThat(req.getIncludeDatabase()).isTrue();
+ assertThat(req.getIncludeFiles()).isFalse();
+ assertThat(req.getIncludeConfiguration()).isTrue();
+ }
+
+ @Test
+ void testBuilder() {
+ CreateBackupRequest req = CreateBackupRequest.builder()
+ .name("test")
+ .type("AUTO")
+ .includeDatabase(true)
+ .build();
+ assertThat(req.getName()).isEqualTo("test");
+ assertThat(req.getType()).isEqualTo("AUTO");
+ assertThat(req.getIncludeDatabase()).isTrue();
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ CreateBackupRequest r1 = CreateBackupRequest.builder().name("x").build();
+ CreateBackupRequest r2 = CreateBackupRequest.builder().name("x").build();
+ assertThat(r1).isEqualTo(r2);
+ assertThat(r1.hashCode()).isEqualTo(r2.hashCode());
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/RestoreBackupRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/RestoreBackupRequestTest.java
new file mode 100644
index 0000000..c80c70f
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/RestoreBackupRequestTest.java
@@ -0,0 +1,55 @@
+package dev.lions.unionflow.server.api.dto.backup.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests RestoreBackupRequest")
+class RestoreBackupRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new RestoreBackupRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID id = UUID.randomUUID();
+ RestoreBackupRequest req = new RestoreBackupRequest();
+ req.setBackupId(id);
+ req.setRestoreDatabase(true);
+ req.setRestoreFiles(false);
+ req.setRestoreConfiguration(true);
+ req.setCreateRestorePoint(false);
+
+ assertThat(req.getBackupId()).isEqualTo(id);
+ assertThat(req.getRestoreDatabase()).isTrue();
+ assertThat(req.getRestoreFiles()).isFalse();
+ assertThat(req.getRestoreConfiguration()).isTrue();
+ assertThat(req.getCreateRestorePoint()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ UUID id = UUID.randomUUID();
+ RestoreBackupRequest req = RestoreBackupRequest.builder()
+ .backupId(id)
+ .restoreDatabase(true)
+ .createRestorePoint(true)
+ .build();
+ assertThat(req.getBackupId()).isEqualTo(id);
+ assertThat(req.getRestoreDatabase()).isTrue();
+ assertThat(req.getCreateRestorePoint()).isTrue();
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ UUID id = UUID.randomUUID();
+ RestoreBackupRequest r1 = RestoreBackupRequest.builder().backupId(id).build();
+ RestoreBackupRequest r2 = RestoreBackupRequest.builder().backupId(id).build();
+ assertThat(r1).isEqualTo(r2);
+ assertThat(r1.hashCode()).isEqualTo(r2.hashCode());
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/UpdateBackupConfigRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/UpdateBackupConfigRequestTest.java
new file mode 100644
index 0000000..1ec627c
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/backup/request/UpdateBackupConfigRequestTest.java
@@ -0,0 +1,49 @@
+package dev.lions.unionflow.server.api.dto.backup.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests UpdateBackupConfigRequest")
+class UpdateBackupConfigRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new UpdateBackupConfigRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UpdateBackupConfigRequest req = new UpdateBackupConfigRequest();
+ req.setAutoBackupEnabled(true);
+ req.setFrequency("DAILY");
+ req.setRetention("30 jours");
+ req.setRetentionDays(30);
+ req.setBackupTime("02:00");
+ req.setIncludeDatabase(true);
+ req.setIncludeFiles(true);
+ req.setIncludeConfiguration(false);
+
+ assertThat(req.getAutoBackupEnabled()).isTrue();
+ assertThat(req.getFrequency()).isEqualTo("DAILY");
+ assertThat(req.getRetention()).isEqualTo("30 jours");
+ assertThat(req.getRetentionDays()).isEqualTo(30);
+ assertThat(req.getBackupTime()).isEqualTo("02:00");
+ assertThat(req.getIncludeDatabase()).isTrue();
+ assertThat(req.getIncludeFiles()).isTrue();
+ assertThat(req.getIncludeConfiguration()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ UpdateBackupConfigRequest req = UpdateBackupConfigRequest.builder()
+ .autoBackupEnabled(false)
+ .frequency("WEEKLY")
+ .retentionDays(90)
+ .build();
+ assertThat(req.getAutoBackupEnabled()).isFalse();
+ assertThat(req.getFrequency()).isEqualTo("WEEKLY");
+ assertThat(req.getRetentionDays()).isEqualTo(90);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/backup/response/BackupConfigResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/backup/response/BackupConfigResponseTest.java
new file mode 100644
index 0000000..5ef9a94
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/backup/response/BackupConfigResponseTest.java
@@ -0,0 +1,59 @@
+package dev.lions.unionflow.server.api.dto.backup.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests BackupConfigResponse")
+class BackupConfigResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new BackupConfigResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime last = LocalDateTime.now().minusDays(1);
+ LocalDateTime next = LocalDateTime.now().plusDays(1);
+ BackupConfigResponse resp = new BackupConfigResponse();
+ resp.setAutoBackupEnabled(true);
+ resp.setFrequency("DAILY");
+ resp.setRetention("7 jours");
+ resp.setRetentionDays(7);
+ resp.setBackupTime("03:00");
+ resp.setIncludeDatabase(true);
+ resp.setIncludeFiles(false);
+ resp.setIncludeConfiguration(true);
+ resp.setLastBackup(last);
+ resp.setNextScheduledBackup(next);
+ resp.setTotalBackups(5);
+ resp.setTotalSizeBytes(1024L);
+ resp.setTotalSizeFormatted("1 KB");
+
+ assertThat(resp.getAutoBackupEnabled()).isTrue();
+ assertThat(resp.getFrequency()).isEqualTo("DAILY");
+ assertThat(resp.getRetention()).isEqualTo("7 jours");
+ assertThat(resp.getRetentionDays()).isEqualTo(7);
+ assertThat(resp.getBackupTime()).isEqualTo("03:00");
+ assertThat(resp.getIncludeDatabase()).isTrue();
+ assertThat(resp.getIncludeFiles()).isFalse();
+ assertThat(resp.getLastBackup()).isEqualTo(last);
+ assertThat(resp.getNextScheduledBackup()).isEqualTo(next);
+ assertThat(resp.getTotalBackups()).isEqualTo(5);
+ assertThat(resp.getTotalSizeBytes()).isEqualTo(1024L);
+ assertThat(resp.getTotalSizeFormatted()).isEqualTo("1 KB");
+ }
+
+ @Test
+ void testBuilder() {
+ BackupConfigResponse resp = BackupConfigResponse.builder()
+ .frequency("HOURLY")
+ .totalBackups(10)
+ .build();
+ assertThat(resp.getFrequency()).isEqualTo("HOURLY");
+ assertThat(resp.getTotalBackups()).isEqualTo(10);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/backup/response/BackupResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/backup/response/BackupResponseTest.java
new file mode 100644
index 0000000..e2101b0
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/backup/response/BackupResponseTest.java
@@ -0,0 +1,68 @@
+package dev.lions.unionflow.server.api.dto.backup.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests BackupResponse")
+class BackupResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new BackupResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID id = UUID.randomUUID();
+ LocalDateTime created = LocalDateTime.now();
+ BackupResponse resp = new BackupResponse();
+ resp.setId(id);
+ resp.setName("full-backup");
+ resp.setDescription("Full backup");
+ resp.setType("MANUAL");
+ resp.setSizeBytes(2048L);
+ resp.setSizeFormatted("2 KB");
+ resp.setStatus("COMPLETED");
+ resp.setCreatedAt(created);
+ resp.setCreatedBy("admin");
+ resp.setIncludesDatabase(true);
+ resp.setIncludesFiles(false);
+ resp.setIncludesConfiguration(true);
+ resp.setFilePath("/backups/test.tar.gz");
+ resp.setErrorMessage(null);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getName()).isEqualTo("full-backup");
+ assertThat(resp.getType()).isEqualTo("MANUAL");
+ assertThat(resp.getSizeBytes()).isEqualTo(2048L);
+ assertThat(resp.getSizeFormatted()).isEqualTo("2 KB");
+ assertThat(resp.getStatus()).isEqualTo("COMPLETED");
+ assertThat(resp.getCreatedAt()).isEqualTo(created);
+ assertThat(resp.getCreatedBy()).isEqualTo("admin");
+ assertThat(resp.getIncludesDatabase()).isTrue();
+ assertThat(resp.getIncludesFiles()).isFalse();
+ assertThat(resp.getFilePath()).isEqualTo("/backups/test.tar.gz");
+ assertThat(resp.getErrorMessage()).isNull();
+ }
+
+ @Test
+ void testBuilder() {
+ BackupResponse resp = BackupResponse.builder()
+ .name("test")
+ .status("PENDING")
+ .build();
+ assertThat(resp.getName()).isEqualTo("test");
+ assertThat(resp.getStatus()).isEqualTo("PENDING");
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ BackupResponse r1 = BackupResponse.builder().name("a").build();
+ BackupResponse r2 = BackupResponse.builder().name("a").build();
+ assertThat(r1).isEqualTo(r2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/collectefonds/CampagneCollecteResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/collectefonds/CampagneCollecteResponseTest.java
new file mode 100644
index 0000000..47c6e50
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/collectefonds/CampagneCollecteResponseTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.collectefonds;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.collectefonds.StatutCampagneCollecte;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class CampagneCollecteResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CampagneCollecteResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CampagneCollecteResponse resp = new CampagneCollecteResponse();
+ resp.setOrganisationId("org-1");
+ resp.setTitre("Collecte Ramadan");
+ resp.setCourteDescription("Aide aux familles");
+ resp.setObjectifFinancier(new BigDecimal("1000000"));
+ resp.setMontantCollecteActuel(new BigDecimal("500000"));
+ resp.setNombreDonateurs(50);
+ resp.setStatut(StatutCampagneCollecte.EN_COURS);
+ resp.setEstPublique(true);
+
+ assertThat(resp.getOrganisationId()).isEqualTo("org-1");
+ assertThat(resp.getTitre()).isEqualTo("Collecte Ramadan");
+ assertThat(resp.getObjectifFinancier()).isEqualByComparingTo("1000000");
+ assertThat(resp.getMontantCollecteActuel()).isEqualByComparingTo("500000");
+ assertThat(resp.getNombreDonateurs()).isEqualTo(50);
+ assertThat(resp.getStatut()).isEqualTo(StatutCampagneCollecte.EN_COURS);
+ assertThat(resp.getEstPublique()).isTrue();
+ }
+
+ @Test
+ void testBuilder() {
+ CampagneCollecteResponse resp = CampagneCollecteResponse.builder()
+ .titre("Test")
+ .statut(StatutCampagneCollecte.ATTEINTE)
+ .build();
+ assertThat(resp.getTitre()).isEqualTo("Test");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/collectefonds/ContributionCollecteDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/collectefonds/ContributionCollecteDTOTest.java
new file mode 100644
index 0000000..6c55eed
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/collectefonds/ContributionCollecteDTOTest.java
@@ -0,0 +1,41 @@
+package dev.lions.unionflow.server.api.dto.collectefonds;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class ContributionCollecteDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ContributionCollecteDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ContributionCollecteDTO dto = new ContributionCollecteDTO();
+ dto.setCampagneId("camp-1");
+ dto.setMembreDonateurId("m-1");
+ dto.setAliasDonateur("Donateur Anonyme");
+ dto.setEstAnonyme(true);
+ dto.setMontantSoutien(new BigDecimal("10000"));
+ dto.setMessageSoutien("Bon courage");
+
+ assertThat(dto.getCampagneId()).isEqualTo("camp-1");
+ assertThat(dto.getMembreDonateurId()).isEqualTo("m-1");
+ assertThat(dto.getAliasDonateur()).isEqualTo("Donateur Anonyme");
+ assertThat(dto.getEstAnonyme()).isTrue();
+ assertThat(dto.getMontantSoutien()).isEqualByComparingTo("10000");
+ assertThat(dto.getMessageSoutien()).isEqualTo("Bon courage");
+ }
+
+ @Test
+ void testBuilder() {
+ ContributionCollecteDTO dto = ContributionCollecteDTO.builder()
+ .campagneId("c-1")
+ .montantSoutien(new BigDecimal("5000"))
+ .build();
+ assertThat(dto.getCampagneId()).isEqualTo("c-1");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/CompteComptableResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/CompteComptableResponseTest.java
new file mode 100644
index 0000000..90506ff
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/CompteComptableResponseTest.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.comptabilite.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.comptabilite.TypeCompteComptable;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class CompteComptableResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CompteComptableResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CompteComptableResponse resp = new CompteComptableResponse();
+ resp.setNumeroCompte("401000");
+ resp.setLibelle("Fournisseurs");
+ resp.setTypeCompte(TypeCompteComptable.PASSIF);
+ resp.setClasseComptable(4);
+ resp.setSoldeInitial(new BigDecimal("0"));
+ resp.setSoldeActuel(new BigDecimal("500000"));
+ resp.setCompteCollectif(true);
+ resp.setCompteAnalytique(false);
+ resp.setDescription("Compte fournisseurs");
+
+ assertThat(resp.getNumeroCompte()).isEqualTo("401000");
+ assertThat(resp.getLibelle()).isEqualTo("Fournisseurs");
+ assertThat(resp.getTypeCompte()).isEqualTo(TypeCompteComptable.PASSIF);
+ assertThat(resp.getClasseComptable()).isEqualTo(4);
+ assertThat(resp.getSoldeActuel()).isEqualByComparingTo("500000");
+ assertThat(resp.getCompteCollectif()).isTrue();
+ assertThat(resp.getCompteAnalytique()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ CompteComptableResponse resp = CompteComptableResponse.builder()
+ .numeroCompte("501000")
+ .typeCompte(TypeCompteComptable.ACTIF)
+ .build();
+ assertThat(resp.getNumeroCompte()).isEqualTo("501000");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/EcritureComptableResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/EcritureComptableResponseTest.java
new file mode 100644
index 0000000..c7b2c63
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/EcritureComptableResponseTest.java
@@ -0,0 +1,48 @@
+package dev.lions.unionflow.server.api.dto.comptabilite.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class EcritureComptableResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new EcritureComptableResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID journalId = UUID.randomUUID();
+ EcritureComptableResponse resp = new EcritureComptableResponse();
+ resp.setNumeroPiece("PIECE-001");
+ resp.setDateEcriture(LocalDate.of(2026, 1, 15));
+ resp.setLibelle("Cotisation membre");
+ resp.setReference("REF-001");
+ resp.setPointe(false);
+ resp.setMontantDebit(new BigDecimal("50000"));
+ resp.setMontantCredit(new BigDecimal("50000"));
+ resp.setJournalId(journalId);
+ resp.setLignes(List.of());
+
+ assertThat(resp.getNumeroPiece()).isEqualTo("PIECE-001");
+ assertThat(resp.getDateEcriture()).isEqualTo(LocalDate.of(2026, 1, 15));
+ assertThat(resp.getLibelle()).isEqualTo("Cotisation membre");
+ assertThat(resp.getMontantDebit()).isEqualByComparingTo("50000");
+ assertThat(resp.getJournalId()).isEqualTo(journalId);
+ assertThat(resp.getLignes()).isEmpty();
+ }
+
+ @Test
+ void testBuilder() {
+ EcritureComptableResponse resp = EcritureComptableResponse.builder()
+ .numeroPiece("P-002")
+ .montantDebit(new BigDecimal("1000"))
+ .build();
+ assertThat(resp.getNumeroPiece()).isEqualTo("P-002");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/JournalComptableResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/JournalComptableResponseTest.java
new file mode 100644
index 0000000..f539860
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/JournalComptableResponseTest.java
@@ -0,0 +1,41 @@
+package dev.lions.unionflow.server.api.dto.comptabilite.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class JournalComptableResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new JournalComptableResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ JournalComptableResponse resp = new JournalComptableResponse();
+ resp.setCode("JC-001");
+ resp.setLibelle("Journal Caisse");
+ resp.setTypeJournal(TypeJournalComptable.CAISSE);
+ resp.setDateDebut(LocalDate.of(2026, 1, 1));
+ resp.setDateFin(LocalDate.of(2026, 12, 31));
+ resp.setStatut("OUVERT");
+ resp.setDescription("Journal de caisse principale");
+
+ assertThat(resp.getCode()).isEqualTo("JC-001");
+ assertThat(resp.getLibelle()).isEqualTo("Journal Caisse");
+ assertThat(resp.getTypeJournal()).isEqualTo(TypeJournalComptable.CAISSE);
+ assertThat(resp.getStatut()).isEqualTo("OUVERT");
+ }
+
+ @Test
+ void testBuilder() {
+ JournalComptableResponse resp = JournalComptableResponse.builder()
+ .code("JB-001")
+ .typeJournal(TypeJournalComptable.BANQUE)
+ .build();
+ assertThat(resp.getCode()).isEqualTo("JB-001");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/LigneEcritureResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/LigneEcritureResponseTest.java
new file mode 100644
index 0000000..9580ab5
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/comptabilite/response/LigneEcritureResponseTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.comptabilite.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class LigneEcritureResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new LigneEcritureResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID ecritureId = UUID.randomUUID();
+ UUID compteId = UUID.randomUUID();
+ LigneEcritureResponse resp = new LigneEcritureResponse();
+ resp.setNumeroLigne(1);
+ resp.setMontantDebit(new BigDecimal("25000"));
+ resp.setMontantCredit(BigDecimal.ZERO);
+ resp.setLibelle("Ligne débit");
+ resp.setReference("REF-L1");
+ resp.setEcritureId(ecritureId);
+ resp.setCompteComptableId(compteId);
+
+ assertThat(resp.getNumeroLigne()).isEqualTo(1);
+ assertThat(resp.getMontantDebit()).isEqualByComparingTo("25000");
+ assertThat(resp.getLibelle()).isEqualTo("Ligne débit");
+ assertThat(resp.getEcritureId()).isEqualTo(ecritureId);
+ assertThat(resp.getCompteComptableId()).isEqualTo(compteId);
+ }
+
+ @Test
+ void testBuilder() {
+ LigneEcritureResponse resp = LigneEcritureResponse.builder()
+ .numeroLigne(2)
+ .montantCredit(new BigDecimal("25000"))
+ .build();
+ assertThat(resp.getNumeroLigne()).isEqualTo(2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/config/request/ParametresLcbFtRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/config/request/ParametresLcbFtRequestTest.java
new file mode 100644
index 0000000..9df90b7
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/config/request/ParametresLcbFtRequestTest.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.config.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class ParametresLcbFtRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ParametresLcbFtRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ParametresLcbFtRequest req = new ParametresLcbFtRequest();
+ req.setOrganisationId("org-1");
+ req.setMontantSeuilJustification(new BigDecimal("500000"));
+ req.setMontantSeuilValidationManuelle(new BigDecimal("1000000"));
+ req.setCodeDevise("XOF");
+ req.setNotes("Paramètres UEMOA");
+
+ assertThat(req.getOrganisationId()).isEqualTo("org-1");
+ assertThat(req.getMontantSeuilJustification()).isEqualByComparingTo("500000");
+ assertThat(req.getMontantSeuilValidationManuelle()).isEqualByComparingTo("1000000");
+ assertThat(req.getCodeDevise()).isEqualTo("XOF");
+ assertThat(req.getNotes()).isEqualTo("Paramètres UEMOA");
+ }
+
+ @Test
+ void testBuilder() {
+ ParametresLcbFtRequest req = ParametresLcbFtRequest.builder()
+ .codeDevise("XOF")
+ .montantSeuilJustification(new BigDecimal("300000"))
+ .build();
+ assertThat(req.getCodeDevise()).isEqualTo("XOF");
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ ParametresLcbFtRequest r1 = ParametresLcbFtRequest.builder().codeDevise("XOF").build();
+ ParametresLcbFtRequest r2 = ParametresLcbFtRequest.builder().codeDevise("XOF").build();
+ assertThat(r1).isEqualTo(r2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/config/response/ConfigurationResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/config/response/ConfigurationResponseTest.java
new file mode 100644
index 0000000..41b3a84
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/config/response/ConfigurationResponseTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.config.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+class ConfigurationResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ConfigurationResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ConfigurationResponse resp = new ConfigurationResponse();
+ resp.setCle("smtp.host");
+ resp.setValeur("mail.example.com");
+ resp.setType("STRING");
+ resp.setCategorie("EMAIL");
+ resp.setDescription("Serveur SMTP");
+ resp.setModifiable(true);
+ resp.setVisible(true);
+ resp.setMetadonnees(Map.of("env", "prod"));
+
+ assertThat(resp.getCle()).isEqualTo("smtp.host");
+ assertThat(resp.getValeur()).isEqualTo("mail.example.com");
+ assertThat(resp.getType()).isEqualTo("STRING");
+ assertThat(resp.getCategorie()).isEqualTo("EMAIL");
+ assertThat(resp.getModifiable()).isTrue();
+ assertThat(resp.getMetadonnees()).containsEntry("env", "prod");
+ }
+
+ @Test
+ void testBuilder() {
+ ConfigurationResponse resp = ConfigurationResponse.builder()
+ .cle("key1")
+ .valeur("val1")
+ .build();
+ assertThat(resp.getCle()).isEqualTo("key1");
+ assertThat(resp.getValeur()).isEqualTo("val1");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/config/response/ParametresLcbFtResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/config/response/ParametresLcbFtResponseTest.java
new file mode 100644
index 0000000..dc573c2
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/config/response/ParametresLcbFtResponseTest.java
@@ -0,0 +1,42 @@
+package dev.lions.unionflow.server.api.dto.config.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class ParametresLcbFtResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ParametresLcbFtResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ParametresLcbFtResponse resp = new ParametresLcbFtResponse();
+ resp.setOrganisationId("org-1");
+ resp.setOrganisationNom("Association Test");
+ resp.setMontantSeuilJustification(new BigDecimal("500000"));
+ resp.setMontantSeuilValidationManuelle(new BigDecimal("1000000"));
+ resp.setCodeDevise("XOF");
+ resp.setNotes("Notes");
+ resp.setEstParametrePlateforme(false);
+
+ assertThat(resp.getOrganisationId()).isEqualTo("org-1");
+ assertThat(resp.getOrganisationNom()).isEqualTo("Association Test");
+ assertThat(resp.getMontantSeuilJustification()).isEqualByComparingTo("500000");
+ assertThat(resp.getCodeDevise()).isEqualTo("XOF");
+ assertThat(resp.getEstParametrePlateforme()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ ParametresLcbFtResponse resp = ParametresLcbFtResponse.builder()
+ .codeDevise("XOF")
+ .estParametrePlateforme(true)
+ .build();
+ assertThat(resp.getCodeDevise()).isEqualTo("XOF");
+ assertThat(resp.getEstParametrePlateforme()).isTrue();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/culte/DonReligieuxDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/culte/DonReligieuxDTOTest.java
new file mode 100644
index 0000000..5ce5e1e
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/culte/DonReligieuxDTOTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.culte;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.culte.TypeDonReligieux;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class DonReligieuxDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new DonReligieuxDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime date = LocalDateTime.now();
+ DonReligieuxDTO dto = new DonReligieuxDTO();
+ dto.setInstitutionId("mosque-1");
+ dto.setFideleId("m-1");
+ dto.setTypeDon(TypeDonReligieux.ZAKAT);
+ dto.setMontant(new BigDecimal("25000"));
+ dto.setDateEncaissement(date);
+ dto.setPeriodeOuNatureAssociee("Ramadan 2026");
+
+ assertThat(dto.getInstitutionId()).isEqualTo("mosque-1");
+ assertThat(dto.getFideleId()).isEqualTo("m-1");
+ assertThat(dto.getTypeDon()).isEqualTo(TypeDonReligieux.ZAKAT);
+ assertThat(dto.getMontant()).isEqualByComparingTo("25000");
+ assertThat(dto.getDateEncaissement()).isEqualTo(date);
+ assertThat(dto.getPeriodeOuNatureAssociee()).isEqualTo("Ramadan 2026");
+ }
+
+ @Test
+ void testBuilder() {
+ DonReligieuxDTO dto = DonReligieuxDTO.builder()
+ .institutionId("church-1")
+ .typeDon(TypeDonReligieux.DIME)
+ .build();
+ assertThat(dto.getInstitutionId()).isEqualTo("church-1");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/dashboard/MonthlyStatDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/dashboard/MonthlyStatDTOTest.java
new file mode 100644
index 0000000..43bcfa8
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/dashboard/MonthlyStatDTOTest.java
@@ -0,0 +1,54 @@
+package dev.lions.unionflow.server.api.dto.dashboard;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class MonthlyStatDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new MonthlyStatDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ MonthlyStatDTO dto = new MonthlyStatDTO();
+ dto.setMonth("2026-01");
+ dto.setTotalMembers(150);
+ dto.setActiveMembers(120);
+ dto.setContributionAmount(500000.0);
+ dto.setEventsCount(3);
+ dto.setEngagementRate(80.0);
+ dto.setNewMembers(10);
+ dto.setContributionsCount(100);
+
+ assertThat(dto.getMonth()).isEqualTo("2026-01");
+ assertThat(dto.getTotalMembers()).isEqualTo(150);
+ assertThat(dto.getActiveMembers()).isEqualTo(120);
+ assertThat(dto.getContributionAmount()).isEqualTo(500000.0);
+ assertThat(dto.getEventsCount()).isEqualTo(3);
+ assertThat(dto.getEngagementRate()).isEqualTo(80.0);
+ assertThat(dto.getNewMembers()).isEqualTo(10);
+ assertThat(dto.getContributionsCount()).isEqualTo(100);
+ }
+
+ @Test
+ void testBuilder() {
+ MonthlyStatDTO dto = MonthlyStatDTO.builder()
+ .month("2026-03")
+ .totalMembers(200)
+ .contributionAmount(750000.0)
+ .build();
+ assertThat(dto.getMonth()).isEqualTo("2026-03");
+ assertThat(dto.getTotalMembers()).isEqualTo(200);
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ MonthlyStatDTO d1 = MonthlyStatDTO.builder().month("2026-01").totalMembers(100).build();
+ MonthlyStatDTO d2 = MonthlyStatDTO.builder().month("2026-01").totalMembers(100).build();
+ assertThat(d1).isEqualTo(d2);
+ assertThat(d1.hashCode()).isEqualTo(d2.hashCode());
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/document/response/DocumentResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/document/response/DocumentResponseTest.java
new file mode 100644
index 0000000..66c70bb
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/document/response/DocumentResponseTest.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.document.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.document.TypeDocument;
+import org.junit.jupiter.api.Test;
+
+class DocumentResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new DocumentResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ DocumentResponse resp = new DocumentResponse();
+ resp.setNomFichier("contrat.pdf");
+ resp.setNomOriginal("contrat_original.pdf");
+ resp.setCheminStockage("/storage/docs/contrat.pdf");
+ resp.setTypeMime("application/pdf");
+ resp.setTailleOctets(204800L);
+ resp.setTypeDocument(TypeDocument.CONTRAT);
+ resp.setHashMd5("abc123");
+ resp.setHashSha256("def456");
+ resp.setDescription("Contrat membre");
+ resp.setNombreTelechargements(5);
+ resp.setTailleFormatee("200 KB");
+
+ assertThat(resp.getNomFichier()).isEqualTo("contrat.pdf");
+ assertThat(resp.getTypeMime()).isEqualTo("application/pdf");
+ assertThat(resp.getTailleOctets()).isEqualTo(204800L);
+ assertThat(resp.getTypeDocument()).isEqualTo(TypeDocument.CONTRAT);
+ assertThat(resp.getNombreTelechargements()).isEqualTo(5);
+ assertThat(resp.getTailleFormatee()).isEqualTo("200 KB");
+ }
+
+ @Test
+ void testBuilder() {
+ DocumentResponse resp = DocumentResponse.builder()
+ .nomFichier("test.pdf")
+ .typeDocument(TypeDocument.PIECE_JUSTIFICATIVE)
+ .build();
+ assertThat(resp.getNomFichier()).isEqualTo("test.pdf");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/document/response/PieceJointeResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/document/response/PieceJointeResponseTest.java
new file mode 100644
index 0000000..b016336
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/document/response/PieceJointeResponseTest.java
@@ -0,0 +1,43 @@
+package dev.lions.unionflow.server.api.dto.document.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class PieceJointeResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new PieceJointeResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID docId = UUID.randomUUID();
+ UUID entiteId = UUID.randomUUID();
+ PieceJointeResponse resp = new PieceJointeResponse();
+ resp.setOrdre(1);
+ resp.setLibelle("Pièce jointe 1");
+ resp.setCommentaire("Document obligatoire");
+ resp.setDocumentId(docId);
+ resp.setTypeEntiteRattachee("COTISATION");
+ resp.setEntiteRattacheeId(entiteId);
+
+ assertThat(resp.getOrdre()).isEqualTo(1);
+ assertThat(resp.getLibelle()).isEqualTo("Pièce jointe 1");
+ assertThat(resp.getCommentaire()).isEqualTo("Document obligatoire");
+ assertThat(resp.getDocumentId()).isEqualTo(docId);
+ assertThat(resp.getTypeEntiteRattachee()).isEqualTo("COTISATION");
+ assertThat(resp.getEntiteRattacheeId()).isEqualTo(entiteId);
+ }
+
+ @Test
+ void testBuilder() {
+ PieceJointeResponse resp = PieceJointeResponse.builder()
+ .ordre(2)
+ .libelle("Autre pièce")
+ .build();
+ assertThat(resp.getOrdre()).isEqualTo(2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/favoris/response/FavoriResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/favoris/response/FavoriResponseTest.java
new file mode 100644
index 0000000..3ea6d89
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/favoris/response/FavoriResponseTest.java
@@ -0,0 +1,47 @@
+package dev.lions.unionflow.server.api.dto.favoris.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class FavoriResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new FavoriResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID userId = UUID.randomUUID();
+ FavoriResponse resp = new FavoriResponse();
+ resp.setUtilisateurId(userId);
+ resp.setTypeFavori("PAGE");
+ resp.setTitre("Dashboard");
+ resp.setDescription("Tableau de bord principal");
+ resp.setUrl("/dashboard");
+ resp.setIcon("pi pi-home");
+ resp.setCouleur("#3B82F6");
+ resp.setCategorie("NAVIGATION");
+ resp.setOrdre(1);
+ resp.setNbVisites(42);
+ resp.setEstPlusUtilise(true);
+
+ assertThat(resp.getUtilisateurId()).isEqualTo(userId);
+ assertThat(resp.getTypeFavori()).isEqualTo("PAGE");
+ assertThat(resp.getTitre()).isEqualTo("Dashboard");
+ assertThat(resp.getUrl()).isEqualTo("/dashboard");
+ assertThat(resp.getNbVisites()).isEqualTo(42);
+ assertThat(resp.getEstPlusUtilise()).isTrue();
+ }
+
+ @Test
+ void testBuilder() {
+ FavoriResponse resp = FavoriResponse.builder()
+ .titre("Membres")
+ .url("/membres")
+ .build();
+ assertThat(resp.getTitre()).isEqualTo("Membres");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/ApproveTransactionRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/ApproveTransactionRequestTest.java
new file mode 100644
index 0000000..64aac2e
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/ApproveTransactionRequestTest.java
@@ -0,0 +1,41 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class ApproveTransactionRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ApproveTransactionRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ApproveTransactionRequest req = new ApproveTransactionRequest();
+ req.setComment("Approuvé après vérification");
+ assertThat(req.getComment()).isEqualTo("Approuvé après vérification");
+ }
+
+ @Test
+ void testBuilder() {
+ ApproveTransactionRequest req = ApproveTransactionRequest.builder()
+ .comment("OK")
+ .build();
+ assertThat(req.getComment()).isEqualTo("OK");
+ }
+
+ @Test
+ void testCommentNull() {
+ ApproveTransactionRequest req = new ApproveTransactionRequest();
+ assertThat(req.getComment()).isNull();
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ ApproveTransactionRequest r1 = ApproveTransactionRequest.builder().comment("c").build();
+ ApproveTransactionRequest r2 = ApproveTransactionRequest.builder().comment("c").build();
+ assertThat(r1).isEqualTo(r2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/CreateBudgetLineRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/CreateBudgetLineRequestTest.java
new file mode 100644
index 0000000..9efa5ab
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/CreateBudgetLineRequestTest.java
@@ -0,0 +1,38 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class CreateBudgetLineRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CreateBudgetLineRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CreateBudgetLineRequest req = new CreateBudgetLineRequest();
+ req.setCategory("CONTRIBUTIONS");
+ req.setName("Cotisations mensuelles");
+ req.setDescription("Lignes cotisations");
+ req.setAmountPlanned(new BigDecimal("500000"));
+ req.setNotes("Notes budget");
+
+ assertThat(req.getCategory()).isEqualTo("CONTRIBUTIONS");
+ assertThat(req.getName()).isEqualTo("Cotisations mensuelles");
+ assertThat(req.getAmountPlanned()).isEqualByComparingTo("500000");
+ assertThat(req.getNotes()).isEqualTo("Notes budget");
+ }
+
+ @Test
+ void testBuilder() {
+ CreateBudgetLineRequest req = CreateBudgetLineRequest.builder()
+ .category("SAVINGS")
+ .amountPlanned(new BigDecimal("100000"))
+ .build();
+ assertThat(req.getCategory()).isEqualTo("SAVINGS");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/CreateBudgetRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/CreateBudgetRequestTest.java
new file mode 100644
index 0000000..6e2380d
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/CreateBudgetRequestTest.java
@@ -0,0 +1,49 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.ArrayList;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class CreateBudgetRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ CreateBudgetRequest req = new CreateBudgetRequest();
+ assertThat(req).isNotNull();
+ assertThat(req.getLines()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID orgId = UUID.randomUUID();
+ CreateBudgetRequest req = new CreateBudgetRequest();
+ req.setName("Budget 2026");
+ req.setDescription("Budget annuel");
+ req.setOrganizationId(orgId);
+ req.setPeriod("ANNUAL");
+ req.setYear(2026);
+ req.setMonth(null);
+ req.setCurrency("XOF");
+ req.setLines(new ArrayList<>());
+
+ assertThat(req.getName()).isEqualTo("Budget 2026");
+ assertThat(req.getOrganizationId()).isEqualTo(orgId);
+ assertThat(req.getPeriod()).isEqualTo("ANNUAL");
+ assertThat(req.getYear()).isEqualTo(2026);
+ assertThat(req.getCurrency()).isEqualTo("XOF");
+ assertThat(req.getLines()).isEmpty();
+ }
+
+ @Test
+ void testBuilder() {
+ CreateBudgetRequest req = CreateBudgetRequest.builder()
+ .name("Budget Q1")
+ .period("QUARTERLY")
+ .year(2026)
+ .build();
+ assertThat(req.getName()).isEqualTo("Budget Q1");
+ assertThat(req.getLines()).isNotNull();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/RejectTransactionRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/RejectTransactionRequestTest.java
new file mode 100644
index 0000000..c63b664
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/request/RejectTransactionRequestTest.java
@@ -0,0 +1,35 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class RejectTransactionRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new RejectTransactionRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ RejectTransactionRequest req = new RejectTransactionRequest();
+ req.setReason("Montant incorrect, pièce justificative manquante");
+ assertThat(req.getReason()).isEqualTo("Montant incorrect, pièce justificative manquante");
+ }
+
+ @Test
+ void testBuilder() {
+ RejectTransactionRequest req = RejectTransactionRequest.builder()
+ .reason("Raison du rejet")
+ .build();
+ assertThat(req.getReason()).isEqualTo("Raison du rejet");
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ RejectTransactionRequest r1 = RejectTransactionRequest.builder().reason("r").build();
+ RejectTransactionRequest r2 = RejectTransactionRequest.builder().reason("r").build();
+ assertThat(r1).isEqualTo(r2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/ApproverActionResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/ApproverActionResponseTest.java
new file mode 100644
index 0000000..6cf0155
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/ApproverActionResponseTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class ApproverActionResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ApproverActionResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID id = UUID.randomUUID();
+ UUID approverId = UUID.randomUUID();
+ LocalDateTime decided = LocalDateTime.now();
+ ApproverActionResponse resp = new ApproverActionResponse();
+ resp.setId(id);
+ resp.setApproverId(approverId);
+ resp.setApproverName("John Doe");
+ resp.setApproverRole("TRESORIER");
+ resp.setDecision("APPROVED");
+ resp.setComment("OK");
+ resp.setDecidedAt(decided);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getApproverId()).isEqualTo(approverId);
+ assertThat(resp.getApproverName()).isEqualTo("John Doe");
+ assertThat(resp.getDecision()).isEqualTo("APPROVED");
+ assertThat(resp.getDecidedAt()).isEqualTo(decided);
+ }
+
+ @Test
+ void testBuilder() {
+ ApproverActionResponse resp = ApproverActionResponse.builder()
+ .decision("REJECTED")
+ .comment("Insufficient funds")
+ .build();
+ assertThat(resp.getDecision()).isEqualTo("REJECTED");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/BudgetLineResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/BudgetLineResponseTest.java
new file mode 100644
index 0000000..6659615
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/BudgetLineResponseTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class BudgetLineResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new BudgetLineResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID id = UUID.randomUUID();
+ BudgetLineResponse resp = new BudgetLineResponse();
+ resp.setId(id);
+ resp.setCategory("CONTRIBUTIONS");
+ resp.setName("Cotisations");
+ resp.setAmountPlanned(new BigDecimal("500000"));
+ resp.setAmountRealized(new BigDecimal("480000"));
+ resp.setRealizationRate(96.0);
+ resp.setVariance(new BigDecimal("20000"));
+ resp.setIsOverBudget(false);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getCategory()).isEqualTo("CONTRIBUTIONS");
+ assertThat(resp.getAmountPlanned()).isEqualByComparingTo("500000");
+ assertThat(resp.getAmountRealized()).isEqualByComparingTo("480000");
+ assertThat(resp.getRealizationRate()).isEqualTo(96.0);
+ assertThat(resp.getIsOverBudget()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ BudgetLineResponse resp = BudgetLineResponse.builder()
+ .category("SAVINGS")
+ .amountPlanned(new BigDecimal("100000"))
+ .build();
+ assertThat(resp.getCategory()).isEqualTo("SAVINGS");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/BudgetResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/BudgetResponseTest.java
new file mode 100644
index 0000000..77967f4
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/BudgetResponseTest.java
@@ -0,0 +1,56 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.response;
+
+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.Test;
+
+class BudgetResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ BudgetResponse resp = new BudgetResponse();
+ assertThat(resp).isNotNull();
+ assertThat(resp.getLines()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID id = UUID.randomUUID();
+ UUID orgId = UUID.randomUUID();
+ BudgetResponse resp = new BudgetResponse();
+ resp.setId(id);
+ resp.setName("Budget 2026");
+ resp.setOrganizationId(orgId);
+ resp.setPeriod("ANNUAL");
+ resp.setYear(2026);
+ resp.setStatus("ACTIVE");
+ resp.setTotalPlanned(new BigDecimal("1000000"));
+ resp.setTotalRealized(new BigDecimal("950000"));
+ resp.setCurrency("XOF");
+ resp.setRealizationRate(95.0);
+ resp.setIsOverBudget(false);
+ resp.setIsActive(true);
+ resp.setStartDate(LocalDate.of(2026, 1, 1));
+ resp.setEndDate(LocalDate.of(2026, 12, 31));
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getName()).isEqualTo("Budget 2026");
+ assertThat(resp.getTotalPlanned()).isEqualByComparingTo("1000000");
+ assertThat(resp.getIsActive()).isTrue();
+ }
+
+ @Test
+ void testBuilder() {
+ BudgetResponse resp = BudgetResponse.builder()
+ .name("Budget Q1")
+ .status("DRAFT")
+ .currency("XOF")
+ .build();
+ assertThat(resp.getName()).isEqualTo("Budget Q1");
+ assertThat(resp.getLines()).isNotNull();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/TransactionApprovalResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/TransactionApprovalResponseTest.java
new file mode 100644
index 0000000..566ceb1
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/finance_workflow/response/TransactionApprovalResponseTest.java
@@ -0,0 +1,53 @@
+package dev.lions.unionflow.server.api.dto.finance_workflow.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class TransactionApprovalResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ TransactionApprovalResponse resp = new TransactionApprovalResponse();
+ assertThat(resp).isNotNull();
+ assertThat(resp.getApprovers()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID id = UUID.randomUUID();
+ UUID txId = UUID.randomUUID();
+ TransactionApprovalResponse resp = new TransactionApprovalResponse();
+ resp.setId(id);
+ resp.setTransactionId(txId);
+ resp.setTransactionType("CONTRIBUTION");
+ resp.setAmount(new BigDecimal("50000"));
+ resp.setCurrency("XOF");
+ resp.setRequiredLevel("LEVEL1");
+ resp.setStatus("PENDING");
+ resp.setApprovalCount(1);
+ resp.setRequiredApprovals(2);
+ resp.setHasAllApprovals(false);
+ resp.setIsPending(true);
+ resp.setIsCompleted(false);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getTransactionType()).isEqualTo("CONTRIBUTION");
+ assertThat(resp.getAmount()).isEqualByComparingTo("50000");
+ assertThat(resp.getStatus()).isEqualTo("PENDING");
+ assertThat(resp.getHasAllApprovals()).isFalse();
+ assertThat(resp.getIsPending()).isTrue();
+ }
+
+ @Test
+ void testBuilder() {
+ TransactionApprovalResponse resp = TransactionApprovalResponse.builder()
+ .status("APPROVED")
+ .currency("XOF")
+ .build();
+ assertThat(resp.getStatus()).isEqualTo("APPROVED");
+ assertThat(resp.getApprovers()).isNotNull();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/gouvernance/EchelonOrganigrammeDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/gouvernance/EchelonOrganigrammeDTOTest.java
new file mode 100644
index 0000000..659b3a1
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/gouvernance/EchelonOrganigrammeDTOTest.java
@@ -0,0 +1,38 @@
+package dev.lions.unionflow.server.api.dto.gouvernance;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.gouvernance.NiveauEchelon;
+import org.junit.jupiter.api.Test;
+
+class EchelonOrganigrammeDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new EchelonOrganigrammeDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ EchelonOrganigrammeDTO dto = new EchelonOrganigrammeDTO();
+ dto.setOrganisationId("org-1");
+ dto.setEchelonParentId("org-parent");
+ dto.setNiveau(NiveauEchelon.NATIONAL);
+ dto.setDesignation("Bureau National");
+ dto.setZoneGeographiqueOuDelegation("Sénégal");
+ assertThat(dto.getOrganisationId()).isEqualTo("org-1");
+ assertThat(dto.getEchelonParentId()).isEqualTo("org-parent");
+ assertThat(dto.getNiveau()).isEqualTo(NiveauEchelon.NATIONAL);
+ assertThat(dto.getDesignation()).isEqualTo("Bureau National");
+ assertThat(dto.getZoneGeographiqueOuDelegation()).isEqualTo("Sénégal");
+ }
+
+ @Test
+ void testBuilder() {
+ EchelonOrganigrammeDTO dto = EchelonOrganigrammeDTO.builder()
+ .designation("Section Dakar")
+ .niveau(NiveauEchelon.REGIONAL)
+ .build();
+ assertThat(dto.getDesignation()).isEqualTo("Section Dakar");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierRequestTest.java
new file mode 100644
index 0000000..9606da2
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierRequestTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.kyc;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.membre.TypePieceIdentite;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class KycDossierRequestTest {
+
+ @Test
+ void testBuilder() {
+ KycDossierRequest req = KycDossierRequest.builder()
+ .membreId("m-1")
+ .typePiece(TypePieceIdentite.CNI)
+ .numeroPiece("CNI-001")
+ .dateExpirationPiece(LocalDate.of(2030, 12, 31))
+ .justifDomicileFileId("file-1")
+ .pieceIdentiteRectoFileId("file-recto")
+ .pieceIdentiteVersoFileId("file-verso")
+ .notesValidateur("Dossier complet")
+ .estPep(false)
+ .nationalite("SN")
+ .build();
+
+ assertThat(req.getMembreId()).isEqualTo("m-1");
+ assertThat(req.getTypePiece()).isEqualTo(TypePieceIdentite.CNI);
+ assertThat(req.getNumeroPiece()).isEqualTo("CNI-001");
+ assertThat(req.getDateExpirationPiece()).isEqualTo(LocalDate.of(2030, 12, 31));
+ assertThat(req.getJustifDomicileFileId()).isEqualTo("file-1");
+ assertThat(req.getEstPep()).isFalse();
+ assertThat(req.getNationalite()).isEqualTo("SN");
+ }
+
+ @Test
+ void testBuilderMinimal() {
+ KycDossierRequest req = KycDossierRequest.builder()
+ .membreId("m-2")
+ .typePiece(TypePieceIdentite.PASSEPORT)
+ .numeroPiece("PASS-001")
+ .build();
+ assertThat(req.getMembreId()).isEqualTo("m-2");
+ assertThat(req.getTypePiece()).isEqualTo(TypePieceIdentite.PASSEPORT);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierResponseTest.java
new file mode 100644
index 0000000..b173dfa
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/kyc/KycDossierResponseTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.kyc;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.membre.NiveauRisqueKyc;
+import dev.lions.unionflow.server.api.enums.membre.StatutKyc;
+import dev.lions.unionflow.server.api.enums.membre.TypePieceIdentite;
+import java.time.LocalDate;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class KycDossierResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new KycDossierResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID membreId = UUID.randomUUID();
+ KycDossierResponse resp = new KycDossierResponse();
+ resp.setMembreId(membreId);
+ resp.setMembreNomComplet("Alice Dupont");
+ resp.setMembreEmail("alice@test.com");
+ resp.setTypePiece(TypePieceIdentite.CNI);
+ resp.setNumeroPiece("CNI-001");
+ resp.setDateExpirationPiece(LocalDate.of(2030, 12, 31));
+ resp.setStatut(StatutKyc.VERIFIE);
+ resp.setNiveauRisque(NiveauRisqueKyc.FAIBLE);
+ resp.setScoreRisque(15);
+ resp.setEstPep(false);
+ resp.setNationalite("SN");
+ resp.setAnneeReference(2026);
+
+ assertThat(resp.getMembreId()).isEqualTo(membreId);
+ assertThat(resp.getMembreNomComplet()).isEqualTo("Alice Dupont");
+ assertThat(resp.getTypePiece()).isEqualTo(TypePieceIdentite.CNI);
+ assertThat(resp.getStatut()).isEqualTo(StatutKyc.VERIFIE);
+ assertThat(resp.getNiveauRisque()).isEqualTo(NiveauRisqueKyc.FAIBLE);
+ assertThat(resp.getScoreRisque()).isEqualTo(15);
+ assertThat(resp.isEstPep()).isFalse();
+ assertThat(resp.getAnneeReference()).isEqualTo(2026);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/lcbft/AlerteLcbFtResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/lcbft/AlerteLcbFtResponseTest.java
new file mode 100644
index 0000000..a38e676
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/lcbft/AlerteLcbFtResponseTest.java
@@ -0,0 +1,51 @@
+package dev.lions.unionflow.server.api.dto.lcbft;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class AlerteLcbFtResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new AlerteLcbFtResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime date = LocalDateTime.now();
+ AlerteLcbFtResponse resp = new AlerteLcbFtResponse();
+ resp.setId("alerte-1");
+ resp.setOrganisationId("org-1");
+ resp.setOrganisationNom("Association Test");
+ resp.setMembreId("m-1");
+ resp.setMembreNomComplet("Alice Dupont");
+ resp.setTypeAlerte("SEUIL_DEPASSE");
+ resp.setDateAlerte(date);
+ resp.setDescription("Dépassement de seuil");
+ resp.setMontant(new BigDecimal("600000"));
+ resp.setSeuil(new BigDecimal("500000"));
+ resp.setSeverite("HAUTE");
+ resp.setTraitee(false);
+
+ assertThat(resp.getId()).isEqualTo("alerte-1");
+ assertThat(resp.getOrganisationNom()).isEqualTo("Association Test");
+ assertThat(resp.getTypeAlerte()).isEqualTo("SEUIL_DEPASSE");
+ assertThat(resp.getMontant()).isEqualByComparingTo("600000");
+ assertThat(resp.getSeverite()).isEqualTo("HAUTE");
+ assertThat(resp.getTraitee()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ AlerteLcbFtResponse resp = AlerteLcbFtResponse.builder()
+ .typeAlerte("PEP")
+ .severite("CRITIQUE")
+ .traitee(true)
+ .build();
+ assertThat(resp.getTypeAlerte()).isEqualTo("PEP");
+ assertThat(resp.getTraitee()).isTrue();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/membre/response/MembreSummaryResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/membre/response/MembreSummaryResponseTest.java
new file mode 100644
index 0000000..65d719b
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/membre/response/MembreSummaryResponseTest.java
@@ -0,0 +1,139 @@
+package dev.lions.unionflow.server.api.dto.membre.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class MembreSummaryResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new MembreSummaryResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID id = UUID.randomUUID();
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setId(id);
+ resp.setNumeroMembre("MEM-001");
+ resp.setPrenom("Alice");
+ resp.setNom("Dupont");
+ resp.setEmail("alice@test.com");
+ resp.setStatutCompte("ACTIF");
+ resp.setActif(true);
+ resp.setRoles(List.of("MEMBRE"));
+ resp.setDateAdhesion(LocalDate.of(2025, 1, 1));
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getNumeroMembre()).isEqualTo("MEM-001");
+ assertThat(resp.getPrenom()).isEqualTo("Alice");
+ assertThat(resp.getStatutCompte()).isEqualTo("ACTIF");
+ assertThat(resp.isActif()).isTrue();
+ }
+
+ @Test
+ void testGetNomComplet() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setPrenom("Alice");
+ resp.setNom("Dupont");
+ assertThat(resp.getNomComplet()).isEqualTo("Alice Dupont");
+ }
+
+ @Test
+ void testGetNomCompletNullPrenom() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setPrenom(null);
+ resp.setNom("Dupont");
+ assertThat(resp.getNomComplet()).isEqualTo("Dupont");
+ }
+
+ @Test
+ void testGetStatutAliases() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setStatutCompte("SUSPENDU");
+ resp.setStatutCompteLibelle("Suspendu");
+ resp.setStatutCompteSeverity("warning");
+ assertThat(resp.getStatut()).isEqualTo("SUSPENDU");
+ assertThat(resp.getStatutLibelle()).isEqualTo("Suspendu");
+ assertThat(resp.getStatutSeverity()).isEqualTo("warning");
+ }
+
+ @Test
+ void testGetStatutIcon() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setStatutCompte("ACTIF");
+ assertThat(resp.getStatutIcon()).isEqualTo("pi pi-check-circle");
+ resp.setStatutCompte("SUSPENDU");
+ assertThat(resp.getStatutIcon()).isEqualTo("pi pi-ban");
+ resp.setStatutCompte("RADIE");
+ assertThat(resp.getStatutIcon()).isEqualTo("pi pi-times-circle");
+ resp.setStatutCompte("INACTIF");
+ assertThat(resp.getStatutIcon()).isEqualTo("pi pi-pause-circle");
+ resp.setStatutCompte("INCONNU");
+ assertThat(resp.getStatutIcon()).isEqualTo("pi pi-question-circle");
+ resp.setStatutCompte(null);
+ assertThat(resp.getStatutIcon()).isEqualTo("pi pi-question-circle");
+ }
+
+ @Test
+ void testGetTypeMembre() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setRoles(null);
+ assertThat(resp.getTypeMembre()).isEqualTo("Membre");
+ resp.setRoles(List.of("PRESIDENT"));
+ assertThat(resp.getTypeMembre()).isEqualTo("Président");
+ resp.setRoles(List.of("TRESORIER"));
+ assertThat(resp.getTypeMembre()).isEqualTo("Trésorier");
+ resp.setRoles(List.of("SECRETAIRE"));
+ assertThat(resp.getTypeMembre()).isEqualTo("Secrétaire");
+ resp.setRoles(List.of("VICE_PRESIDENT"));
+ assertThat(resp.getTypeMembre()).isEqualTo("Vice-Président");
+ resp.setRoles(List.of("ADMIN_ORGANISATION"));
+ assertThat(resp.getTypeMembre()).isEqualTo("Administrateur");
+ resp.setRoles(List.of("MODERATEUR"));
+ assertThat(resp.getTypeMembre()).isEqualTo("Modérateur");
+ resp.setRoles(List.of("AUTRE"));
+ assertThat(resp.getTypeMembre()).isEqualTo("Membre");
+ }
+
+ @Test
+ void testGetTypeSeverity() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setRoles(List.of("PRESIDENT"));
+ assertThat(resp.getTypeSeverity()).isEqualTo("primary");
+ resp.setRoles(List.of("ADMIN_ORGANISATION"));
+ assertThat(resp.getTypeSeverity()).isEqualTo("danger");
+ resp.setRoles(null);
+ assertThat(resp.getTypeSeverity()).isEqualTo("secondary");
+ }
+
+ @Test
+ void testGetTypeIcon() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setRoles(List.of("PRESIDENT"));
+ assertThat(resp.getTypeIcon()).isEqualTo("pi pi-star");
+ resp.setRoles(List.of("TRESORIER"));
+ assertThat(resp.getTypeIcon()).isEqualTo("pi pi-wallet");
+ resp.setRoles(List.of("SECRETAIRE"));
+ assertThat(resp.getTypeIcon()).isEqualTo("pi pi-file-edit");
+ resp.setRoles(List.of("ADMIN_ORGANISATION"));
+ assertThat(resp.getTypeIcon()).isEqualTo("pi pi-shield");
+ resp.setRoles(List.of("MODERATEUR"));
+ assertThat(resp.getTypeIcon()).isEqualTo("pi pi-wrench");
+ resp.setRoles(List.of("AUTRE"));
+ assertThat(resp.getTypeIcon()).isEqualTo("pi pi-user");
+ resp.setRoles(null);
+ assertThat(resp.getTypeIcon()).isEqualTo("pi pi-user");
+ }
+
+ @Test
+ void testIsActifNull() {
+ MembreSummaryResponse resp = new MembreSummaryResponse();
+ resp.setActif(null);
+ assertThat(resp.isActif()).isFalse();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/BloquerMembreRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/BloquerMembreRequestTest.java
new file mode 100644
index 0000000..7e2b4d0
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/BloquerMembreRequestTest.java
@@ -0,0 +1,71 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("BloquerMembreRequest")
+class BloquerMembreRequestTest {
+
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ UUID membreId = UUID.randomUUID();
+ UUID orgId = UUID.randomUUID();
+
+ BloquerMembreRequest req = BloquerMembreRequest.builder()
+ .membreABloquerId(membreId)
+ .organisationId(orgId)
+ .build();
+
+ assertThat(req.membreABloquerId()).isEqualTo(membreId);
+ assertThat(req.organisationId()).isEqualTo(orgId);
+ }
+
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ UUID membreId = UUID.randomUUID();
+ UUID orgId = UUID.randomUUID();
+
+ BloquerMembreRequest req = new BloquerMembreRequest(membreId, orgId);
+
+ assertThat(req.membreABloquerId()).isEqualTo(membreId);
+ assertThat(req.organisationId()).isEqualTo(orgId);
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID m = UUID.randomUUID();
+ UUID o = UUID.randomUUID();
+
+ BloquerMembreRequest a = new BloquerMembreRequest(m, o);
+ BloquerMembreRequest b = new BloquerMembreRequest(m, o);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ BloquerMembreRequest a = new BloquerMembreRequest(UUID.randomUUID(), UUID.randomUUID());
+ BloquerMembreRequest b = new BloquerMembreRequest(UUID.randomUUID(), UUID.randomUUID());
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ BloquerMembreRequest req = BloquerMembreRequest.builder()
+ .membreABloquerId(UUID.randomUUID())
+ .organisationId(UUID.randomUUID())
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationDirecteRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationDirecteRequestTest.java
new file mode 100644
index 0000000..b3a4f7e
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationDirecteRequestTest.java
@@ -0,0 +1,93 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("DemarrerConversationDirecteRequest")
+class DemarrerConversationDirecteRequestTest {
+
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ UUID destinataireId = UUID.randomUUID();
+ UUID organisationId = UUID.randomUUID();
+
+ DemarrerConversationDirecteRequest req = DemarrerConversationDirecteRequest.builder()
+ .destinataireId(destinataireId)
+ .organisationId(organisationId)
+ .contenuInitial("Bonjour, comment puis-je vous aider ?")
+ .build();
+
+ assertThat(req.destinataireId()).isEqualTo(destinataireId);
+ assertThat(req.organisationId()).isEqualTo(organisationId);
+ assertThat(req.contenuInitial()).isEqualTo("Bonjour, comment puis-je vous aider ?");
+ }
+
+ @Test
+ @DisplayName("builder — contenuInitial optionnel null")
+ void builder_contenuInitialNull() {
+ UUID destinataireId = UUID.randomUUID();
+ UUID organisationId = UUID.randomUUID();
+
+ DemarrerConversationDirecteRequest req = DemarrerConversationDirecteRequest.builder()
+ .destinataireId(destinataireId)
+ .organisationId(organisationId)
+ .build();
+
+ assertThat(req.destinataireId()).isEqualTo(destinataireId);
+ assertThat(req.organisationId()).isEqualTo(organisationId);
+ assertThat(req.contenuInitial()).isNull();
+ }
+
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ UUID destinataireId = UUID.randomUUID();
+ UUID organisationId = UUID.randomUUID();
+
+ DemarrerConversationDirecteRequest req = new DemarrerConversationDirecteRequest(
+ destinataireId, organisationId, "Premier message");
+
+ assertThat(req.destinataireId()).isEqualTo(destinataireId);
+ assertThat(req.organisationId()).isEqualTo(organisationId);
+ assertThat(req.contenuInitial()).isEqualTo("Premier message");
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID d = UUID.randomUUID();
+ UUID o = UUID.randomUUID();
+
+ DemarrerConversationDirecteRequest a = new DemarrerConversationDirecteRequest(d, o, "msg");
+ DemarrerConversationDirecteRequest b = new DemarrerConversationDirecteRequest(d, o, "msg");
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ DemarrerConversationDirecteRequest a = new DemarrerConversationDirecteRequest(
+ UUID.randomUUID(), UUID.randomUUID(), null);
+ DemarrerConversationDirecteRequest b = new DemarrerConversationDirecteRequest(
+ UUID.randomUUID(), UUID.randomUUID(), null);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ DemarrerConversationDirecteRequest req = DemarrerConversationDirecteRequest.builder()
+ .destinataireId(UUID.randomUUID())
+ .organisationId(UUID.randomUUID())
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationRoleRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationRoleRequestTest.java
new file mode 100644
index 0000000..b4ae187
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/DemarrerConversationRoleRequestTest.java
@@ -0,0 +1,90 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+@DisplayName("DemarrerConversationRoleRequest")
+class DemarrerConversationRoleRequestTest {
+
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ UUID organisationId = UUID.randomUUID();
+
+ DemarrerConversationRoleRequest req = DemarrerConversationRoleRequest.builder()
+ .organisationId(organisationId)
+ .roleCible("TRESORIER")
+ .contenuInitial("Bonjour Trésorier")
+ .build();
+
+ assertThat(req.organisationId()).isEqualTo(organisationId);
+ assertThat(req.roleCible()).isEqualTo("TRESORIER");
+ assertThat(req.contenuInitial()).isEqualTo("Bonjour Trésorier");
+ }
+
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ UUID organisationId = UUID.randomUUID();
+
+ DemarrerConversationRoleRequest req = new DemarrerConversationRoleRequest(
+ organisationId, "PRESIDENT", "Demande urgente");
+
+ assertThat(req.organisationId()).isEqualTo(organisationId);
+ assertThat(req.roleCible()).isEqualTo("PRESIDENT");
+ assertThat(req.contenuInitial()).isEqualTo("Demande urgente");
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"PRESIDENT", "TRESORIER", "SECRETAIRE", "VICE_PRESIDENT", "ADMIN", "ADMIN_ORGANISATION"})
+ @DisplayName("tous les rôles valides acceptés")
+ void allValidRoles(String role) {
+ DemarrerConversationRoleRequest req = DemarrerConversationRoleRequest.builder()
+ .organisationId(UUID.randomUUID())
+ .roleCible(role)
+ .contenuInitial("message")
+ .build();
+
+ assertThat(req.roleCible()).isEqualTo(role);
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID org = UUID.randomUUID();
+
+ DemarrerConversationRoleRequest a = new DemarrerConversationRoleRequest(org, "TRESORIER", "msg");
+ DemarrerConversationRoleRequest b = new DemarrerConversationRoleRequest(org, "TRESORIER", "msg");
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ DemarrerConversationRoleRequest a = new DemarrerConversationRoleRequest(
+ UUID.randomUUID(), "TRESORIER", "msg");
+ DemarrerConversationRoleRequest b = new DemarrerConversationRoleRequest(
+ UUID.randomUUID(), "PRESIDENT", "msg");
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ DemarrerConversationRoleRequest req = DemarrerConversationRoleRequest.builder()
+ .organisationId(UUID.randomUUID())
+ .roleCible("SECRETAIRE")
+ .contenuInitial("test")
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/EnvoyerMessageRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/EnvoyerMessageRequestTest.java
new file mode 100644
index 0000000..3c76b55
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/EnvoyerMessageRequestTest.java
@@ -0,0 +1,120 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+@DisplayName("EnvoyerMessageRequest")
+class EnvoyerMessageRequestTest {
+
+ @Test
+ @DisplayName("builder — message texte")
+ void builder_messageTexte() {
+ EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
+ .typeMessage("TEXTE")
+ .contenu("Bonjour à tous !")
+ .build();
+
+ assertThat(req.typeMessage()).isEqualTo("TEXTE");
+ assertThat(req.contenu()).isEqualTo("Bonjour à tous !");
+ assertThat(req.urlFichier()).isNull();
+ assertThat(req.dureeAudio()).isNull();
+ assertThat(req.messageParentId()).isNull();
+ }
+
+ @Test
+ @DisplayName("builder — note vocale")
+ void builder_noteVocale() {
+ EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
+ .typeMessage("VOCAL")
+ .urlFichier("https://storage.example.com/audio/note.opus")
+ .dureeAudio(45)
+ .build();
+
+ assertThat(req.typeMessage()).isEqualTo("VOCAL");
+ assertThat(req.urlFichier()).isEqualTo("https://storage.example.com/audio/note.opus");
+ assertThat(req.dureeAudio()).isEqualTo(45);
+ assertThat(req.contenu()).isNull();
+ }
+
+ @Test
+ @DisplayName("builder — image")
+ void builder_image() {
+ EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
+ .typeMessage("IMAGE")
+ .urlFichier("https://storage.example.com/img/photo.jpg")
+ .build();
+
+ assertThat(req.typeMessage()).isEqualTo("IMAGE");
+ assertThat(req.urlFichier()).isEqualTo("https://storage.example.com/img/photo.jpg");
+ }
+
+ @Test
+ @DisplayName("builder — réponse à un message parent")
+ void builder_avecMessageParent() {
+ UUID parentId = UUID.randomUUID();
+
+ EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
+ .typeMessage("TEXTE")
+ .contenu("Oui, c'est exact !")
+ .messageParentId(parentId)
+ .build();
+
+ assertThat(req.messageParentId()).isEqualTo(parentId);
+ }
+
+ @Test
+ @DisplayName("builder — tous les champs null (aucune contrainte record)")
+ void builder_allNull() {
+ EnvoyerMessageRequest req = EnvoyerMessageRequest.builder().build();
+
+ assertThat(req.typeMessage()).isNull();
+ assertThat(req.contenu()).isNull();
+ assertThat(req.urlFichier()).isNull();
+ assertThat(req.dureeAudio()).isNull();
+ assertThat(req.messageParentId()).isNull();
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"TEXTE", "VOCAL", "IMAGE", "SYSTEME"})
+ @DisplayName("tous les types de message valides")
+ void allValidTypes(String type) {
+ EnvoyerMessageRequest req = new EnvoyerMessageRequest(type, null, null, null, null);
+ assertThat(req.typeMessage()).isEqualTo(type);
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID parentId = UUID.randomUUID();
+ EnvoyerMessageRequest a = new EnvoyerMessageRequest("TEXTE", "bonjour", null, null, parentId);
+ EnvoyerMessageRequest b = new EnvoyerMessageRequest("TEXTE", "bonjour", null, null, parentId);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ EnvoyerMessageRequest a = new EnvoyerMessageRequest("TEXTE", "bonjour", null, null, null);
+ EnvoyerMessageRequest b = new EnvoyerMessageRequest("VOCAL", null, "url", 30, null);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
+ .typeMessage("TEXTE")
+ .contenu("test")
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/MettreAJourPolitiqueRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/MettreAJourPolitiqueRequestTest.java
new file mode 100644
index 0000000..7d53f37
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/request/MettreAJourPolitiqueRequestTest.java
@@ -0,0 +1,101 @@
+package dev.lions.unionflow.server.api.dto.messagerie.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+@DisplayName("MettreAJourPolitiqueRequest")
+class MettreAJourPolitiqueRequestTest {
+
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ MettreAJourPolitiqueRequest req = MettreAJourPolitiqueRequest.builder()
+ .typePolitique("OUVERT")
+ .autoriserMembreVersMembre(true)
+ .autoriserMembreVersRole(true)
+ .autoriserNotesVocales(false)
+ .build();
+
+ assertThat(req.typePolitique()).isEqualTo("OUVERT");
+ assertThat(req.autoriserMembreVersMembre()).isTrue();
+ assertThat(req.autoriserMembreVersRole()).isTrue();
+ assertThat(req.autoriserNotesVocales()).isFalse();
+ }
+
+ @Test
+ @DisplayName("builder — tous les champs null (mise à jour partielle)")
+ void builder_allNull() {
+ MettreAJourPolitiqueRequest req = MettreAJourPolitiqueRequest.builder().build();
+
+ assertThat(req.typePolitique()).isNull();
+ assertThat(req.autoriserMembreVersMembre()).isNull();
+ assertThat(req.autoriserMembreVersRole()).isNull();
+ assertThat(req.autoriserNotesVocales()).isNull();
+ }
+
+ @Test
+ @DisplayName("builder — mise à jour partielle (typePolitique uniquement)")
+ void builder_partialUpdate_typeOnly() {
+ MettreAJourPolitiqueRequest req = MettreAJourPolitiqueRequest.builder()
+ .typePolitique("BUREAU_SEULEMENT")
+ .build();
+
+ assertThat(req.typePolitique()).isEqualTo("BUREAU_SEULEMENT");
+ assertThat(req.autoriserMembreVersMembre()).isNull();
+ assertThat(req.autoriserMembreVersRole()).isNull();
+ assertThat(req.autoriserNotesVocales()).isNull();
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"OUVERT", "BUREAU_SEULEMENT", "GROUPES_INTERNES"})
+ @DisplayName("toutes les politiques valides")
+ void allValidPolicies(String politique) {
+ MettreAJourPolitiqueRequest req = new MettreAJourPolitiqueRequest(politique, null, null, null);
+ assertThat(req.typePolitique()).isEqualTo(politique);
+ }
+
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ MettreAJourPolitiqueRequest req = new MettreAJourPolitiqueRequest(
+ "GROUPES_INTERNES", false, true, true);
+
+ assertThat(req.typePolitique()).isEqualTo("GROUPES_INTERNES");
+ assertThat(req.autoriserMembreVersMembre()).isFalse();
+ assertThat(req.autoriserMembreVersRole()).isTrue();
+ assertThat(req.autoriserNotesVocales()).isTrue();
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ MettreAJourPolitiqueRequest a = new MettreAJourPolitiqueRequest("OUVERT", true, true, true);
+ MettreAJourPolitiqueRequest b = new MettreAJourPolitiqueRequest("OUVERT", true, true, true);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ MettreAJourPolitiqueRequest a = new MettreAJourPolitiqueRequest("OUVERT", true, true, true);
+ MettreAJourPolitiqueRequest b = new MettreAJourPolitiqueRequest("BUREAU_SEULEMENT", false, false, false);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ MettreAJourPolitiqueRequest req = MettreAJourPolitiqueRequest.builder()
+ .typePolitique("OUVERT")
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ContactPolicyResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ContactPolicyResponseTest.java
new file mode 100644
index 0000000..04ab3fa
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ContactPolicyResponseTest.java
@@ -0,0 +1,113 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("ContactPolicyResponse")
+class ContactPolicyResponseTest {
+
+ @Test
+ @DisplayName("builder — politique OUVERT (valeurs par défaut)")
+ void builder_politiqueOuvert() {
+ UUID id = UUID.randomUUID();
+ UUID orgId = UUID.randomUUID();
+
+ ContactPolicyResponse resp = ContactPolicyResponse.builder()
+ .id(id)
+ .organisationId(orgId)
+ .typePolitique("OUVERT")
+ .autoriserMembreVersMembre(true)
+ .autoriserMembreVersRole(true)
+ .autoriserNotesVocales(true)
+ .build();
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getOrganisationId()).isEqualTo(orgId);
+ assertThat(resp.getTypePolitique()).isEqualTo("OUVERT");
+ assertThat(resp.isAutoriserMembreVersMembre()).isTrue();
+ assertThat(resp.isAutoriserMembreVersRole()).isTrue();
+ assertThat(resp.isAutoriserNotesVocales()).isTrue();
+ }
+
+ @Test
+ @DisplayName("builder — politique BUREAU_SEULEMENT restrictive")
+ void builder_politiqueBureauSeulement() {
+ ContactPolicyResponse resp = ContactPolicyResponse.builder()
+ .typePolitique("BUREAU_SEULEMENT")
+ .autoriserMembreVersMembre(false)
+ .autoriserMembreVersRole(true)
+ .autoriserNotesVocales(false)
+ .build();
+
+ assertThat(resp.getTypePolitique()).isEqualTo("BUREAU_SEULEMENT");
+ assertThat(resp.isAutoriserMembreVersMembre()).isFalse();
+ assertThat(resp.isAutoriserMembreVersRole()).isTrue();
+ assertThat(resp.isAutoriserNotesVocales()).isFalse();
+ }
+
+ @Test
+ @DisplayName("builder — politique GROUPES_INTERNES")
+ void builder_politiqueGroupesInternes() {
+ ContactPolicyResponse resp = ContactPolicyResponse.builder()
+ .typePolitique("GROUPES_INTERNES")
+ .autoriserMembreVersMembre(true)
+ .autoriserMembreVersRole(true)
+ .autoriserNotesVocales(true)
+ .build();
+
+ assertThat(resp.getTypePolitique()).isEqualTo("GROUPES_INTERNES");
+ }
+
+ @Test
+ @DisplayName("constructeur no-args — valeurs par défaut")
+ void noArgsConstructor_defaults() {
+ ContactPolicyResponse resp = new ContactPolicyResponse();
+
+ assertThat(resp.getId()).isNull();
+ assertThat(resp.getOrganisationId()).isNull();
+ assertThat(resp.getTypePolitique()).isNull();
+ assertThat(resp.isAutoriserMembreVersMembre()).isFalse();
+ assertThat(resp.isAutoriserMembreVersRole()).isFalse();
+ assertThat(resp.isAutoriserNotesVocales()).isFalse();
+ }
+
+ @Test
+ @DisplayName("setters et getters fonctionnent")
+ void settersGetters() {
+ ContactPolicyResponse resp = new ContactPolicyResponse();
+ UUID id = UUID.randomUUID();
+ resp.setId(id);
+ resp.setTypePolitique("OUVERT");
+ resp.setAutoriserNotesVocales(true);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getTypePolitique()).isEqualTo("OUVERT");
+ assertThat(resp.isAutoriserNotesVocales()).isTrue();
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID id = UUID.randomUUID();
+ UUID org = UUID.randomUUID();
+ ContactPolicyResponse a = ContactPolicyResponse.builder().id(id).organisationId(org).typePolitique("OUVERT").build();
+ ContactPolicyResponse b = ContactPolicyResponse.builder().id(id).organisationId(org).typePolitique("OUVERT").build();
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ ContactPolicyResponse resp = ContactPolicyResponse.builder()
+ .id(UUID.randomUUID())
+ .typePolitique("OUVERT")
+ .build();
+
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationResponseTest.java
new file mode 100644
index 0000000..a66fe91
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationResponseTest.java
@@ -0,0 +1,140 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("ConversationResponse")
+class ConversationResponseTest {
+
+ @Test
+ @DisplayName("builder — conversation directe avec messages et participants")
+ void builder_conversationComplète() {
+ UUID id = UUID.randomUUID();
+ UUID orgId = UUID.randomUUID();
+ LocalDateTime dateCreation = LocalDateTime.of(2026, 4, 1, 9, 0);
+
+ ConversationResponse.ParticipantResponse p1 = ConversationResponse.ParticipantResponse.builder()
+ .membreId(UUID.randomUUID())
+ .prenom("Alice")
+ .nom("Dupont")
+ .roleDansConversation("INITIATEUR")
+ .build();
+
+ MessageResponse msg = MessageResponse.builder()
+ .id(UUID.randomUUID())
+ .typeMessage("TEXTE")
+ .contenu("Bonjour !")
+ .build();
+
+ ConversationResponse resp = ConversationResponse.builder()
+ .id(id)
+ .typeConversation("DIRECTE")
+ .titre("Alice Dupont")
+ .statut("ACTIVE")
+ .organisationId(orgId)
+ .organisationNom("Association Lions")
+ .dateCreation(dateCreation)
+ .nombreMessages(1)
+ .participants(List.of(p1))
+ .messages(List.of(msg))
+ .nonLus(0L)
+ .build();
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getTypeConversation()).isEqualTo("DIRECTE");
+ assertThat(resp.getTitre()).isEqualTo("Alice Dupont");
+ assertThat(resp.getStatut()).isEqualTo("ACTIVE");
+ assertThat(resp.getOrganisationId()).isEqualTo(orgId);
+ assertThat(resp.getOrganisationNom()).isEqualTo("Association Lions");
+ assertThat(resp.getDateCreation()).isEqualTo(dateCreation);
+ assertThat(resp.getNombreMessages()).isEqualTo(1);
+ assertThat(resp.getParticipants()).hasSize(1);
+ assertThat(resp.getMessages()).hasSize(1);
+ assertThat(resp.getNonLus()).isZero();
+ }
+
+ @Test
+ @DisplayName("builder — canal rôle")
+ void builder_canalRole() {
+ ConversationResponse resp = ConversationResponse.builder()
+ .typeConversation("ROLE_CANAL")
+ .roleCible("TRESORIER")
+ .titre("Trésorier")
+ .statut("ACTIVE")
+ .build();
+
+ assertThat(resp.getTypeConversation()).isEqualTo("ROLE_CANAL");
+ assertThat(resp.getRoleCible()).isEqualTo("TRESORIER");
+ assertThat(resp.getTitre()).isEqualTo("Trésorier");
+ }
+
+ @Test
+ @DisplayName("constructeur no-args — valeurs par défaut")
+ void noArgsConstructor_defaults() {
+ ConversationResponse resp = new ConversationResponse();
+
+ assertThat(resp.getId()).isNull();
+ assertThat(resp.getParticipants()).isNull();
+ assertThat(resp.getMessages()).isNull();
+ assertThat(resp.getNonLus()).isZero();
+ assertThat(resp.getNombreMessages()).isZero();
+ }
+
+ @Test
+ @DisplayName("ParticipantResponse builder — tous les champs")
+ void participantResponse_builder() {
+ UUID membreId = UUID.randomUUID();
+ LocalDateTime luJusqua = LocalDateTime.now();
+
+ ConversationResponse.ParticipantResponse p = ConversationResponse.ParticipantResponse.builder()
+ .membreId(membreId)
+ .prenom("Bob")
+ .nom("Martin")
+ .roleDansConversation("PARTICIPANT")
+ .luJusqua(luJusqua)
+ .build();
+
+ assertThat(p.getMembreId()).isEqualTo(membreId);
+ assertThat(p.getPrenom()).isEqualTo("Bob");
+ assertThat(p.getNom()).isEqualTo("Martin");
+ assertThat(p.getRoleDansConversation()).isEqualTo("PARTICIPANT");
+ assertThat(p.getLuJusqua()).isEqualTo(luJusqua);
+ }
+
+ @Test
+ @DisplayName("ParticipantResponse no-args — valeurs nulles")
+ void participantResponse_noArgsConstructor() {
+ ConversationResponse.ParticipantResponse p = new ConversationResponse.ParticipantResponse();
+
+ assertThat(p.getMembreId()).isNull();
+ assertThat(p.getPrenom()).isNull();
+ assertThat(p.getLuJusqua()).isNull();
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID id = UUID.randomUUID();
+ ConversationResponse a = ConversationResponse.builder().id(id).titre("Alice").build();
+ ConversationResponse b = ConversationResponse.builder().id(id).titre("Alice").build();
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ ConversationResponse resp = ConversationResponse.builder()
+ .id(UUID.randomUUID())
+ .typeConversation("DIRECTE")
+ .build();
+
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationSummaryResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationSummaryResponseTest.java
new file mode 100644
index 0000000..f89f8ea
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/ConversationSummaryResponseTest.java
@@ -0,0 +1,102 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("ConversationSummaryResponse")
+class ConversationSummaryResponseTest {
+
+ @Test
+ @DisplayName("builder — conversation directe")
+ void builder_conversationDirecte() {
+ UUID id = UUID.randomUUID();
+ UUID orgId = UUID.randomUUID();
+ LocalDateTime dernierMsg = LocalDateTime.of(2026, 4, 13, 14, 0);
+
+ ConversationSummaryResponse resp = ConversationSummaryResponse.builder()
+ .id(id)
+ .typeConversation("DIRECTE")
+ .titre("Alice Dupont")
+ .statut("ACTIVE")
+ .dernierMessageApercu("Bonjour !")
+ .dernierMessageType("TEXTE")
+ .dernierMessageAt(dernierMsg)
+ .nonLus(3L)
+ .organisationId(orgId)
+ .build();
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getTypeConversation()).isEqualTo("DIRECTE");
+ assertThat(resp.getTitre()).isEqualTo("Alice Dupont");
+ assertThat(resp.getStatut()).isEqualTo("ACTIVE");
+ assertThat(resp.getDernierMessageApercu()).isEqualTo("Bonjour !");
+ assertThat(resp.getDernierMessageType()).isEqualTo("TEXTE");
+ assertThat(resp.getDernierMessageAt()).isEqualTo(dernierMsg);
+ assertThat(resp.getNonLus()).isEqualTo(3L);
+ assertThat(resp.getOrganisationId()).isEqualTo(orgId);
+ }
+
+ @Test
+ @DisplayName("builder — canal rôle (Trésorier)")
+ void builder_canalRole() {
+ ConversationSummaryResponse resp = ConversationSummaryResponse.builder()
+ .typeConversation("ROLE_CANAL")
+ .titre("Trésorier")
+ .statut("ACTIVE")
+ .nonLus(0L)
+ .build();
+
+ assertThat(resp.getTypeConversation()).isEqualTo("ROLE_CANAL");
+ assertThat(resp.getTitre()).isEqualTo("Trésorier");
+ assertThat(resp.getNonLus()).isZero();
+ }
+
+ @Test
+ @DisplayName("constructeur no-args — valeurs par défaut")
+ void noArgsConstructor_defaults() {
+ ConversationSummaryResponse resp = new ConversationSummaryResponse();
+
+ assertThat(resp.getId()).isNull();
+ assertThat(resp.getTypeConversation()).isNull();
+ assertThat(resp.getNonLus()).isZero();
+ }
+
+ @Test
+ @DisplayName("setters et getters fonctionnent")
+ void settersGetters() {
+ ConversationSummaryResponse resp = new ConversationSummaryResponse();
+ resp.setTitre("Bob Martin");
+ resp.setStatut("ARCHIVEE");
+ resp.setNonLus(5L);
+
+ assertThat(resp.getTitre()).isEqualTo("Bob Martin");
+ assertThat(resp.getStatut()).isEqualTo("ARCHIVEE");
+ assertThat(resp.getNonLus()).isEqualTo(5L);
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID id = UUID.randomUUID();
+ ConversationSummaryResponse a = ConversationSummaryResponse.builder().id(id).titre("Alice").build();
+ ConversationSummaryResponse b = ConversationSummaryResponse.builder().id(id).titre("Alice").build();
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ ConversationSummaryResponse resp = ConversationSummaryResponse.builder()
+ .id(UUID.randomUUID())
+ .typeConversation("DIRECTE")
+ .build();
+
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/MessageResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/MessageResponseTest.java
new file mode 100644
index 0000000..f6b886c
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/messagerie/response/MessageResponseTest.java
@@ -0,0 +1,134 @@
+package dev.lions.unionflow.server.api.dto.messagerie.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("MessageResponse")
+class MessageResponseTest {
+
+ @Test
+ @DisplayName("builder — message texte complet")
+ void builder_messageTexte() {
+ UUID id = UUID.randomUUID();
+ UUID expediteurId = UUID.randomUUID();
+ LocalDateTime dateEnvoi = LocalDateTime.of(2026, 4, 13, 10, 30);
+
+ MessageResponse resp = MessageResponse.builder()
+ .id(id)
+ .typeMessage("TEXTE")
+ .contenu("Bonjour tout le monde !")
+ .supprime(false)
+ .expediteurId(expediteurId)
+ .expediteurNom("Dupont")
+ .expediteurPrenom("Alice")
+ .dateEnvoi(dateEnvoi)
+ .build();
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getTypeMessage()).isEqualTo("TEXTE");
+ assertThat(resp.getContenu()).isEqualTo("Bonjour tout le monde !");
+ assertThat(resp.isSupprime()).isFalse();
+ assertThat(resp.getExpediteurId()).isEqualTo(expediteurId);
+ assertThat(resp.getExpediteurNom()).isEqualTo("Dupont");
+ assertThat(resp.getExpediteurPrenom()).isEqualTo("Alice");
+ assertThat(resp.getDateEnvoi()).isEqualTo(dateEnvoi);
+ }
+
+ @Test
+ @DisplayName("builder — note vocale")
+ void builder_noteVocale() {
+ MessageResponse resp = MessageResponse.builder()
+ .typeMessage("VOCAL")
+ .urlFichier("https://storage.example.com/audio/note.opus")
+ .dureeAudio(67)
+ .supprime(false)
+ .build();
+
+ assertThat(resp.getTypeMessage()).isEqualTo("VOCAL");
+ assertThat(resp.getUrlFichier()).isEqualTo("https://storage.example.com/audio/note.opus");
+ assertThat(resp.getDureeAudio()).isEqualTo(67);
+ assertThat(resp.getContenu()).isNull();
+ }
+
+ @Test
+ @DisplayName("builder — message supprimé")
+ void builder_messageSupprime() {
+ MessageResponse resp = MessageResponse.builder()
+ .typeMessage("TEXTE")
+ .contenu("[Message supprimé]")
+ .supprime(true)
+ .build();
+
+ assertThat(resp.isSupprime()).isTrue();
+ assertThat(resp.getContenu()).isEqualTo("[Message supprimé]");
+ }
+
+ @Test
+ @DisplayName("builder — réponse à un message parent")
+ void builder_avecParent() {
+ UUID parentId = UUID.randomUUID();
+
+ MessageResponse resp = MessageResponse.builder()
+ .typeMessage("TEXTE")
+ .contenu("Tout à fait !")
+ .messageParentId(parentId)
+ .messageParentApercu("Êtes-vous disponible demain ?")
+ .build();
+
+ assertThat(resp.getMessageParentId()).isEqualTo(parentId);
+ assertThat(resp.getMessageParentApercu()).isEqualTo("Êtes-vous disponible demain ?");
+ }
+
+ @Test
+ @DisplayName("constructeur no-args — valeurs par défaut")
+ void noArgsConstructor_defaults() {
+ MessageResponse resp = new MessageResponse();
+
+ assertThat(resp.getId()).isNull();
+ assertThat(resp.getTypeMessage()).isNull();
+ assertThat(resp.getContenu()).isNull();
+ assertThat(resp.isSupprime()).isFalse();
+ }
+
+ @Test
+ @DisplayName("setters et getters fonctionnent")
+ void settersGetters() {
+ MessageResponse resp = new MessageResponse();
+ UUID id = UUID.randomUUID();
+ resp.setId(id);
+ resp.setTypeMessage("IMAGE");
+ resp.setUrlFichier("https://img.example.com/photo.jpg");
+ resp.setSupprime(false);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getTypeMessage()).isEqualTo("IMAGE");
+ assertThat(resp.getUrlFichier()).isEqualTo("https://img.example.com/photo.jpg");
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID id = UUID.randomUUID();
+ MessageResponse a = MessageResponse.builder().id(id).typeMessage("TEXTE").build();
+ MessageResponse b = MessageResponse.builder().id(id).typeMessage("TEXTE").build();
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ MessageResponse resp = MessageResponse.builder()
+ .id(UUID.randomUUID())
+ .typeMessage("TEXTE")
+ .contenu("hello")
+ .build();
+
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/DemandeCreditRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/DemandeCreditRequestTest.java
new file mode 100644
index 0000000..fec6596
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/DemandeCreditRequestTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.credit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit;
+import java.math.BigDecimal;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class DemandeCreditRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new DemandeCreditRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ DemandeCreditRequest req = new DemandeCreditRequest();
+ req.setMembreId("m-1");
+ req.setTypeCredit(TypeCredit.CONSOMMATION);
+ req.setMontantDemande(new BigDecimal("500000"));
+ req.setDureeMois(12);
+ req.setCompteLieId("compte-1");
+ req.setJustificationDetaillee("Pour achat équipement");
+ req.setDocumentIds(List.of("doc-1", "doc-2"));
+
+ assertThat(req.getMembreId()).isEqualTo("m-1");
+ assertThat(req.getTypeCredit()).isEqualTo(TypeCredit.CONSOMMATION);
+ assertThat(req.getMontantDemande()).isEqualByComparingTo("500000");
+ assertThat(req.getDureeMois()).isEqualTo(12);
+ assertThat(req.getDocumentIds()).hasSize(2);
+ }
+
+ @Test
+ void testBuilder() {
+ DemandeCreditRequest req = DemandeCreditRequest.builder()
+ .membreId("m-2")
+ .typeCredit(TypeCredit.URGENCE)
+ .montantDemande(new BigDecimal("100000"))
+ .build();
+ assertThat(req.getMembreId()).isEqualTo("m-2");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/DemandeCreditResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/DemandeCreditResponseTest.java
new file mode 100644
index 0000000..3913a14
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/DemandeCreditResponseTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.credit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutDemandeCredit;
+import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeCredit;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class DemandeCreditResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new DemandeCreditResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ DemandeCreditResponse resp = new DemandeCreditResponse();
+ resp.setNumeroDossier("CREDIT-001");
+ resp.setMembreId("m-1");
+ resp.setTypeCredit(TypeCredit.CONSOMMATION);
+ resp.setMontantDemande(new BigDecimal("500000"));
+ resp.setMontantApprouve(new BigDecimal("450000"));
+ resp.setDureeMoisDemande(12);
+ resp.setDureeMoisApprouvee(10);
+ resp.setTauxInteretAnnuel(new BigDecimal("0.12"));
+ resp.setStatut(StatutDemandeCredit.APPROUVEE);
+
+ assertThat(resp.getNumeroDossier()).isEqualTo("CREDIT-001");
+ assertThat(resp.getTypeCredit()).isEqualTo(TypeCredit.CONSOMMATION);
+ assertThat(resp.getMontantApprouve()).isEqualByComparingTo("450000");
+ assertThat(resp.getStatut()).isEqualTo(StatutDemandeCredit.APPROUVEE);
+ }
+
+ @Test
+ void testBuilder() {
+ DemandeCreditResponse resp = DemandeCreditResponse.builder()
+ .numeroDossier("CREDIT-002")
+ .statut(StatutDemandeCredit.SOUMISE)
+ .build();
+ assertThat(resp.getNumeroDossier()).isEqualTo("CREDIT-002");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/EcheanceCreditDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/EcheanceCreditDTOTest.java
new file mode 100644
index 0000000..0b7755a
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/EcheanceCreditDTOTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.credit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.credit.StatutEcheanceCredit;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class EcheanceCreditDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new EcheanceCreditDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ EcheanceCreditDTO dto = new EcheanceCreditDTO();
+ dto.setDemandeCreditId("credit-1");
+ dto.setOrdre(1);
+ dto.setDateEcheancePrevue(LocalDate.of(2026, 2, 1));
+ dto.setCapitalAmorti(new BigDecimal("40000"));
+ dto.setInteretsDeLaPeriode(new BigDecimal("5000"));
+ dto.setMontantTotalExigible(new BigDecimal("45000"));
+ dto.setCapitalRestantDu(new BigDecimal("460000"));
+ dto.setMontantRegle(new BigDecimal("45000"));
+ dto.setStatut(StatutEcheanceCredit.PAYEE);
+
+ assertThat(dto.getDemandeCreditId()).isEqualTo("credit-1");
+ assertThat(dto.getOrdre()).isEqualTo(1);
+ assertThat(dto.getCapitalAmorti()).isEqualByComparingTo("40000");
+ assertThat(dto.getStatut()).isEqualTo(StatutEcheanceCredit.PAYEE);
+ }
+
+ @Test
+ void testBuilder() {
+ EcheanceCreditDTO dto = EcheanceCreditDTO.builder()
+ .ordre(2)
+ .statut(StatutEcheanceCredit.A_VENIR)
+ .build();
+ assertThat(dto.getOrdre()).isEqualTo(2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/GarantieDemandeDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/GarantieDemandeDTOTest.java
new file mode 100644
index 0000000..f8fae30
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/credit/GarantieDemandeDTOTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.credit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.credit.TypeGarantie;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class GarantieDemandeDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new GarantieDemandeDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ GarantieDemandeDTO dto = new GarantieDemandeDTO();
+ dto.setTypeGarantie(TypeGarantie.EPARGNE_BLOQUEE);
+ dto.setValeurEstimee(new BigDecimal("200000"));
+ dto.setReferenceOuDescription("Compte épargne MEC-001");
+ dto.setDocumentPreuveId("doc-1");
+
+ assertThat(dto.getTypeGarantie()).isEqualTo(TypeGarantie.EPARGNE_BLOQUEE);
+ assertThat(dto.getValeurEstimee()).isEqualByComparingTo("200000");
+ assertThat(dto.getReferenceOuDescription()).isEqualTo("Compte épargne MEC-001");
+ assertThat(dto.getDocumentPreuveId()).isEqualTo("doc-1");
+ }
+
+ @Test
+ void testBuilder() {
+ GarantieDemandeDTO dto = GarantieDemandeDTO.builder()
+ .typeGarantie(TypeGarantie.CAUTION_SOLIDAIRE)
+ .referenceOuDescription("Caution membre M-002")
+ .build();
+ assertThat(dto.getTypeGarantie()).isEqualTo(TypeGarantie.CAUTION_SOLIDAIRE);
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ GarantieDemandeDTO d1 = GarantieDemandeDTO.builder().typeGarantie(TypeGarantie.EPARGNE_BLOQUEE).referenceOuDescription("r").build();
+ GarantieDemandeDTO d2 = GarantieDemandeDTO.builder().typeGarantie(TypeGarantie.EPARGNE_BLOQUEE).referenceOuDescription("r").build();
+ assertThat(d1).isEqualTo(d2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/CompteEpargneRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/CompteEpargneRequestTest.java
new file mode 100644
index 0000000..7743299
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/CompteEpargneRequestTest.java
@@ -0,0 +1,37 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.epargne;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeCompteEpargne;
+import org.junit.jupiter.api.Test;
+
+class CompteEpargneRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CompteEpargneRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CompteEpargneRequest req = new CompteEpargneRequest();
+ req.setMembreId("m-1");
+ req.setOrganisationId("org-1");
+ req.setTypeCompte(TypeCompteEpargne.EPARGNE_LIBRE);
+ req.setNotesOuverture("Ouverture initiale");
+
+ assertThat(req.getMembreId()).isEqualTo("m-1");
+ assertThat(req.getOrganisationId()).isEqualTo("org-1");
+ assertThat(req.getTypeCompte()).isEqualTo(TypeCompteEpargne.EPARGNE_LIBRE);
+ assertThat(req.getNotesOuverture()).isEqualTo("Ouverture initiale");
+ }
+
+ @Test
+ void testBuilder() {
+ CompteEpargneRequest req = CompteEpargneRequest.builder()
+ .membreId("m-2")
+ .typeCompte(TypeCompteEpargne.EPARGNE_BLOQUEE)
+ .build();
+ assertThat(req.getTypeCompte()).isEqualTo(TypeCompteEpargne.EPARGNE_BLOQUEE);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/CompteEpargneResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/CompteEpargneResponseTest.java
new file mode 100644
index 0000000..a332b55
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/CompteEpargneResponseTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.epargne;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.epargne.StatutCompteEpargne;
+import dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeCompteEpargne;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class CompteEpargneResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CompteEpargneResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CompteEpargneResponse resp = new CompteEpargneResponse();
+ resp.setMembreId("m-1");
+ resp.setOrganisationId("org-1");
+ resp.setNumeroCompte("MEC-001");
+ resp.setTypeCompte(TypeCompteEpargne.EPARGNE_LIBRE);
+ resp.setSoldeActuel(new BigDecimal("250000"));
+ resp.setSoldeBloque(new BigDecimal("50000"));
+ resp.setStatut(StatutCompteEpargne.ACTIF);
+ resp.setDateOuverture(LocalDate.of(2025, 1, 1));
+
+ assertThat(resp.getNumeroCompte()).isEqualTo("MEC-001");
+ assertThat(resp.getTypeCompte()).isEqualTo(TypeCompteEpargne.EPARGNE_LIBRE);
+ assertThat(resp.getSoldeActuel()).isEqualByComparingTo("250000");
+ assertThat(resp.getStatut()).isEqualTo(StatutCompteEpargne.ACTIF);
+ }
+
+ @Test
+ void testBuilder() {
+ CompteEpargneResponse resp = CompteEpargneResponse.builder()
+ .numeroCompte("MEC-002")
+ .statut(StatutCompteEpargne.CLOTURE)
+ .build();
+ assertThat(resp.getNumeroCompte()).isEqualTo("MEC-002");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/TransactionEpargneRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/TransactionEpargneRequestTest.java
new file mode 100644
index 0000000..af580cd
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/TransactionEpargneRequestTest.java
@@ -0,0 +1,41 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.epargne;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeTransactionEpargne;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class TransactionEpargneRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TransactionEpargneRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ TransactionEpargneRequest req = new TransactionEpargneRequest();
+ req.setCompteId("compte-1");
+ req.setTypeTransaction(TypeTransactionEpargne.DEPOT);
+ req.setMontant(new BigDecimal("50000"));
+ req.setMotif("Dépôt mensuel");
+ req.setOrigineFonds("Salaire");
+ req.setPieceJustificativeId("doc-1");
+
+ assertThat(req.getCompteId()).isEqualTo("compte-1");
+ assertThat(req.getTypeTransaction()).isEqualTo(TypeTransactionEpargne.DEPOT);
+ assertThat(req.getMontant()).isEqualByComparingTo("50000");
+ assertThat(req.getOrigineFonds()).isEqualTo("Salaire");
+ }
+
+ @Test
+ void testBuilder() {
+ TransactionEpargneRequest req = TransactionEpargneRequest.builder()
+ .compteId("compte-2")
+ .typeTransaction(TypeTransactionEpargne.RETRAIT)
+ .montant(new BigDecimal("20000"))
+ .build();
+ assertThat(req.getTypeTransaction()).isEqualTo(TypeTransactionEpargne.RETRAIT);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/TransactionEpargneResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/TransactionEpargneResponseTest.java
new file mode 100644
index 0000000..eaff877
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/epargne/TransactionEpargneResponseTest.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.epargne;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeTransactionEpargne;
+import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class TransactionEpargneResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TransactionEpargneResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime date = LocalDateTime.now();
+ TransactionEpargneResponse resp = new TransactionEpargneResponse();
+ resp.setCompteId("compte-1");
+ resp.setType(TypeTransactionEpargne.DEPOT);
+ resp.setMontant(new BigDecimal("50000"));
+ resp.setSoldeAvant(new BigDecimal("200000"));
+ resp.setSoldeApres(new BigDecimal("250000"));
+ resp.setMotif("Dépôt");
+ resp.setDateTransaction(date);
+ resp.setStatutExecution(StatutTransactionWave.REUSSIE);
+
+ assertThat(resp.getCompteId()).isEqualTo("compte-1");
+ assertThat(resp.getType()).isEqualTo(TypeTransactionEpargne.DEPOT);
+ assertThat(resp.getMontant()).isEqualByComparingTo("50000");
+ assertThat(resp.getSoldeApres()).isEqualByComparingTo("250000");
+ assertThat(resp.getStatutExecution()).isEqualTo(StatutTransactionWave.REUSSIE);
+ }
+
+ @Test
+ void testBuilder() {
+ TransactionEpargneResponse resp = TransactionEpargneResponse.builder()
+ .compteId("c-1")
+ .type(TypeTransactionEpargne.TRANSFERT_ENTRANT)
+ .build();
+ assertThat(resp.getType()).isEqualTo(TypeTransactionEpargne.TRANSFERT_ENTRANT);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellRequestTest.java
new file mode 100644
index 0000000..f60b90c
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellRequestTest.java
@@ -0,0 +1,40 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.financier;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class ParametresFinanciersMutuellRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ParametresFinanciersMutuellRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ParametresFinanciersMutuellRequest req = new ParametresFinanciersMutuellRequest();
+ req.setOrganisationId("org-1");
+ req.setValeurNominaleParDefaut(new BigDecimal("5000"));
+ req.setTauxInteretAnnuelEpargne(new BigDecimal("0.03"));
+ req.setTauxDividendePartsAnnuel(new BigDecimal("0.05"));
+ req.setPeriodiciteCalcul("MENSUEL");
+ req.setSeuilMinEpargneInterets(new BigDecimal("10000"));
+
+ assertThat(req.getOrganisationId()).isEqualTo("org-1");
+ assertThat(req.getValeurNominaleParDefaut()).isEqualByComparingTo("5000");
+ assertThat(req.getTauxInteretAnnuelEpargne()).isEqualByComparingTo("0.03");
+ assertThat(req.getTauxDividendePartsAnnuel()).isEqualByComparingTo("0.05");
+ assertThat(req.getPeriodiciteCalcul()).isEqualTo("MENSUEL");
+ }
+
+ @Test
+ void testBuilder() {
+ ParametresFinanciersMutuellRequest req = ParametresFinanciersMutuellRequest.builder()
+ .organisationId("org-2")
+ .periodiciteCalcul("ANNUEL")
+ .build();
+ assertThat(req.getOrganisationId()).isEqualTo("org-2");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellResponseTest.java
new file mode 100644
index 0000000..fc42303
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/financier/ParametresFinanciersMutuellResponseTest.java
@@ -0,0 +1,43 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.financier;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class ParametresFinanciersMutuellResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ParametresFinanciersMutuellResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDate prochaine = LocalDate.of(2026, 2, 1);
+ LocalDate derniere = LocalDate.of(2026, 1, 1);
+ ParametresFinanciersMutuellResponse resp = new ParametresFinanciersMutuellResponse();
+ resp.setOrganisationId("org-1");
+ resp.setOrganisationNom("Mutuelle Santé");
+ resp.setValeurNominaleParDefaut(new BigDecimal("5000"));
+ resp.setTauxInteretAnnuelEpargne(new BigDecimal("0.03"));
+ resp.setPeriodiciteCalcul("MENSUEL");
+ resp.setProchaineCalculInterets(prochaine);
+ resp.setDernierCalculInterets(derniere);
+ resp.setDernierNbComptesTraites(42);
+
+ assertThat(resp.getOrganisationId()).isEqualTo("org-1");
+ assertThat(resp.getValeurNominaleParDefaut()).isEqualByComparingTo("5000");
+ assertThat(resp.getProchaineCalculInterets()).isEqualTo(prochaine);
+ assertThat(resp.getDernierNbComptesTraites()).isEqualTo(42);
+ }
+
+ @Test
+ void testBuilder() {
+ ParametresFinanciersMutuellResponse resp = ParametresFinanciersMutuellResponse.builder()
+ .organisationNom("Test Mutuelle")
+ .build();
+ assertThat(resp.getOrganisationNom()).isEqualTo("Test Mutuelle");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesRequestTest.java
new file mode 100644
index 0000000..1742328
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesRequestTest.java
@@ -0,0 +1,39 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class ComptePartsSocialesRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ComptePartsSocialesRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ComptePartsSocialesRequest req = new ComptePartsSocialesRequest();
+ req.setMembreId("m-1");
+ req.setOrganisationId("org-1");
+ req.setNombreParts(5);
+ req.setValeurNominale(new BigDecimal("5000"));
+ req.setNotes("Souscription initiale");
+
+ assertThat(req.getMembreId()).isEqualTo("m-1");
+ assertThat(req.getOrganisationId()).isEqualTo("org-1");
+ assertThat(req.getNombreParts()).isEqualTo(5);
+ assertThat(req.getValeurNominale()).isEqualByComparingTo("5000");
+ assertThat(req.getNotes()).isEqualTo("Souscription initiale");
+ }
+
+ @Test
+ void testBuilder() {
+ ComptePartsSocialesRequest req = ComptePartsSocialesRequest.builder()
+ .membreId("m-2")
+ .nombreParts(10)
+ .build();
+ assertThat(req.getNombreParts()).isEqualTo(10);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesResponseTest.java
new file mode 100644
index 0000000..67f7943
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/ComptePartsSocialesResponseTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.parts.StatutComptePartsSociales;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class ComptePartsSocialesResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ComptePartsSocialesResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ComptePartsSocialesResponse resp = new ComptePartsSocialesResponse();
+ resp.setMembreId("m-1");
+ resp.setMembreNomComplet("Alice Dupont");
+ resp.setOrganisationId("org-1");
+ resp.setNumeroCompte("PS-MEG-001");
+ resp.setNombreParts(5);
+ resp.setValeurNominale(new BigDecimal("5000"));
+ resp.setMontantTotal(new BigDecimal("25000"));
+ resp.setTotalDividendesRecus(new BigDecimal("2500"));
+ resp.setStatut(StatutComptePartsSociales.ACTIF);
+ resp.setDateOuverture(LocalDate.of(2025, 1, 1));
+
+ assertThat(resp.getNumeroCompte()).isEqualTo("PS-MEG-001");
+ assertThat(resp.getNombreParts()).isEqualTo(5);
+ assertThat(resp.getMontantTotal()).isEqualByComparingTo("25000");
+ assertThat(resp.getStatut()).isEqualTo(StatutComptePartsSociales.ACTIF);
+ }
+
+ @Test
+ void testBuilder() {
+ ComptePartsSocialesResponse resp = ComptePartsSocialesResponse.builder()
+ .numeroCompte("PS-001")
+ .nombreParts(3)
+ .build();
+ assertThat(resp.getNombreParts()).isEqualTo(3);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesRequestTest.java
new file mode 100644
index 0000000..a7311b5
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesRequestTest.java
@@ -0,0 +1,40 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.parts.TypeTransactionPartsSociales;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class TransactionPartsSocialesRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TransactionPartsSocialesRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ TransactionPartsSocialesRequest req = new TransactionPartsSocialesRequest();
+ req.setCompteId("compte-1");
+ req.setTypeTransaction(TypeTransactionPartsSociales.SOUSCRIPTION);
+ req.setNombreParts(2);
+ req.setMontant(new BigDecimal("10000"));
+ req.setMotif("Souscription parts");
+ req.setReferenceExterne("REC-001");
+
+ assertThat(req.getCompteId()).isEqualTo("compte-1");
+ assertThat(req.getTypeTransaction()).isEqualTo(TypeTransactionPartsSociales.SOUSCRIPTION);
+ assertThat(req.getNombreParts()).isEqualTo(2);
+ assertThat(req.getMontant()).isEqualByComparingTo("10000");
+ }
+
+ @Test
+ void testBuilder() {
+ TransactionPartsSocialesRequest req = TransactionPartsSocialesRequest.builder()
+ .typeTransaction(TypeTransactionPartsSociales.RACHAT_TOTAL)
+ .nombreParts(1)
+ .build();
+ assertThat(req.getTypeTransaction()).isEqualTo(TypeTransactionPartsSociales.RACHAT_TOTAL);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesResponseTest.java
new file mode 100644
index 0000000..8fa98a9
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/mutuelle/parts/TransactionPartsSocialesResponseTest.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.mutuelle.parts;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.mutuelle.parts.TypeTransactionPartsSociales;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class TransactionPartsSocialesResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TransactionPartsSocialesResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime date = LocalDateTime.now();
+ TransactionPartsSocialesResponse resp = new TransactionPartsSocialesResponse();
+ resp.setCompteId("compte-1");
+ resp.setNumeroCompte("PS-001");
+ resp.setTypeTransaction(TypeTransactionPartsSociales.SOUSCRIPTION);
+ resp.setNombreParts(3);
+ resp.setMontant(new BigDecimal("15000"));
+ resp.setSoldePartsAvant(2);
+ resp.setSoldePartsApres(5);
+ resp.setMotif("Augmentation capital");
+ resp.setDateTransaction(date);
+
+ assertThat(resp.getNumeroCompte()).isEqualTo("PS-001");
+ assertThat(resp.getTypeTransaction()).isEqualTo(TypeTransactionPartsSociales.SOUSCRIPTION);
+ assertThat(resp.getNombreParts()).isEqualTo(3);
+ assertThat(resp.getSoldePartsAvant()).isEqualTo(2);
+ assertThat(resp.getSoldePartsApres()).isEqualTo(5);
+ }
+
+ @Test
+ void testBuilder() {
+ TransactionPartsSocialesResponse resp = TransactionPartsSocialesResponse.builder()
+ .nombreParts(1)
+ .typeTransaction(TypeTransactionPartsSociales.PAIEMENT_DIVIDENDE)
+ .build();
+ assertThat(resp.getTypeTransaction()).isEqualTo(TypeTransactionPartsSociales.PAIEMENT_DIVIDENDE);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/notification/response/NotificationResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/notification/response/NotificationResponseTest.java
new file mode 100644
index 0000000..158ad80
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/notification/response/NotificationResponseTest.java
@@ -0,0 +1,47 @@
+package dev.lions.unionflow.server.api.dto.notification.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class NotificationResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new NotificationResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID membreId = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+ NotificationResponse resp = new NotificationResponse();
+ resp.setTypeNotification("EMAIL");
+ resp.setPriorite("HAUTE");
+ resp.setStatut("ENVOYEE");
+ resp.setSujet("Rappel cotisation");
+ resp.setCorps("Votre cotisation est due");
+ resp.setDateEnvoi(now);
+ resp.setNombreTentatives(1);
+ resp.setMembreId(membreId);
+
+ assertThat(resp.getTypeNotification()).isEqualTo("EMAIL");
+ assertThat(resp.getPriorite()).isEqualTo("HAUTE");
+ assertThat(resp.getStatut()).isEqualTo("ENVOYEE");
+ assertThat(resp.getSujet()).isEqualTo("Rappel cotisation");
+ assertThat(resp.getDateEnvoi()).isEqualTo(now);
+ assertThat(resp.getNombreTentatives()).isEqualTo(1);
+ assertThat(resp.getMembreId()).isEqualTo(membreId);
+ }
+
+ @Test
+ void testBuilder() {
+ NotificationResponse resp = NotificationResponse.builder()
+ .typeNotification("SMS")
+ .statut("EN_ATTENTE")
+ .build();
+ assertThat(resp.getTypeNotification()).isEqualTo("SMS");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/notification/response/TemplateNotificationResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/notification/response/TemplateNotificationResponseTest.java
new file mode 100644
index 0000000..8e2bb0b
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/notification/response/TemplateNotificationResponseTest.java
@@ -0,0 +1,40 @@
+package dev.lions.unionflow.server.api.dto.notification.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class TemplateNotificationResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TemplateNotificationResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ TemplateNotificationResponse resp = new TemplateNotificationResponse();
+ resp.setCode("RAPPEL_COTISATION");
+ resp.setSujet("Rappel cotisation {mois}");
+ resp.setCorpsTexte("Bonjour {prenom}, votre cotisation est due");
+ resp.setCorpsHtml("Bonjour {prenom}
");
+ resp.setVariablesDisponibles("{prenom},{mois}");
+ resp.setCanauxSupportes("EMAIL,SMS");
+ resp.setLangue("fr");
+ resp.setDescription("Template rappel cotisation mensuelle");
+
+ assertThat(resp.getCode()).isEqualTo("RAPPEL_COTISATION");
+ assertThat(resp.getSujet()).contains("mois");
+ assertThat(resp.getCanauxSupportes()).isEqualTo("EMAIL,SMS");
+ assertThat(resp.getLangue()).isEqualTo("fr");
+ }
+
+ @Test
+ void testBuilder() {
+ TemplateNotificationResponse resp = TemplateNotificationResponse.builder()
+ .code("BIENVENUE")
+ .langue("fr")
+ .build();
+ assertThat(resp.getCode()).isEqualTo("BIENVENUE");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/ong/ProjetOngDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/ong/ProjetOngDTOTest.java
new file mode 100644
index 0000000..45b50be
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/ong/ProjetOngDTOTest.java
@@ -0,0 +1,43 @@
+package dev.lions.unionflow.server.api.dto.ong;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.ong.StatutProjetOng;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class ProjetOngDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new ProjetOngDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ProjetOngDTO dto = new ProjetOngDTO();
+ dto.setOrganisationId("org-1");
+ dto.setNomProjet("Projet Eau Potable");
+ dto.setDescriptionMandat("Accès eau potable zone rurale");
+ dto.setZoneGeographiqueIntervention("Thiès");
+ dto.setBudgetPrevisionnel(new BigDecimal("5000000"));
+ dto.setDepensesReelles(new BigDecimal("2000000"));
+ dto.setDateLancement(LocalDate.of(2025, 1, 1));
+ dto.setDateFinEstimee(LocalDate.of(2026, 12, 31));
+ dto.setStatut(StatutProjetOng.EN_COURS);
+
+ assertThat(dto.getNomProjet()).isEqualTo("Projet Eau Potable");
+ assertThat(dto.getBudgetPrevisionnel()).isEqualByComparingTo("5000000");
+ assertThat(dto.getStatut()).isEqualTo(StatutProjetOng.EN_COURS);
+ }
+
+ @Test
+ void testBuilder() {
+ ProjetOngDTO dto = ProjetOngDTO.builder()
+ .nomProjet("Alphabétisation")
+ .statut(StatutProjetOng.EN_ETUDE)
+ .build();
+ assertThat(dto.getNomProjet()).isEqualTo("Alphabétisation");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequestTest.java
index 44fb1df..d19662e 100644
--- a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequestTest.java
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/CreatePaiementRequestTest.java
@@ -1,221 +1,96 @@
package dev.lions.unionflow.server.api.dto.paiement.request;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
import static org.assertj.core.api.Assertions.assertThat;
-import jakarta.validation.ConstraintViolation;
-import jakarta.validation.Validation;
-import jakarta.validation.Validator;
-import jakarta.validation.ValidatorFactory;
-import java.math.BigDecimal;
-import java.util.Set;
-import java.util.UUID;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
+@DisplayName("CreatePaiementRequest")
class CreatePaiementRequestTest {
- private Validator validator;
+ @Test
+ @DisplayName("builder — tous les champs")
+ void builder_allFields() {
+ UUID membreId = UUID.randomUUID();
- @BeforeEach
- void setUp() {
- ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
- validator = factory.getValidator();
- }
+ CreatePaiementRequest req = CreatePaiementRequest.builder()
+ .numeroReference("REF-001")
+ .montant(new BigDecimal("5000.00"))
+ .codeDevise("XOF")
+ .methodePaiement("WAVE")
+ .commentaire("Cotisation avril")
+ .membreId(membreId)
+ .build();
- @Test
- void testBuilder_AllFields() {
- UUID membreId = UUID.randomUUID();
- BigDecimal montant = new BigDecimal("5000.00");
+ assertThat(req.numeroReference()).isEqualTo("REF-001");
+ assertThat(req.montant()).isEqualByComparingTo("5000.00");
+ assertThat(req.codeDevise()).isEqualTo("XOF");
+ assertThat(req.methodePaiement()).isEqualTo("WAVE");
+ assertThat(req.commentaire()).isEqualTo("Cotisation avril");
+ assertThat(req.membreId()).isEqualTo(membreId);
+ }
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000001")
- .montant(montant)
- .codeDevise("XOF")
- .methodePaiement("WAVE")
- .commentaire("Paiement pour cotisation mensuelle")
- .membreId(membreId)
- .build();
+ @Test
+ @DisplayName("builder — champs optionnels null")
+ void builder_optionalNull() {
+ CreatePaiementRequest req = CreatePaiementRequest.builder()
+ .numeroReference("REF-002")
+ .montant(new BigDecimal("1000"))
+ .codeDevise("XOF")
+ .methodePaiement("ESPECES")
+ .build();
- assertThat(request).isNotNull();
- assertThat(request.numeroReference()).isEqualTo("PAY-2025-000001");
- assertThat(request.montant()).isEqualByComparingTo(montant);
- assertThat(request.codeDevise()).isEqualTo("XOF");
- assertThat(request.methodePaiement()).isEqualTo("WAVE");
- assertThat(request.commentaire()).isEqualTo("Paiement pour cotisation mensuelle");
- assertThat(request.membreId()).isEqualTo(membreId);
- }
+ assertThat(req.commentaire()).isNull();
+ assertThat(req.membreId()).isNull();
+ }
- @Test
- void testBuilder_MinimalFields() {
- UUID membreId = UUID.randomUUID();
+ @Test
+ @DisplayName("constructeur canonique")
+ void canonicalConstructor() {
+ UUID membreId = UUID.randomUUID();
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000002")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("EUR")
- .methodePaiement("ESPECES")
- .membreId(membreId)
- .build();
+ CreatePaiementRequest req = new CreatePaiementRequest(
+ "REF-003", new BigDecimal("2500"), "XOF", "ORANGE_MONEY", null, membreId);
- assertThat(request).isNotNull();
- assertThat(request.numeroReference()).isEqualTo("PAY-2025-000002");
- assertThat(request.montant()).isEqualByComparingTo(new BigDecimal("1000.00"));
- assertThat(request.codeDevise()).isEqualTo("EUR");
- assertThat(request.methodePaiement()).isEqualTo("ESPECES");
- assertThat(request.membreId()).isEqualTo(membreId);
- assertThat(request.commentaire()).isNull();
- }
+ assertThat(req.numeroReference()).isEqualTo("REF-003");
+ assertThat(req.montant()).isEqualByComparingTo("2500");
+ assertThat(req.membreId()).isEqualTo(membreId);
+ }
- @Test
- void testValidation_MissingRequiredFields() {
- CreatePaiementRequest request = CreatePaiementRequest.builder().build();
+ @Test
+ @DisplayName("equals et hashCode — mêmes données")
+ void equalsHashCode_sameData() {
+ UUID membreId = UUID.randomUUID();
- Set> violations = validator.validate(request);
+ CreatePaiementRequest a = new CreatePaiementRequest("REF", new BigDecimal("1000"), "XOF", "WAVE", null, membreId);
+ CreatePaiementRequest b = new CreatePaiementRequest("REF", new BigDecimal("1000"), "XOF", "WAVE", null, membreId);
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroReference"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("montant"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("codeDevise"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("membreId"));
- }
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
- @Test
- void testValidation_BlankNumeroReference() {
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference(" ")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("XOF")
- .methodePaiement("WAVE")
- .membreId(UUID.randomUUID())
- .build();
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ CreatePaiementRequest a = new CreatePaiementRequest("REF-A", new BigDecimal("1000"), "XOF", "WAVE", null, null);
+ CreatePaiementRequest b = new CreatePaiementRequest("REF-B", new BigDecimal("2000"), "XOF", "WAVE", null, null);
- Set> violations = validator.validate(request);
+ assertThat(a).isNotEqualTo(b);
+ }
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroReference"));
- }
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ CreatePaiementRequest req = CreatePaiementRequest.builder()
+ .numeroReference("REF-004")
+ .montant(new BigDecimal("500"))
+ .codeDevise("XOF")
+ .methodePaiement("ESPECES")
+ .build();
- @Test
- void testValidation_MontantNegatif() {
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000003")
- .montant(new BigDecimal("-100.00"))
- .codeDevise("XOF")
- .methodePaiement("WAVE")
- .membreId(UUID.randomUUID())
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("montant"));
- }
-
- @Test
- void testValidation_CodeDeviseInvalide() {
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000004")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("INVALID")
- .methodePaiement("WAVE")
- .membreId(UUID.randomUUID())
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("codeDevise"));
- }
-
- @Test
- void testValidation_CodeDeviseTooShort() {
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000005")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("XO")
- .methodePaiement("WAVE")
- .membreId(UUID.randomUUID())
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("codeDevise"));
- }
-
- @Test
- void testValidation_BlankMethodePaiement() {
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000006")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("XOF")
- .methodePaiement(" ")
- .membreId(UUID.randomUUID())
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement"));
- }
-
- @Test
- void testValidation_ValidFields() {
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000007")
- .montant(new BigDecimal("5000.00"))
- .codeDevise("XOF")
- .methodePaiement("WAVE")
- .commentaire("Paiement mensuel")
- .membreId(UUID.randomUUID())
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testEquals() {
- UUID membreId = UUID.randomUUID();
-
- CreatePaiementRequest request1 = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000008")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("XOF")
- .methodePaiement("WAVE")
- .membreId(membreId)
- .build();
-
- CreatePaiementRequest request2 = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000008")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("XOF")
- .methodePaiement("WAVE")
- .membreId(membreId)
- .build();
-
- assertThat(request1).isEqualTo(request2);
- assertThat(request1.hashCode()).isEqualTo(request2.hashCode());
- }
-
- @Test
- void testToString() {
- CreatePaiementRequest request = CreatePaiementRequest.builder()
- .numeroReference("PAY-2025-000009")
- .montant(new BigDecimal("1000.00"))
- .codeDevise("XOF")
- .methodePaiement("WAVE")
- .membreId(UUID.randomUUID())
- .build();
-
- String toString = request.toString();
-
- assertThat(toString).isNotNull();
- assertThat(toString).contains("CreatePaiementRequest");
- assertThat(toString).contains("PAY-2025-000009");
- assertThat(toString).contains("XOF");
- assertThat(toString).contains("WAVE");
- }
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequestTest.java
index faee781..c30ca7d 100644
--- a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequestTest.java
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/DeclarerPaiementManuelRequestTest.java
@@ -1,230 +1,70 @@
package dev.lions.unionflow.server.api.dto.paiement.request;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.UUID;
+
import static org.assertj.core.api.Assertions.assertThat;
-import jakarta.validation.ConstraintViolation;
-import jakarta.validation.Validation;
-import jakarta.validation.Validator;
-import jakarta.validation.ValidatorFactory;
-import java.util.Set;
-import java.util.UUID;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
+@DisplayName("DeclarerPaiementManuelRequest")
class DeclarerPaiementManuelRequestTest {
- private Validator validator;
+ @Test
+ @DisplayName("constructeur — tous les champs")
+ void constructor_allFields() {
+ UUID cotisationId = UUID.randomUUID();
- @BeforeEach
- void setUp() {
- ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
- validator = factory.getValidator();
- }
+ DeclarerPaiementManuelRequest req = new DeclarerPaiementManuelRequest(
+ cotisationId, "VIREMENT", "VIR-2026-001", "Virement bancaire SGBS");
- @Test
- void testBuilder_AllFields() {
- UUID cotisationId = UUID.randomUUID();
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.methodePaiement()).isEqualTo("VIREMENT");
+ assertThat(req.reference()).isEqualTo("VIR-2026-001");
+ assertThat(req.commentaire()).isEqualTo("Virement bancaire SGBS");
+ }
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("ESPECES")
- .reference("REF-2025-001")
- .commentaire("Paiement reçu en espèces")
- .origineFonds("Salaire mensuel")
- .justificationLcbFt("Bulletin de salaire fourni")
- .build();
+ @Test
+ @DisplayName("constructeur — champs optionnels null")
+ void constructor_optionalNull() {
+ UUID cotisationId = UUID.randomUUID();
- assertThat(request).isNotNull();
- assertThat(request.cotisationId()).isEqualTo(cotisationId);
- assertThat(request.methodePaiement()).isEqualTo("ESPECES");
- assertThat(request.reference()).isEqualTo("REF-2025-001");
- assertThat(request.commentaire()).isEqualTo("Paiement reçu en espèces");
- assertThat(request.origineFonds()).isEqualTo("Salaire mensuel");
- assertThat(request.justificationLcbFt()).isEqualTo("Bulletin de salaire fourni");
- }
+ DeclarerPaiementManuelRequest req = new DeclarerPaiementManuelRequest(
+ cotisationId, "ESPECES", null, null);
- @Test
- void testBuilder_MinimalFields() {
- UUID cotisationId = UUID.randomUUID();
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.methodePaiement()).isEqualTo("ESPECES");
+ assertThat(req.reference()).isNull();
+ assertThat(req.commentaire()).isNull();
+ }
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("VIREMENT")
- .build();
+ @Test
+ @DisplayName("equals et hashCode — mêmes données")
+ void equalsHashCode_sameData() {
+ UUID cotisationId = UUID.randomUUID();
- assertThat(request).isNotNull();
- assertThat(request.cotisationId()).isEqualTo(cotisationId);
- assertThat(request.methodePaiement()).isEqualTo("VIREMENT");
- assertThat(request.reference()).isNull();
- assertThat(request.commentaire()).isNull();
- assertThat(request.origineFonds()).isNull();
- assertThat(request.justificationLcbFt()).isNull();
- }
+ DeclarerPaiementManuelRequest a = new DeclarerPaiementManuelRequest(cotisationId, "CHEQUE", "CHQ-001", null);
+ DeclarerPaiementManuelRequest b = new DeclarerPaiementManuelRequest(cotisationId, "CHEQUE", "CHQ-001", null);
- @Test
- void testValidation_MissingRequiredFields() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder().build();
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
- Set> violations = validator.validate(request);
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ DeclarerPaiementManuelRequest a = new DeclarerPaiementManuelRequest(UUID.randomUUID(), "ESPECES", null, null);
+ DeclarerPaiementManuelRequest b = new DeclarerPaiementManuelRequest(UUID.randomUUID(), "CHEQUE", "CHQ-002", null);
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("cotisationId"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement"));
- }
+ assertThat(a).isNotEqualTo(b);
+ }
- @Test
- void testValidation_BlankMethodePaiement() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement(" ")
- .build();
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ DeclarerPaiementManuelRequest req = new DeclarerPaiementManuelRequest(
+ UUID.randomUUID(), "ESPECES", null, "Paiement en espèces");
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement"));
- }
-
- @Test
- void testValidation_InvalidMethodePaiement() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("PAYPAL")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement")
- && v.getMessage().contains("Valeurs autorisées : ESPECES, VIREMENT, CHEQUE, AUTRE"));
- }
-
- @Test
- void testValidation_ReferenceTooLong() {
- String longReference = "A".repeat(101);
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("ESPECES")
- .reference(longReference)
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("reference"));
- }
-
- @Test
- void testValidation_CommentaireTooLong() {
- String longCommentaire = "A".repeat(501);
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("ESPECES")
- .commentaire(longCommentaire)
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("commentaire"));
- }
-
- @Test
- void testValidation_ValidMethodePaiement_ESPECES() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("ESPECES")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidMethodePaiement_VIREMENT() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("VIREMENT")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidMethodePaiement_CHEQUE() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("CHEQUE")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidMethodePaiement_AUTRE() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("AUTRE")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidFields() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("ESPECES")
- .reference("REF-2025-001")
- .commentaire("Paiement mensuel")
- .origineFonds("Salaire")
- .justificationLcbFt("Bulletin de paie")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testEquals() {
- UUID cotisationId = UUID.randomUUID();
-
- DeclarerPaiementManuelRequest request1 = DeclarerPaiementManuelRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("ESPECES")
- .reference("REF-001")
- .build();
-
- DeclarerPaiementManuelRequest request2 = DeclarerPaiementManuelRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("ESPECES")
- .reference("REF-001")
- .build();
-
- assertThat(request1).isEqualTo(request2);
- assertThat(request1.hashCode()).isEqualTo(request2.hashCode());
- }
-
- @Test
- void testToString() {
- DeclarerPaiementManuelRequest request = DeclarerPaiementManuelRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("ESPECES")
- .reference("REF-001")
- .build();
-
- String toString = request.toString();
-
- assertThat(toString).isNotNull();
- assertThat(toString).contains("DeclarerPaiementManuelRequest");
- assertThat(toString).contains("ESPECES");
- }
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierDepotEpargneRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierDepotEpargneRequestTest.java
index 108c7cf..cac5a35 100644
--- a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierDepotEpargneRequestTest.java
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierDepotEpargneRequestTest.java
@@ -1,249 +1,108 @@
package dev.lions.unionflow.server.api.dto.paiement.request;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
import static org.assertj.core.api.Assertions.assertThat;
-import jakarta.validation.ConstraintViolation;
-import jakarta.validation.Validation;
-import jakarta.validation.Validator;
-import jakarta.validation.ValidatorFactory;
-import java.math.BigDecimal;
-import java.util.Set;
-import java.util.UUID;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
+/**
+ * Tests unitaires pour {@link InitierDepotEpargneRequest}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("InitierDepotEpargneRequest (paiement)")
class InitierDepotEpargneRequestTest {
- private Validator validator;
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ UUID compteId = UUID.randomUUID();
- @BeforeEach
- void setUp() {
- ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
- validator = factory.getValidator();
- }
+ InitierDepotEpargneRequest req = InitierDepotEpargneRequest.builder()
+ .compteId(compteId)
+ .montant(new BigDecimal("10000.00"))
+ .numeroTelephone("771234567")
+ .origineFonds("Salaire")
+ .justificationLcbFt("Épargne mensuelle")
+ .build();
- @Test
- void testBuilder_AllFields() {
- UUID compteId = UUID.randomUUID();
+ assertThat(req.compteId()).isEqualTo(compteId);
+ assertThat(req.montant()).isEqualByComparingTo("10000.00");
+ assertThat(req.numeroTelephone()).isEqualTo("771234567");
+ assertThat(req.origineFonds()).isEqualTo("Salaire");
+ assertThat(req.justificationLcbFt()).isEqualTo("Épargne mensuelle");
+ }
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(compteId)
- .montant(new BigDecimal("50000"))
- .numeroTelephone("771234567")
- .origineFonds("Salaire mensuel")
- .justificationLcbFt("Bulletin de salaire du mois de mars 2025")
- .build();
+ @Test
+ @DisplayName("builder — champs optionnels null")
+ void builder_optionalFieldsNull() {
+ UUID compteId = UUID.randomUUID();
- assertThat(request).isNotNull();
- assertThat(request.compteId()).isEqualTo(compteId);
- assertThat(request.montant()).isEqualByComparingTo(new BigDecimal("50000"));
- assertThat(request.numeroTelephone()).isEqualTo("771234567");
- assertThat(request.origineFonds()).isEqualTo("Salaire mensuel");
- assertThat(request.justificationLcbFt()).isEqualTo("Bulletin de salaire du mois de mars 2025");
- }
+ InitierDepotEpargneRequest req = InitierDepotEpargneRequest.builder()
+ .compteId(compteId)
+ .montant(new BigDecimal("5000"))
+ .build();
- @Test
- void testBuilder_MinimalFields() {
- UUID compteId = UUID.randomUUID();
+ assertThat(req.compteId()).isEqualTo(compteId);
+ assertThat(req.montant()).isEqualByComparingTo("5000");
+ assertThat(req.numeroTelephone()).isNull();
+ assertThat(req.origineFonds()).isNull();
+ assertThat(req.justificationLcbFt()).isNull();
+ }
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(compteId)
- .montant(new BigDecimal("10000"))
- .numeroTelephone("771234567")
- .build();
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ UUID compteId = UUID.randomUUID();
- assertThat(request).isNotNull();
- assertThat(request.compteId()).isEqualTo(compteId);
- assertThat(request.montant()).isEqualByComparingTo(new BigDecimal("10000"));
- assertThat(request.numeroTelephone()).isEqualTo("771234567");
- assertThat(request.origineFonds()).isNull();
- assertThat(request.justificationLcbFt()).isNull();
- }
+ InitierDepotEpargneRequest req = new InitierDepotEpargneRequest(
+ compteId, new BigDecimal("25000"), "701234567", null, null);
- @Test
- void testValidation_MissingRequiredFields() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder().build();
+ assertThat(req.compteId()).isEqualTo(compteId);
+ assertThat(req.montant()).isEqualByComparingTo("25000");
+ assertThat(req.numeroTelephone()).isEqualTo("701234567");
+ assertThat(req.origineFonds()).isNull();
+ assertThat(req.justificationLcbFt()).isNull();
+ }
- Set> violations = validator.validate(request);
+ @Test
+ @DisplayName("equals et hashCode — mêmes données")
+ void equalsHashCode_sameData() {
+ UUID compteId = UUID.randomUUID();
+ BigDecimal montant = new BigDecimal("10000");
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("compteId"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("montant"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
+ InitierDepotEpargneRequest a = new InitierDepotEpargneRequest(compteId, montant, "771234567", null, null);
+ InitierDepotEpargneRequest b = new InitierDepotEpargneRequest(compteId, montant, "771234567", null, null);
- @Test
- void testValidation_MontantZero() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(BigDecimal.ZERO)
- .numeroTelephone("771234567")
- .build();
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
- Set> violations = validator.validate(request);
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ InitierDepotEpargneRequest a = new InitierDepotEpargneRequest(
+ UUID.randomUUID(), new BigDecimal("5000"), "701234567", null, null);
+ InitierDepotEpargneRequest b = new InitierDepotEpargneRequest(
+ UUID.randomUUID(), new BigDecimal("10000"), "771234567", null, null);
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("montant")
- && v.getMessage().contains("strictement positif"));
- }
+ assertThat(a).isNotEqualTo(b);
+ }
- @Test
- void testValidation_MontantNegatif() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("-1000"))
- .numeroTelephone("771234567")
- .build();
+ @Test
+ @DisplayName("toString non null et non vide")
+ void toString_nonNull() {
+ InitierDepotEpargneRequest req = InitierDepotEpargneRequest.builder()
+ .compteId(UUID.randomUUID())
+ .montant(new BigDecimal("5000"))
+ .numeroTelephone("771234567")
+ .build();
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("montant"));
- }
-
- @Test
- void testValidation_BlankNumeroTelephone() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("10000"))
- .numeroTelephone(" ")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
-
- @Test
- void testValidation_NumeroTelephoneTooShort() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("10000"))
- .numeroTelephone("12345678")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone")
- && v.getMessage().contains("9-15 chiffres"));
- }
-
- @Test
- void testValidation_NumeroTelephoneTooLong() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("10000"))
- .numeroTelephone("1234567890123456")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
-
- @Test
- void testValidation_NumeroTelephoneInvalidFormat() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("10000"))
- .numeroTelephone("77-123-4567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
-
- @Test
- void testValidation_ValidNumeroTelephone_9Digits() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("10000"))
- .numeroTelephone("771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidNumeroTelephone_12Digits() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("10000"))
- .numeroTelephone("221771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidNumeroTelephone_15Digits() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("10000"))
- .numeroTelephone("221771234567890")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidFields() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("50000"))
- .numeroTelephone("771234567")
- .origineFonds("Salaire")
- .justificationLcbFt("Bulletin de paie")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testEquals() {
- UUID compteId = UUID.randomUUID();
-
- InitierDepotEpargneRequest request1 = InitierDepotEpargneRequest.builder()
- .compteId(compteId)
- .montant(new BigDecimal("10000"))
- .numeroTelephone("771234567")
- .build();
-
- InitierDepotEpargneRequest request2 = InitierDepotEpargneRequest.builder()
- .compteId(compteId)
- .montant(new BigDecimal("10000"))
- .numeroTelephone("771234567")
- .build();
-
- assertThat(request1).isEqualTo(request2);
- assertThat(request1.hashCode()).isEqualTo(request2.hashCode());
- }
-
- @Test
- void testToString() {
- InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
- .compteId(UUID.randomUUID())
- .montant(new BigDecimal("50000"))
- .numeroTelephone("771234567")
- .build();
-
- String toString = request.toString();
-
- assertThat(toString).isNotNull();
- assertThat(toString).contains("InitierDepotEpargneRequest");
- assertThat(toString).contains("771234567");
- }
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequestTest.java
index 5654f1c..9ee7f4a 100644
--- a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequestTest.java
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/request/InitierPaiementEnLigneRequestTest.java
@@ -1,303 +1,68 @@
package dev.lions.unionflow.server.api.dto.paiement.request;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.UUID;
+
import static org.assertj.core.api.Assertions.assertThat;
-import jakarta.validation.ConstraintViolation;
-import jakarta.validation.Validation;
-import jakarta.validation.Validator;
-import jakarta.validation.ValidatorFactory;
-import java.util.Set;
-import java.util.UUID;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
+@DisplayName("InitierPaiementEnLigneRequest")
class InitierPaiementEnLigneRequestTest {
- private Validator validator;
+ @Test
+ @DisplayName("constructeur — tous les champs")
+ void constructor_allFields() {
+ UUID cotisationId = UUID.randomUUID();
- @BeforeEach
- void setUp() {
- ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
- validator = factory.getValidator();
- }
+ InitierPaiementEnLigneRequest req = new InitierPaiementEnLigneRequest(
+ cotisationId, "WAVE", "771234567");
- @Test
- void testBuilder_AllFields() {
- UUID cotisationId = UUID.randomUUID();
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.methodePaiement()).isEqualTo("WAVE");
+ assertThat(req.numeroTelephone()).isEqualTo("771234567");
+ }
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("WAVE")
- .numeroTelephone("771234567")
- .origineFonds("Salaire mensuel")
- .justificationLcbFt("Bulletin de salaire du mois de mars 2025")
- .build();
+ @Test
+ @DisplayName("constructeur — numeroTelephone null")
+ void constructor_telephoneNull() {
+ UUID cotisationId = UUID.randomUUID();
- assertThat(request).isNotNull();
- assertThat(request.cotisationId()).isEqualTo(cotisationId);
- assertThat(request.methodePaiement()).isEqualTo("WAVE");
- assertThat(request.numeroTelephone()).isEqualTo("771234567");
- assertThat(request.origineFonds()).isEqualTo("Salaire mensuel");
- assertThat(request.justificationLcbFt()).isEqualTo("Bulletin de salaire du mois de mars 2025");
- }
+ InitierPaiementEnLigneRequest req = new InitierPaiementEnLigneRequest(
+ cotisationId, "CARTE_BANCAIRE", null);
- @Test
- void testBuilder_MinimalFields() {
- UUID cotisationId = UUID.randomUUID();
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.methodePaiement()).isEqualTo("CARTE_BANCAIRE");
+ assertThat(req.numeroTelephone()).isNull();
+ }
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("ORANGE_MONEY")
- .numeroTelephone("771234567")
- .build();
+ @Test
+ @DisplayName("equals et hashCode — mêmes données")
+ void equalsHashCode_sameData() {
+ UUID cotisationId = UUID.randomUUID();
- assertThat(request).isNotNull();
- assertThat(request.cotisationId()).isEqualTo(cotisationId);
- assertThat(request.methodePaiement()).isEqualTo("ORANGE_MONEY");
- assertThat(request.numeroTelephone()).isEqualTo("771234567");
- assertThat(request.origineFonds()).isNull();
- assertThat(request.justificationLcbFt()).isNull();
- }
+ InitierPaiementEnLigneRequest a = new InitierPaiementEnLigneRequest(cotisationId, "WAVE", "771234567");
+ InitierPaiementEnLigneRequest b = new InitierPaiementEnLigneRequest(cotisationId, "WAVE", "771234567");
- @Test
- void testValidation_MissingRequiredFields() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder().build();
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
- Set> violations = validator.validate(request);
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ InitierPaiementEnLigneRequest a = new InitierPaiementEnLigneRequest(UUID.randomUUID(), "WAVE", "771234567");
+ InitierPaiementEnLigneRequest b = new InitierPaiementEnLigneRequest(UUID.randomUUID(), "ORANGE_MONEY", "701234567");
- // cotisationId et methodePaiement sont obligatoires
- // numeroTelephone est optionnel (web QR sans restriction de payeur)
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("cotisationId"));
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement"));
- assertThat(violations).noneMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
+ assertThat(a).isNotEqualTo(b);
+ }
- @Test
- void testValidation_BlankMethodePaiement() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement(" ")
- .numeroTelephone("771234567")
- .build();
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ InitierPaiementEnLigneRequest req = new InitierPaiementEnLigneRequest(
+ UUID.randomUUID(), "WAVE", "771234567");
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement"));
- }
-
- @Test
- void testValidation_InvalidMethodePaiement() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("PAYPAL")
- .numeroTelephone("771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("methodePaiement")
- && v.getMessage().contains("Valeurs autorisées : WAVE, ORANGE_MONEY, FREE_MONEY, CARTE_BANCAIRE"));
- }
-
- @Test
- void testValidation_BlankNumeroTelephone() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone(" ")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
-
- @Test
- void testValidation_NumeroTelephoneTooShort() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("12345678")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone")
- && v.getMessage().contains("9-15 chiffres"));
- }
-
- @Test
- void testValidation_NumeroTelephoneTooLong() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("1234567890123456")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
-
- @Test
- void testValidation_NumeroTelephoneInvalidFormat() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("77-123-4567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isNotEmpty();
- assertThat(violations).anyMatch(v -> v.getPropertyPath().toString().equals("numeroTelephone"));
- }
-
- @Test
- void testValidation_ValidMethodePaiement_WAVE() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidMethodePaiement_ORANGE_MONEY() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("ORANGE_MONEY")
- .numeroTelephone("771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidMethodePaiement_FREE_MONEY() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("FREE_MONEY")
- .numeroTelephone("771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidMethodePaiement_CARTE_BANCAIRE() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("CARTE_BANCAIRE")
- .numeroTelephone("771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidNumeroTelephone_9Digits() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidNumeroTelephone_12Digits() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("221771234567")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidNumeroTelephone_15Digits() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("221771234567890")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testValidation_ValidFields() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("771234567")
- .origineFonds("Salaire")
- .justificationLcbFt("Bulletin de paie")
- .build();
-
- Set> violations = validator.validate(request);
-
- assertThat(violations).isEmpty();
- }
-
- @Test
- void testEquals() {
- UUID cotisationId = UUID.randomUUID();
-
- InitierPaiementEnLigneRequest request1 = InitierPaiementEnLigneRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("WAVE")
- .numeroTelephone("771234567")
- .build();
-
- InitierPaiementEnLigneRequest request2 = InitierPaiementEnLigneRequest.builder()
- .cotisationId(cotisationId)
- .methodePaiement("WAVE")
- .numeroTelephone("771234567")
- .build();
-
- assertThat(request1).isEqualTo(request2);
- assertThat(request1.hashCode()).isEqualTo(request2.hashCode());
- }
-
- @Test
- void testToString() {
- InitierPaiementEnLigneRequest request = InitierPaiementEnLigneRequest.builder()
- .cotisationId(UUID.randomUUID())
- .methodePaiement("WAVE")
- .numeroTelephone("771234567")
- .build();
-
- String toString = request.toString();
-
- assertThat(toString).isNotNull();
- assertThat(toString).contains("InitierPaiementEnLigneRequest");
- assertThat(toString).contains("WAVE");
- assertThat(toString).contains("771234567");
- }
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponseTest.java
index 2702551..14891fd 100644
--- a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponseTest.java
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/IntentionStatutResponseTest.java
@@ -1,112 +1,99 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.util.UUID;
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DisplayName("IntentionStatutResponse")
class IntentionStatutResponseTest {
- @Test
- void testBuilder_AllFields() {
- UUID intentionId = UUID.randomUUID();
+ @Test
+ @DisplayName("builder — tous les champs")
+ void builder_allFields() {
+ UUID intentionId = UUID.randomUUID();
- IntentionStatutResponse response = IntentionStatutResponse.builder()
- .intentionId(intentionId)
- .statut("COMPLETEE")
- .waveLaunchUrl("https://pay.wave.com/c/cos-abc123")
- .waveCheckoutSessionId("cos-abc123")
- .waveTransactionId("TCN4Y4ZC3FM")
- .montant(new BigDecimal("5000"))
- .referenceCotisation("COT-2025-001")
- .message("Paiement confirmé !")
- .build();
+ IntentionStatutResponse resp = IntentionStatutResponse.builder()
+ .intentionId(intentionId)
+ .statut("COMPLETEE")
+ .confirme(true)
+ .waveLaunchUrl("wave://checkout/abc")
+ .waveCheckoutSessionId("cos-abc123")
+ .waveTransactionId("TCN-001")
+ .montant(new BigDecimal("5000.00"))
+ .referenceCotisation("COT-2026-001")
+ .message("Paiement confirmé")
+ .build();
- assertThat(response).isNotNull();
- assertThat(response.getIntentionId()).isEqualTo(intentionId);
- assertThat(response.getStatut()).isEqualTo("COMPLETEE");
- assertThat(response.getWaveLaunchUrl()).isEqualTo("https://pay.wave.com/c/cos-abc123");
- assertThat(response.getWaveCheckoutSessionId()).isEqualTo("cos-abc123");
- assertThat(response.getWaveTransactionId()).isEqualTo("TCN4Y4ZC3FM");
- assertThat(response.getMontant()).isEqualByComparingTo(new BigDecimal("5000"));
- assertThat(response.getReferenceCotisation()).isEqualTo("COT-2025-001");
- assertThat(response.getMessage()).isEqualTo("Paiement confirmé !");
- }
+ assertThat(resp.getIntentionId()).isEqualTo(intentionId);
+ assertThat(resp.getStatut()).isEqualTo("COMPLETEE");
+ assertThat(resp.isConfirme()).isTrue();
+ assertThat(resp.getWaveLaunchUrl()).isEqualTo("wave://checkout/abc");
+ assertThat(resp.getWaveCheckoutSessionId()).isEqualTo("cos-abc123");
+ assertThat(resp.getWaveTransactionId()).isEqualTo("TCN-001");
+ assertThat(resp.getMontant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.getReferenceCotisation()).isEqualTo("COT-2026-001");
+ assertThat(resp.getMessage()).isEqualTo("Paiement confirmé");
+ }
- @Test
- void testBuilder_EnCours() {
- UUID intentionId = UUID.randomUUID();
+ @Test
+ @DisplayName("no-args constructor — champs null/false")
+ void noArgsConstructor() {
+ IntentionStatutResponse resp = new IntentionStatutResponse();
- IntentionStatutResponse response = IntentionStatutResponse.builder()
- .intentionId(intentionId)
- .statut("EN_COURS")
- .waveLaunchUrl("https://pay.wave.com/c/cos-xyz789")
- .waveCheckoutSessionId("cos-xyz789")
- .montant(new BigDecimal("10000"))
- .message("En attente de confirmation Wave...")
- .build();
+ assertThat(resp.getStatut()).isNull();
+ assertThat(resp.isConfirme()).isFalse();
+ assertThat(resp.getIntentionId()).isNull();
+ }
- assertThat(response.getIntentionId()).isEqualTo(intentionId);
- assertThat(response.getStatut()).isEqualTo("EN_COURS");
- assertThat(response.getWaveLaunchUrl()).isEqualTo("https://pay.wave.com/c/cos-xyz789");
- assertThat(response.getWaveTransactionId()).isNull();
- assertThat(response.getReferenceCotisation()).isNull();
- }
+ @Test
+ @DisplayName("all-args constructor")
+ void allArgsConstructor() {
+ UUID id = UUID.randomUUID();
- @Test
- void testBuilder_Expiree() {
- UUID intentionId = UUID.randomUUID();
+ IntentionStatutResponse resp = new IntentionStatutResponse(
+ id, "EN_ATTENTE", false, null, null, null, null, null, null);
- IntentionStatutResponse response = IntentionStatutResponse.builder()
- .intentionId(intentionId)
- .statut("EXPIREE")
- .montant(new BigDecimal("2500"))
- .message("Session Wave expirée")
- .build();
+ assertThat(resp.getIntentionId()).isEqualTo(id);
+ assertThat(resp.getStatut()).isEqualTo("EN_ATTENTE");
+ assertThat(resp.isConfirme()).isFalse();
+ }
- assertThat(response.getStatut()).isEqualTo("EXPIREE");
- assertThat(response.getWaveLaunchUrl()).isNull();
- assertThat(response.getWaveCheckoutSessionId()).isNull();
- assertThat(response.getWaveTransactionId()).isNull();
- }
+ @Test
+ @DisplayName("equals et hashCode — mêmes données")
+ void equalsHashCode_sameData() {
+ UUID id = UUID.randomUUID();
- @Test
- void testEquals_SameFields() {
- UUID intentionId = UUID.randomUUID();
+ IntentionStatutResponse a = IntentionStatutResponse.builder()
+ .intentionId(id).statut("COMPLETEE").confirme(true).build();
+ IntentionStatutResponse b = IntentionStatutResponse.builder()
+ .intentionId(id).statut("COMPLETEE").confirme(true).build();
- IntentionStatutResponse r1 = IntentionStatutResponse.builder()
- .intentionId(intentionId)
- .statut("EN_COURS")
- .waveLaunchUrl("https://pay.wave.com/c/cos-abc")
- .waveCheckoutSessionId("cos-abc")
- .montant(new BigDecimal("5000"))
- .build();
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
- IntentionStatutResponse r2 = IntentionStatutResponse.builder()
- .intentionId(intentionId)
- .statut("EN_COURS")
- .waveLaunchUrl("https://pay.wave.com/c/cos-abc")
- .waveCheckoutSessionId("cos-abc")
- .montant(new BigDecimal("5000"))
- .build();
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ IntentionStatutResponse resp = IntentionStatutResponse.builder()
+ .statut("EN_COURS")
+ .build();
- assertThat(r1).isEqualTo(r2);
- assertThat(r1.hashCode()).isEqualTo(r2.hashCode());
- }
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
- @Test
- void testToString() {
- IntentionStatutResponse response = IntentionStatutResponse.builder()
- .intentionId(UUID.randomUUID())
- .statut("COMPLETEE")
- .waveTransactionId("TCN4Y4ZC3FM")
- .build();
+ @Test
+ @DisplayName("setter statut")
+ void setter_statut() {
+ IntentionStatutResponse resp = new IntentionStatutResponse();
+ resp.setStatut("EXPIREE");
+ resp.setConfirme(false);
- String str = response.toString();
- assertThat(str).isNotNull();
- assertThat(str).contains("IntentionStatutResponse");
- assertThat(str).contains("COMPLETEE");
- assertThat(str).contains("TCN4Y4ZC3FM");
- }
+ assertThat(resp.getStatut()).isEqualTo("EXPIREE");
+ assertThat(resp.isConfirme()).isFalse();
+ }
}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponseTest.java
index b0ec12c..28e917b 100644
--- a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponseTest.java
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementGatewayResponseTest.java
@@ -1,255 +1,74 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.util.UUID;
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DisplayName("PaiementGatewayResponse")
class PaiementGatewayResponseTest {
- @Test
- void testBuilder_AllFields() {
- UUID transactionId = UUID.randomUUID();
+ @Test
+ @DisplayName("builder — tous les champs")
+ void builder_allFields() {
+ UUID transactionId = UUID.randomUUID();
- PaiementGatewayResponse response = PaiementGatewayResponse.builder()
- .transactionId(transactionId)
- .redirectUrl("https://checkout.wave.com/session/abc123")
- .montant(new BigDecimal("5000"))
- .statut("EN_ATTENTE")
- .methodePaiement("WAVE")
- .referenceCotisation("COT-2025-001")
- .message("Redirection vers Wave en cours")
- .waveLaunchUrl("wave://checkout/abc123")
- .waveCheckoutSessionId("cos-abc123")
- .clientReference("ref-123")
- .build();
+ PaiementGatewayResponse resp = PaiementGatewayResponse.builder()
+ .transactionId(transactionId)
+ .redirectUrl("https://checkout.wave.com/session/abc123")
+ .waveLaunchUrl("wave://pay?session=abc123")
+ .waveCheckoutSessionId("sess_abc123")
+ .clientReference("intention-uuid-001")
+ .montant(new BigDecimal("5000.00"))
+ .statut("EN_ATTENTE")
+ .methodePaiement("WAVE")
+ .referenceCotisation("COT-2026-001")
+ .message("Redirection vers Wave en cours")
+ .build();
- assertThat(response).isNotNull();
- assertThat(response.getTransactionId()).isEqualTo(transactionId);
- assertThat(response.getRedirectUrl()).isEqualTo("https://checkout.wave.com/session/abc123");
- assertThat(response.getMontant()).isEqualByComparingTo(new BigDecimal("5000"));
- assertThat(response.getStatut()).isEqualTo("EN_ATTENTE");
- assertThat(response.getMethodePaiement()).isEqualTo("WAVE");
- assertThat(response.getReferenceCotisation()).isEqualTo("COT-2025-001");
- assertThat(response.getMessage()).isEqualTo("Redirection vers Wave en cours");
- assertThat(response.getWaveLaunchUrl()).isEqualTo("wave://checkout/abc123");
- assertThat(response.getWaveCheckoutSessionId()).isEqualTo("cos-abc123");
- assertThat(response.getClientReference()).isEqualTo("ref-123");
- }
+ assertThat(resp.getTransactionId()).isEqualTo(transactionId);
+ assertThat(resp.getRedirectUrl()).isEqualTo("https://checkout.wave.com/session/abc123");
+ assertThat(resp.getWaveLaunchUrl()).isEqualTo("wave://pay?session=abc123");
+ assertThat(resp.getWaveCheckoutSessionId()).isEqualTo("sess_abc123");
+ assertThat(resp.getClientReference()).isEqualTo("intention-uuid-001");
+ assertThat(resp.getMontant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.getStatut()).isEqualTo("EN_ATTENTE");
+ assertThat(resp.getMethodePaiement()).isEqualTo("WAVE");
+ assertThat(resp.getReferenceCotisation()).isEqualTo("COT-2026-001");
+ assertThat(resp.getMessage()).isEqualTo("Redirection vers Wave en cours");
+ }
- @Test
- void testBuilder_MinimalFields() {
- UUID transactionId = UUID.randomUUID();
+ @Test
+ @DisplayName("builder — champs optionnels null")
+ void builder_optionalNull() {
+ UUID transactionId = UUID.randomUUID();
- PaiementGatewayResponse response = PaiementGatewayResponse.builder()
- .transactionId(transactionId)
- .redirectUrl("https://checkout.wave.com/session/def456")
- .montant(new BigDecimal("10000"))
- .statut("EN_ATTENTE")
- .methodePaiement("ORANGE_MONEY")
- .build();
+ PaiementGatewayResponse resp = PaiementGatewayResponse.builder()
+ .transactionId(transactionId)
+ .montant(new BigDecimal("1000"))
+ .statut("EN_ATTENTE")
+ .methodePaiement("ESPECES")
+ .build();
- assertThat(response).isNotNull();
- assertThat(response.getTransactionId()).isEqualTo(transactionId);
- assertThat(response.getRedirectUrl()).isEqualTo("https://checkout.wave.com/session/def456");
- assertThat(response.getMontant()).isEqualByComparingTo(new BigDecimal("10000"));
- assertThat(response.getStatut()).isEqualTo("EN_ATTENTE");
- assertThat(response.getMethodePaiement()).isEqualTo("ORANGE_MONEY");
- assertThat(response.getReferenceCotisation()).isNull();
- assertThat(response.getMessage()).isNull();
- assertThat(response.getWaveLaunchUrl()).isNull();
- assertThat(response.getWaveCheckoutSessionId()).isNull();
- assertThat(response.getClientReference()).isNull();
- }
+ assertThat(resp.getTransactionId()).isEqualTo(transactionId);
+ assertThat(resp.getRedirectUrl()).isNull();
+ assertThat(resp.getWaveLaunchUrl()).isNull();
+ assertThat(resp.getWaveCheckoutSessionId()).isNull();
+ assertThat(resp.getClientReference()).isNull();
+ assertThat(resp.getReferenceCotisation()).isNull();
+ assertThat(resp.getMessage()).isNull();
+ }
- @Test
- void testNoArgsConstructor() {
- PaiementGatewayResponse response = new PaiementGatewayResponse();
+ @Test
+ @DisplayName("builder — instance non null")
+ void builder_notNull() {
+ PaiementGatewayResponse resp = PaiementGatewayResponse.builder()
+ .statut("EN_ATTENTE")
+ .build();
- assertThat(response).isNotNull();
- assertThat(response.getTransactionId()).isNull();
- assertThat(response.getRedirectUrl()).isNull();
- assertThat(response.getMontant()).isNull();
- assertThat(response.getStatut()).isNull();
- assertThat(response.getMethodePaiement()).isNull();
- }
-
- @Test
- void testAllArgsConstructor() {
- UUID transactionId = UUID.randomUUID();
-
- PaiementGatewayResponse response = new PaiementGatewayResponse(
- transactionId,
- "https://checkout.wave.com/session/xyz789",
- new BigDecimal("15000"),
- "VALIDE",
- "WAVE",
- "COT-2025-002",
- "Paiement validé",
- "wave://checkout/xyz789",
- "cos-xyz789",
- "ref-456"
- );
-
- assertThat(response).isNotNull();
- assertThat(response.getTransactionId()).isEqualTo(transactionId);
- assertThat(response.getRedirectUrl()).isEqualTo("https://checkout.wave.com/session/xyz789");
- assertThat(response.getMontant()).isEqualByComparingTo(new BigDecimal("15000"));
- assertThat(response.getStatut()).isEqualTo("VALIDE");
- assertThat(response.getMethodePaiement()).isEqualTo("WAVE");
- assertThat(response.getReferenceCotisation()).isEqualTo("COT-2025-002");
- assertThat(response.getMessage()).isEqualTo("Paiement validé");
- assertThat(response.getWaveLaunchUrl()).isEqualTo("wave://checkout/xyz789");
- assertThat(response.getWaveCheckoutSessionId()).isEqualTo("cos-xyz789");
- assertThat(response.getClientReference()).isEqualTo("ref-456");
- }
-
- @Test
- void testSettersAndGetters() {
- UUID transactionId = UUID.randomUUID();
- PaiementGatewayResponse response = new PaiementGatewayResponse();
-
- response.setTransactionId(transactionId);
- response.setRedirectUrl("https://example.com");
- response.setMontant(new BigDecimal("20000"));
- response.setStatut("ECHOUE");
- response.setMethodePaiement("FREE_MONEY");
- response.setReferenceCotisation("COT-2025-003");
- response.setMessage("Erreur de paiement");
- response.setWaveLaunchUrl("wave://checkout/test");
- response.setWaveCheckoutSessionId("cos-test");
- response.setClientReference("ref-789");
-
- assertThat(response.getTransactionId()).isEqualTo(transactionId);
- assertThat(response.getRedirectUrl()).isEqualTo("https://example.com");
- assertThat(response.getMontant()).isEqualByComparingTo(new BigDecimal("20000"));
- assertThat(response.getStatut()).isEqualTo("ECHOUE");
- assertThat(response.getMethodePaiement()).isEqualTo("FREE_MONEY");
- assertThat(response.getReferenceCotisation()).isEqualTo("COT-2025-003");
- assertThat(response.getMessage()).isEqualTo("Erreur de paiement");
- assertThat(response.getWaveLaunchUrl()).isEqualTo("wave://checkout/test");
- assertThat(response.getWaveCheckoutSessionId()).isEqualTo("cos-test");
- assertThat(response.getClientReference()).isEqualTo("ref-789");
- }
-
- @Test
- void testEquals_SameValues() {
- UUID transactionId = UUID.randomUUID();
-
- PaiementGatewayResponse response1 = PaiementGatewayResponse.builder()
- .transactionId(transactionId)
- .redirectUrl("https://checkout.wave.com")
- .montant(new BigDecimal("5000"))
- .statut("EN_ATTENTE")
- .methodePaiement("WAVE")
- .build();
-
- PaiementGatewayResponse response2 = PaiementGatewayResponse.builder()
- .transactionId(transactionId)
- .redirectUrl("https://checkout.wave.com")
- .montant(new BigDecimal("5000"))
- .statut("EN_ATTENTE")
- .methodePaiement("WAVE")
- .build();
-
- assertThat(response1).isEqualTo(response2);
- assertThat(response1.hashCode()).isEqualTo(response2.hashCode());
- }
-
- @Test
- void testEquals_DifferentValues() {
- PaiementGatewayResponse response1 = PaiementGatewayResponse.builder()
- .transactionId(UUID.randomUUID())
- .redirectUrl("https://checkout.wave.com/1")
- .montant(new BigDecimal("5000"))
- .statut("EN_ATTENTE")
- .methodePaiement("WAVE")
- .build();
-
- PaiementGatewayResponse response2 = PaiementGatewayResponse.builder()
- .transactionId(UUID.randomUUID())
- .redirectUrl("https://checkout.wave.com/2")
- .montant(new BigDecimal("10000"))
- .statut("VALIDE")
- .methodePaiement("ORANGE_MONEY")
- .build();
-
- assertThat(response1).isNotEqualTo(response2);
- assertThat(response1.hashCode()).isNotEqualTo(response2.hashCode());
- }
-
- @Test
- void testEquals_SameObject() {
- PaiementGatewayResponse response = PaiementGatewayResponse.builder()
- .transactionId(UUID.randomUUID())
- .redirectUrl("https://checkout.wave.com")
- .montant(new BigDecimal("5000"))
- .statut("EN_ATTENTE")
- .methodePaiement("WAVE")
- .build();
-
- assertThat(response).isEqualTo(response);
- }
-
- @Test
- void testEquals_Null() {
- PaiementGatewayResponse response = PaiementGatewayResponse.builder()
- .transactionId(UUID.randomUUID())
- .build();
-
- assertThat(response).isNotEqualTo(null);
- }
-
- @Test
- void testToString() {
- UUID transactionId = UUID.randomUUID();
- PaiementGatewayResponse response = PaiementGatewayResponse.builder()
- .transactionId(transactionId)
- .redirectUrl("https://checkout.wave.com")
- .montant(new BigDecimal("5000"))
- .statut("EN_ATTENTE")
- .methodePaiement("WAVE")
- .referenceCotisation("COT-2025-001")
- .build();
-
- String toString = response.toString();
-
- // PaiementGatewayResponse n'a pas @ToString de Lombok, donc toString() utilise Object.toString()
- assertThat(toString).isNotNull();
- assertThat(toString).contains("PaiementGatewayResponse");
- }
-
- @Test
- void testWaveSpecificFields() {
- PaiementGatewayResponse response = PaiementGatewayResponse.builder()
- .transactionId(UUID.randomUUID())
- .redirectUrl("https://checkout.wave.com/session/abc123")
- .montant(new BigDecimal("25000"))
- .statut("EN_ATTENTE")
- .methodePaiement("WAVE")
- .waveLaunchUrl("wave://checkout/abc123")
- .waveCheckoutSessionId("cos-abc123")
- .clientReference("intention-uuid-123")
- .build();
-
- assertThat(response.getWaveLaunchUrl()).isEqualTo("wave://checkout/abc123");
- assertThat(response.getWaveCheckoutSessionId()).isEqualTo("cos-abc123");
- assertThat(response.getClientReference()).isEqualTo("intention-uuid-123");
- }
-
- @Test
- void testNonWaveMethod_NoWaveFields() {
- PaiementGatewayResponse response = PaiementGatewayResponse.builder()
- .transactionId(UUID.randomUUID())
- .redirectUrl("https://orange-money.com/checkout")
- .montant(new BigDecimal("15000"))
- .statut("EN_ATTENTE")
- .methodePaiement("ORANGE_MONEY")
- .build();
-
- assertThat(response.getMethodePaiement()).isEqualTo("ORANGE_MONEY");
- assertThat(response.getWaveLaunchUrl()).isNull();
- assertThat(response.getWaveCheckoutSessionId()).isNull();
- }
+ assertThat(resp).isNotNull();
+ }
}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementResponseTest.java
new file mode 100644
index 0000000..f5ec1a4
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementResponseTest.java
@@ -0,0 +1,185 @@
+package dev.lions.unionflow.server.api.dto.paiement.response;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DisplayName("PaiementResponse")
+class PaiementResponseTest {
+
+ @Test
+ @DisplayName("builder — tous les champs")
+ void builder_allFields() {
+ UUID id = UUID.randomUUID();
+ UUID membreId = UUID.randomUUID();
+ UUID transactionWaveId = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ PaiementResponse resp = PaiementResponse.builder()
+ .numeroReference("PAY-001")
+ .montant(new BigDecimal("5000.00"))
+ .codeDevise("XOF")
+ .methodePaiement("WAVE")
+ .methodePaiementLibelle("Wave")
+ .statutPaiement("VALIDE")
+ .statutPaiementLibelle("Validé")
+ .statutPaiementSeverity("success")
+ .datePaiement(now)
+ .dateValidation(now)
+ .validateur("admin@test.com")
+ .referenceExterne("WAVE-TXN-123")
+ .urlPreuve("https://wave.com/proof/123")
+ .commentaire("RAS")
+ .membreId(membreId)
+ .membreNom("Diallo Amadou")
+ .transactionWaveId(transactionWaveId)
+ .build();
+
+ resp.setId(id);
+
+ assertThat(resp.getNumeroReference()).isEqualTo("PAY-001");
+ assertThat(resp.getMontant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.getCodeDevise()).isEqualTo("XOF");
+ assertThat(resp.getMethodePaiement()).isEqualTo("WAVE");
+ assertThat(resp.getMethodePaiementLibelle()).isEqualTo("Wave");
+ assertThat(resp.getStatutPaiement()).isEqualTo("VALIDE");
+ assertThat(resp.getStatutPaiementLibelle()).isEqualTo("Validé");
+ assertThat(resp.getStatutPaiementSeverity()).isEqualTo("success");
+ assertThat(resp.getDatePaiement()).isEqualTo(now);
+ assertThat(resp.getDateValidation()).isEqualTo(now);
+ assertThat(resp.getValidateur()).isEqualTo("admin@test.com");
+ assertThat(resp.getReferenceExterne()).isEqualTo("WAVE-TXN-123");
+ assertThat(resp.getUrlPreuve()).isEqualTo("https://wave.com/proof/123");
+ assertThat(resp.getCommentaire()).isEqualTo("RAS");
+ assertThat(resp.getMembreId()).isEqualTo(membreId);
+ assertThat(resp.getMembreNom()).isEqualTo("Diallo Amadou");
+ assertThat(resp.getTransactionWaveId()).isEqualTo(transactionWaveId);
+ assertThat(resp.getId()).isEqualTo(id);
+ }
+
+ @Test
+ @DisplayName("constructeur no-args — champs null")
+ void noArgsConstructor() {
+ PaiementResponse resp = new PaiementResponse();
+
+ assertThat(resp.getNumeroReference()).isNull();
+ assertThat(resp.getMontant()).isNull();
+ assertThat(resp.getId()).isNull();
+ }
+
+ @Test
+ @DisplayName("constructeur all-args")
+ void allArgsConstructor() {
+ UUID membreId = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ PaiementResponse resp = new PaiementResponse(
+ "PAY-002", new BigDecimal("1000"), "XOF",
+ "ESPECES", "Espèces",
+ "EN_ATTENTE", "En attente", "warning",
+ now, null, null, null, null, null,
+ membreId, "Test Membre", null);
+
+ assertThat(resp.getNumeroReference()).isEqualTo("PAY-002");
+ assertThat(resp.getMontant()).isEqualByComparingTo("1000");
+ assertThat(resp.getMembreId()).isEqualTo(membreId);
+ }
+
+ @Test
+ @DisplayName("setters et getters hérités de BaseResponse")
+ void baseResponseFields() {
+ PaiementResponse resp = new PaiementResponse();
+ UUID id = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ resp.setId(id);
+ resp.setDateCreation(now);
+ resp.setDateModification(now);
+ resp.setCreePar("user@test.com");
+ resp.setModifiePar("admin@test.com");
+ resp.setVersion(1L);
+ resp.setActif(true);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getDateCreation()).isEqualTo(now);
+ assertThat(resp.getDateModification()).isEqualTo(now);
+ assertThat(resp.getCreePar()).isEqualTo("user@test.com");
+ assertThat(resp.getModifiePar()).isEqualTo("admin@test.com");
+ assertThat(resp.getVersion()).isEqualTo(1L);
+ assertThat(resp.getActif()).isTrue();
+ }
+
+ @Test
+ @DisplayName("equals — mêmes champs propres → égaux")
+ void equals_sameFields() {
+ // Lombok @EqualsAndHashCode(callSuper=false) : compare uniquement les champs propres
+ PaiementResponse a = new PaiementResponse();
+ a.setNumeroReference("PAY-001");
+ a.setStatutPaiement("VALIDE");
+
+ PaiementResponse b = new PaiementResponse();
+ b.setNumeroReference("PAY-001");
+ b.setStatutPaiement("VALIDE");
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — champs propres différents → non égal")
+ void equals_differentFields() {
+ // @EqualsAndHashCode(callSuper=false) : Lombok utilise uniquement les champs
+ // de PaiementResponse (pas id hérité de BaseResponse)
+ PaiementResponse a = new PaiementResponse();
+ a.setNumeroReference("PAY-A");
+
+ PaiementResponse b = new PaiementResponse();
+ b.setNumeroReference("PAY-B");
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("equals — tous les champs null → égaux (Lombok callSuper=false)")
+ void equals_allFieldsNull() {
+ PaiementResponse a = new PaiementResponse();
+ PaiementResponse b = new PaiementResponse();
+
+ // Lombok génère equals sur les champs propres uniquement : tous null → égaux
+ assertThat(a).isEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("equals — même instance")
+ void equals_sameInstance() {
+ PaiementResponse resp = new PaiementResponse();
+ resp.setNumeroReference("PAY-X");
+
+ assertThat(resp).isEqualTo(resp);
+ }
+
+ @Test
+ @DisplayName("equals — null et autre type")
+ void equals_nullAndDifferentType() {
+ PaiementResponse resp = new PaiementResponse();
+ resp.setNumeroReference("PAY-Y");
+
+ assertThat(resp).isNotEqualTo(null);
+ assertThat(resp).isNotEqualTo("not a PaiementResponse");
+ }
+
+ @Test
+ @DisplayName("hashCode — cohérent sur deux instances identiques")
+ void hashCode_consistent() {
+ PaiementResponse a = new PaiementResponse();
+ PaiementResponse b = new PaiementResponse();
+
+ // Même état → même hashCode (Lombok sur champs propres)
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponseTest.java
index ed1bc77..026bcae 100644
--- a/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponseTest.java
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/paiement/response/PaiementSummaryResponseTest.java
@@ -1,72 +1,81 @@
package dev.lions.unionflow.server.api.dto.paiement.response;
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DisplayName("PaiementSummaryResponse")
class PaiementSummaryResponseTest {
- @Test
- void testAllFields() {
- UUID id = UUID.randomUUID();
- LocalDateTime datePaiement = LocalDateTime.now();
+ @Test
+ @DisplayName("constructeur — tous les champs")
+ void constructor_allFields() {
+ UUID id = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
- PaiementSummaryResponse response = new PaiementSummaryResponse(
- id,
- "PAY-2026-001",
- new BigDecimal("5000.00"),
- "XOF",
- "Carte bancaire",
- "REUSSI",
- "Réussi",
- "success",
- datePaiement
- );
+ PaiementSummaryResponse resp = new PaiementSummaryResponse(
+ id, "PAY-001", new BigDecimal("5000.00"), "XOF",
+ "Wave", "VALIDE", "Validé", "success", now);
- assertThat(response.getId()).isEqualTo(id);
- assertThat(response.getNumeroReference()).isEqualTo("PAY-2026-001");
- assertThat(response.getMontant()).isEqualByComparingTo(new BigDecimal("5000.00"));
- assertThat(response.getCodeDevise()).isEqualTo("XOF");
- assertThat(response.getMethodePaiementLibelle()).isEqualTo("Carte bancaire");
- assertThat(response.getStatutPaiement()).isEqualTo("REUSSI");
- assertThat(response.getStatutPaiementLibelle()).isEqualTo("Réussi");
- assertThat(response.getStatutPaiementSeverity()).isEqualTo("success");
- assertThat(response.getDatePaiement()).isEqualTo(datePaiement);
- }
+ assertThat(resp.id()).isEqualTo(id);
+ assertThat(resp.numeroReference()).isEqualTo("PAY-001");
+ assertThat(resp.montant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.codeDevise()).isEqualTo("XOF");
+ assertThat(resp.methodePaiementLibelle()).isEqualTo("Wave");
+ assertThat(resp.statutPaiement()).isEqualTo("VALIDE");
+ assertThat(resp.statutPaiementLibelle()).isEqualTo("Validé");
+ assertThat(resp.statutPaiementSeverity()).isEqualTo("success");
+ assertThat(resp.datePaiement()).isEqualTo(now);
+ }
- @Test
- void testEquals() {
- UUID id = UUID.randomUUID();
- LocalDateTime date = LocalDateTime.now();
+ @Test
+ @DisplayName("constructeur — champs optionnels null")
+ void constructor_nullFields() {
+ PaiementSummaryResponse resp = new PaiementSummaryResponse(
+ null, null, null, null, null, null, null, null, null);
- PaiementSummaryResponse response1 = new PaiementSummaryResponse(
- id, "PAY-001", new BigDecimal("1000.00"), "XOF",
- "Wave", "REUSSI", "Réussi", "success", date
- );
+ assertThat(resp.id()).isNull();
+ assertThat(resp.numeroReference()).isNull();
+ assertThat(resp.montant()).isNull();
+ assertThat(resp.datePaiement()).isNull();
+ }
- PaiementSummaryResponse response2 = new PaiementSummaryResponse(
- id, "PAY-001", new BigDecimal("1000.00"), "XOF",
- "Wave", "REUSSI", "Réussi", "success", date
- );
+ @Test
+ @DisplayName("equals et hashCode — mêmes données")
+ void equalsHashCode_sameData() {
+ UUID id = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
- assertThat(response1).isEqualTo(response2);
- assertThat(response1.hashCode()).isEqualTo(response2.hashCode());
- }
+ PaiementSummaryResponse a = new PaiementSummaryResponse(id, "PAY-001", new BigDecimal("1000"), "XOF", "Wave", "VALIDE", "Validé", "success", now);
+ PaiementSummaryResponse b = new PaiementSummaryResponse(id, "PAY-001", new BigDecimal("1000"), "XOF", "Wave", "VALIDE", "Validé", "success", now);
- @Test
- void testToString() {
- PaiementSummaryResponse response = new PaiementSummaryResponse(
- UUID.randomUUID(), "PAY-001", new BigDecimal("1000.00"), "XOF",
- "Wave", "REUSSI", "Réussi", "success", LocalDateTime.now()
- );
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
- String toString = response.toString();
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ LocalDateTime now = LocalDateTime.now();
- assertThat(toString).isNotNull();
- assertThat(toString).contains("PaiementSummaryResponse");
- assertThat(toString).contains("PAY-001");
- }
+ PaiementSummaryResponse a = new PaiementSummaryResponse(UUID.randomUUID(), "PAY-001", new BigDecimal("1000"), "XOF", "Wave", "VALIDE", "Validé", "success", now);
+ PaiementSummaryResponse b = new PaiementSummaryResponse(UUID.randomUUID(), "PAY-002", new BigDecimal("2000"), "XOF", "Wave", "EN_ATTENTE", "En attente", "warning", now);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ PaiementSummaryResponse resp = new PaiementSummaryResponse(
+ UUID.randomUUID(), "PAY-003", new BigDecimal("500"), "XOF",
+ "Espèces", "EN_ATTENTE", "En attente", "warning", LocalDateTime.now());
+
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/registre/AgrementProfessionnelDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/registre/AgrementProfessionnelDTOTest.java
new file mode 100644
index 0000000..a01d536
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/registre/AgrementProfessionnelDTOTest.java
@@ -0,0 +1,42 @@
+package dev.lions.unionflow.server.api.dto.registre;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.registre.StatutAgrement;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class AgrementProfessionnelDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new AgrementProfessionnelDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ AgrementProfessionnelDTO dto = new AgrementProfessionnelDTO();
+ dto.setMembreId("m-1");
+ dto.setOrganisationId("org-1");
+ dto.setSecteurOuOrdre("Ordre des Médecins");
+ dto.setNumeroLicenceOuRegistre("MED-001");
+ dto.setCategorieClassement("Généraliste");
+ dto.setDateDelivrance(LocalDate.of(2020, 6, 1));
+ dto.setDateExpiration(LocalDate.of(2025, 6, 1));
+ dto.setStatut(StatutAgrement.VALIDE);
+
+ assertThat(dto.getMembreId()).isEqualTo("m-1");
+ assertThat(dto.getSecteurOuOrdre()).isEqualTo("Ordre des Médecins");
+ assertThat(dto.getNumeroLicenceOuRegistre()).isEqualTo("MED-001");
+ assertThat(dto.getStatut()).isEqualTo(StatutAgrement.VALIDE);
+ }
+
+ @Test
+ void testBuilder() {
+ AgrementProfessionnelDTO dto = AgrementProfessionnelDTO.builder()
+ .secteurOuOrdre("Barreau")
+ .statut(StatutAgrement.RETRETIRE)
+ .build();
+ assertThat(dto.getSecteurOuOrdre()).isEqualTo("Barreau");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/role/response/PermissionResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/role/response/PermissionResponseTest.java
new file mode 100644
index 0000000..1d4b6c9
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/role/response/PermissionResponseTest.java
@@ -0,0 +1,39 @@
+package dev.lions.unionflow.server.api.dto.role.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class PermissionResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new PermissionResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ PermissionResponse resp = new PermissionResponse();
+ resp.setCode("MEMBRE_CREATE");
+ resp.setModule("MEMBRES");
+ resp.setRessource("MEMBRE");
+ resp.setAction("CREATE");
+ resp.setLibelle("Créer un membre");
+ resp.setDescription("Permission de création de membre");
+
+ assertThat(resp.getCode()).isEqualTo("MEMBRE_CREATE");
+ assertThat(resp.getModule()).isEqualTo("MEMBRES");
+ assertThat(resp.getRessource()).isEqualTo("MEMBRE");
+ assertThat(resp.getAction()).isEqualTo("CREATE");
+ assertThat(resp.getLibelle()).isEqualTo("Créer un membre");
+ }
+
+ @Test
+ void testBuilder() {
+ PermissionResponse resp = PermissionResponse.builder()
+ .code("COTISATION_READ")
+ .module("FINANCES")
+ .build();
+ assertThat(resp.getCode()).isEqualTo("COTISATION_READ");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/role/response/RoleResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/role/response/RoleResponseTest.java
new file mode 100644
index 0000000..44eed81
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/role/response/RoleResponseTest.java
@@ -0,0 +1,42 @@
+package dev.lions.unionflow.server.api.dto.role.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class RoleResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new RoleResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID orgId = UUID.randomUUID();
+ RoleResponse resp = new RoleResponse();
+ resp.setCode("TRESORIER");
+ resp.setLibelle("Trésorier");
+ resp.setDescription("Gère les finances");
+ resp.setTypeRole("ORGANISATION");
+ resp.setNiveauHierarchique(3);
+ resp.setOrganisationId(orgId);
+ resp.setNomOrganisation("Association Test");
+
+ assertThat(resp.getCode()).isEqualTo("TRESORIER");
+ assertThat(resp.getLibelle()).isEqualTo("Trésorier");
+ assertThat(resp.getTypeRole()).isEqualTo("ORGANISATION");
+ assertThat(resp.getNiveauHierarchique()).isEqualTo(3);
+ assertThat(resp.getOrganisationId()).isEqualTo(orgId);
+ }
+
+ @Test
+ void testBuilder() {
+ RoleResponse resp = RoleResponse.builder()
+ .code("PRESIDENT")
+ .libelle("Président")
+ .build();
+ assertThat(resp.getCode()).isEqualTo("PRESIDENT");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/BeneficiaireAideDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/BeneficiaireAideDTOTest.java
new file mode 100644
index 0000000..bf60d96
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/BeneficiaireAideDTOTest.java
@@ -0,0 +1,47 @@
+package dev.lions.unionflow.server.api.dto.solidarite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class BeneficiaireAideDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ BeneficiaireAideDTO dto = new BeneficiaireAideDTO();
+ assertThat(dto).isNotNull();
+ assertThat(dto.getEstDemandeurPrincipal()).isFalse();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ BeneficiaireAideDTO dto = new BeneficiaireAideDTO();
+ dto.setId("ben-1");
+ dto.setNomComplet("Alice Dupont");
+ dto.setRelationDemandeur("Conjoint");
+ dto.setDateNaissance(LocalDate.of(1985, 5, 20));
+ dto.setAge(41);
+ dto.setGenre("F");
+ dto.setTelephone("+221700000000");
+ dto.setEmail("alice@test.com");
+ dto.setEstDemandeurPrincipal(true);
+ dto.setPourcentageAide(100.0);
+
+ assertThat(dto.getId()).isEqualTo("ben-1");
+ assertThat(dto.getNomComplet()).isEqualTo("Alice Dupont");
+ assertThat(dto.getRelationDemandeur()).isEqualTo("Conjoint");
+ assertThat(dto.getEstDemandeurPrincipal()).isTrue();
+ assertThat(dto.getPourcentageAide()).isEqualTo(100.0);
+ }
+
+ @Test
+ void testBuilder() {
+ BeneficiaireAideDTO dto = BeneficiaireAideDTO.builder()
+ .nomComplet("Bob")
+ .relationDemandeur("Enfant")
+ .build();
+ assertThat(dto.getNomComplet()).isEqualTo("Bob");
+ assertThat(dto.getEstDemandeurPrincipal()).isFalse();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/ContactProposantDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/ContactProposantDTOTest.java
new file mode 100644
index 0000000..6385f6c
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/ContactProposantDTOTest.java
@@ -0,0 +1,47 @@
+package dev.lions.unionflow.server.api.dto.solidarite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+class ContactProposantDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ ContactProposantDTO dto = new ContactProposantDTO();
+ assertThat(dto).isNotNull();
+ assertThat(dto.getRencontresPhysiquesPossibles()).isFalse();
+ assertThat(dto.getAppelsAcceptes()).isTrue();
+ assertThat(dto.getSmsAcceptes()).isTrue();
+ assertThat(dto.getEmailsAcceptes()).isTrue();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ContactProposantDTO dto = new ContactProposantDTO();
+ dto.setTelephonePrincipal("+221700000001");
+ dto.setEmail("contact@test.com");
+ dto.setWhatsapp("+221700000001");
+ dto.setTelegram("@user");
+ dto.setHorairesDisponibilite("9h-18h");
+ dto.setLanguesPreferees(List.of("fr", "wolof"));
+ dto.setAutresContacts(Map.of("facebook", "fb.com/user"));
+ dto.setInstructionsSpeciales("Appeler avant de venir");
+
+ assertThat(dto.getTelephonePrincipal()).isEqualTo("+221700000001");
+ assertThat(dto.getEmail()).isEqualTo("contact@test.com");
+ assertThat(dto.getLanguesPreferees()).containsExactly("fr", "wolof");
+ }
+
+ @Test
+ void testBuilder() {
+ ContactProposantDTO dto = ContactProposantDTO.builder()
+ .telephonePrincipal("+221700000002")
+ .emailsAcceptes(false)
+ .build();
+ assertThat(dto.getTelephonePrincipal()).isEqualTo("+221700000002");
+ assertThat(dto.getEmailsAcceptes()).isFalse();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/ContactUrgenceDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/ContactUrgenceDTOTest.java
new file mode 100644
index 0000000..8f5a291
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/ContactUrgenceDTOTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.solidarite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class ContactUrgenceDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ ContactUrgenceDTO dto = new ContactUrgenceDTO();
+ assertThat(dto).isNotNull();
+ assertThat(dto.getPeutPrendreDecisions()).isFalse();
+ assertThat(dto.getNotificationAutomatique()).isTrue();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ ContactUrgenceDTO dto = new ContactUrgenceDTO();
+ dto.setNomComplet("Bob Diallo");
+ dto.setRelation("Frère");
+ dto.setTelephonePrincipal("+221700000003");
+ dto.setEmail("bob@test.com");
+ dto.setDisponibilite("24h/24");
+ dto.setPeutPrendreDecisions(true);
+ dto.setNotificationAutomatique(false);
+ dto.setCommentaires("Contact prioritaire");
+
+ assertThat(dto.getNomComplet()).isEqualTo("Bob Diallo");
+ assertThat(dto.getRelation()).isEqualTo("Frère");
+ assertThat(dto.getTelephonePrincipal()).isEqualTo("+221700000003");
+ assertThat(dto.getPeutPrendreDecisions()).isTrue();
+ assertThat(dto.getNotificationAutomatique()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ ContactUrgenceDTO dto = ContactUrgenceDTO.builder()
+ .nomComplet("Charlie")
+ .relation("Père")
+ .telephonePrincipal("+221700000004")
+ .build();
+ assertThat(dto.getNomComplet()).isEqualTo("Charlie");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/CritereSelectionDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/CritereSelectionDTOTest.java
new file mode 100644
index 0000000..5de9d8d
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/CritereSelectionDTOTest.java
@@ -0,0 +1,48 @@
+package dev.lions.unionflow.server.api.dto.solidarite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class CritereSelectionDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ CritereSelectionDTO dto = new CritereSelectionDTO();
+ assertThat(dto).isNotNull();
+ assertThat(dto.getEstObligatoire()).isFalse();
+ assertThat(dto.getPoids()).isEqualTo(5);
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CritereSelectionDTO dto = new CritereSelectionDTO();
+ dto.setNom("Age minimum");
+ dto.setType("age");
+ dto.setOperateur("greater_than");
+ dto.setValeur("18");
+ dto.setValeurMax("65");
+ dto.setEstObligatoire(true);
+ dto.setPoids(8);
+ dto.setDescription("Critère d'âge");
+
+ assertThat(dto.getNom()).isEqualTo("Age minimum");
+ assertThat(dto.getType()).isEqualTo("age");
+ assertThat(dto.getOperateur()).isEqualTo("greater_than");
+ assertThat(dto.getValeur()).isEqualTo("18");
+ assertThat(dto.getEstObligatoire()).isTrue();
+ assertThat(dto.getPoids()).isEqualTo(8);
+ }
+
+ @Test
+ void testBuilder() {
+ CritereSelectionDTO dto = CritereSelectionDTO.builder()
+ .nom("Localisation")
+ .type("localisation")
+ .operateur("equals")
+ .valeur("Dakar")
+ .build();
+ assertThat(dto.getNom()).isEqualTo("Localisation");
+ assertThat(dto.getPoids()).isEqualTo(5);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/HistoriqueStatutDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/HistoriqueStatutDTOTest.java
new file mode 100644
index 0000000..f96e86d
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/HistoriqueStatutDTOTest.java
@@ -0,0 +1,48 @@
+package dev.lions.unionflow.server.api.dto.solidarite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class HistoriqueStatutDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ HistoriqueStatutDTO dto = new HistoriqueStatutDTO();
+ assertThat(dto).isNotNull();
+ assertThat(dto.getEstAutomatique()).isFalse();
+ assertThat(dto.getDateChangement()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime date = LocalDateTime.of(2026, 1, 15, 10, 0);
+ HistoriqueStatutDTO dto = new HistoriqueStatutDTO();
+ dto.setId("hist-1");
+ dto.setAncienStatut(StatutAide.EN_ATTENTE);
+ dto.setNouveauStatut(StatutAide.APPROUVEE);
+ dto.setDateChangement(date);
+ dto.setAuteurId("admin-1");
+ dto.setAuteurNom("Admin User");
+ dto.setMotif("Dossier complet");
+ dto.setEstAutomatique(false);
+ dto.setDureeDepuisPrecedent(120L);
+
+ assertThat(dto.getAncienStatut()).isEqualTo(StatutAide.EN_ATTENTE);
+ assertThat(dto.getNouveauStatut()).isEqualTo(StatutAide.APPROUVEE);
+ assertThat(dto.getDateChangement()).isEqualTo(date);
+ assertThat(dto.getAuteurId()).isEqualTo("admin-1");
+ assertThat(dto.getDureeDepuisPrecedent()).isEqualTo(120L);
+ }
+
+ @Test
+ void testBuilder() {
+ HistoriqueStatutDTO dto = HistoriqueStatutDTO.builder()
+ .auteurId("a-1")
+ .nouveauStatut(StatutAide.VERSEE)
+ .build();
+ assertThat(dto.getNouveauStatut()).isEqualTo(StatutAide.VERSEE);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/LocalisationDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/LocalisationDTOTest.java
new file mode 100644
index 0000000..d68ace8
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/LocalisationDTOTest.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.solidarite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class LocalisationDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ LocalisationDTO dto = new LocalisationDTO();
+ assertThat(dto).isNotNull();
+ assertThat(dto.getEstApproximative()).isFalse();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalisationDTO dto = new LocalisationDTO();
+ dto.setLatitude(14.6928);
+ dto.setLongitude(-17.4467);
+ dto.setAdresseComplete("15 Rue Félix Faure, Dakar");
+ dto.setVille("Dakar");
+ dto.setRegion("Dakar");
+ dto.setPays("Sénégal");
+ dto.setCodePostal("BP 10");
+ dto.setPrecision(50.0);
+ dto.setEstApproximative(false);
+
+ assertThat(dto.getLatitude()).isEqualTo(14.6928);
+ assertThat(dto.getLongitude()).isEqualTo(-17.4467);
+ assertThat(dto.getVille()).isEqualTo("Dakar");
+ assertThat(dto.getPays()).isEqualTo("Sénégal");
+ assertThat(dto.getEstApproximative()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ LocalisationDTO dto = LocalisationDTO.builder()
+ .ville("Thiès")
+ .pays("Sénégal")
+ .estApproximative(true)
+ .build();
+ assertThat(dto.getVille()).isEqualTo("Thiès");
+ assertThat(dto.getEstApproximative()).isTrue();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/PieceJustificativeDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/PieceJustificativeDTOTest.java
new file mode 100644
index 0000000..0046825
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/solidarite/PieceJustificativeDTOTest.java
@@ -0,0 +1,49 @@
+package dev.lions.unionflow.server.api.dto.solidarite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class PieceJustificativeDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ PieceJustificativeDTO dto = new PieceJustificativeDTO();
+ assertThat(dto).isNotNull();
+ assertThat(dto.getEstObligatoire()).isFalse();
+ assertThat(dto.getEstVerifiee()).isFalse();
+ assertThat(dto.getDateAjout()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ PieceJustificativeDTO dto = new PieceJustificativeDTO();
+ dto.setId("pj-1");
+ dto.setNomFichier("certificat_medical.pdf");
+ dto.setTypePiece("CERTIFICAT_MEDICAL");
+ dto.setDescription("Certificat médical");
+ dto.setUrlFichier("https://storage/pj-1.pdf");
+ dto.setTypeMime("application/pdf");
+ dto.setTailleFichier(102400L);
+ dto.setEstObligatoire(true);
+ dto.setEstVerifiee(false);
+
+ assertThat(dto.getId()).isEqualTo("pj-1");
+ assertThat(dto.getNomFichier()).isEqualTo("certificat_medical.pdf");
+ assertThat(dto.getTypePiece()).isEqualTo("CERTIFICAT_MEDICAL");
+ assertThat(dto.getTailleFichier()).isEqualTo(102400L);
+ assertThat(dto.getEstObligatoire()).isTrue();
+ assertThat(dto.getEstVerifiee()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
+ .nomFichier("doc.pdf")
+ .urlFichier("https://url")
+ .typePiece("IDENTITE")
+ .build();
+ assertThat(dto.getNomFichier()).isEqualTo("doc.pdf");
+ assertThat(dto.getEstObligatoire()).isFalse();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/souscription/FormuleAbonnementResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/souscription/FormuleAbonnementResponseTest.java
new file mode 100644
index 0000000..caae8d4
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/souscription/FormuleAbonnementResponseTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.souscription;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class FormuleAbonnementResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new FormuleAbonnementResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ FormuleAbonnementResponse resp = new FormuleAbonnementResponse();
+ resp.setCode("PREMIUM");
+ resp.setLibelle("Premium");
+ resp.setDescription("Plan premium tout inclus");
+ resp.setPlage("GRANDE");
+ resp.setPlageLibelle("Grande structure");
+ resp.setMinMembres(201);
+ resp.setMaxMembres(1000);
+ resp.setPrixMensuel(new BigDecimal("75000"));
+ resp.setPrixAnnuel(new BigDecimal("810000"));
+ resp.setOrdreAffichage(3);
+ resp.setPlanCommercial("AVANCE");
+ resp.setNiveauReporting("AVANCE");
+ resp.setApiAccess(true);
+ resp.setFederationAccess(false);
+ resp.setSupportPrioritaire(true);
+ resp.setSlaGaranti("99.9%");
+ resp.setMaxAdmins(10);
+
+ assertThat(resp.getCode()).isEqualTo("PREMIUM");
+ assertThat(resp.getPrixMensuel()).isEqualByComparingTo("75000");
+ assertThat(resp.getMinMembres()).isEqualTo(201);
+ assertThat(resp.isApiAccess()).isTrue();
+ assertThat(resp.isFederationAccess()).isFalse();
+ assertThat(resp.isSupportPrioritaire()).isTrue();
+ assertThat(resp.getSlaGaranti()).isEqualTo("99.9%");
+ assertThat(resp.getMaxAdmins()).isEqualTo(10);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/souscription/SouscriptionDemandeRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/souscription/SouscriptionDemandeRequestTest.java
new file mode 100644
index 0000000..47a1716
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/souscription/SouscriptionDemandeRequestTest.java
@@ -0,0 +1,29 @@
+package dev.lions.unionflow.server.api.dto.souscription;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class SouscriptionDemandeRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new SouscriptionDemandeRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ SouscriptionDemandeRequest req = new SouscriptionDemandeRequest();
+ req.setTypeFormule("PREMIUM");
+ req.setPlageMembres("GRANDE");
+ req.setTypePeriode("ANNUEL");
+ req.setTypeOrganisation("MUTUELLE");
+ req.setOrganisationId("org-1");
+
+ assertThat(req.getTypeFormule()).isEqualTo("PREMIUM");
+ assertThat(req.getPlageMembres()).isEqualTo("GRANDE");
+ assertThat(req.getTypePeriode()).isEqualTo("ANNUEL");
+ assertThat(req.getTypeOrganisation()).isEqualTo("MUTUELLE");
+ assertThat(req.getOrganisationId()).isEqualTo("org-1");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/souscription/SouscriptionStatutResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/souscription/SouscriptionStatutResponseTest.java
new file mode 100644
index 0000000..de47c4a
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/souscription/SouscriptionStatutResponseTest.java
@@ -0,0 +1,47 @@
+package dev.lions.unionflow.server.api.dto.souscription;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class SouscriptionStatutResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new SouscriptionStatutResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ SouscriptionStatutResponse resp = new SouscriptionStatutResponse();
+ resp.setSouscriptionId("sous-1");
+ resp.setStatutValidation("VALIDE");
+ resp.setStatutLibelle("Validée");
+ resp.setTypeFormule("STANDARD");
+ resp.setPlageMembres("MOYENNE");
+ resp.setTypePeriode("ANNUEL");
+ resp.setMontantTotal(new BigDecimal("600000"));
+ resp.setOrganisationId("org-1");
+ resp.setOrganisationNom("Association Test");
+ resp.setQuotaMax(500);
+ resp.setQuotaUtilise(100);
+ resp.setQuotaRestant(400);
+ resp.setQuotaDepasse(false);
+ resp.setApiAccess(false);
+ resp.setFederationAccess(false);
+ resp.setSupportPrioritaire(false);
+ resp.setStatut("ACTIVE");
+ resp.setJoursAvantExpiration(365L);
+
+ assertThat(resp.getSouscriptionId()).isEqualTo("sous-1");
+ assertThat(resp.getTypeFormule()).isEqualTo("STANDARD");
+ assertThat(resp.getMontantTotal()).isEqualByComparingTo("600000");
+ assertThat(resp.getQuotaMax()).isEqualTo(500);
+ assertThat(resp.getQuotaRestant()).isEqualTo(400);
+ assertThat(resp.isQuotaDepasse()).isFalse();
+ assertThat(resp.getStatut()).isEqualTo("ACTIVE");
+ assertThat(resp.getJoursAvantExpiration()).isEqualTo(365L);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/suggestion/response/SuggestionResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/suggestion/response/SuggestionResponseTest.java
new file mode 100644
index 0000000..b8d4f47
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/suggestion/response/SuggestionResponseTest.java
@@ -0,0 +1,46 @@
+package dev.lions.unionflow.server.api.dto.suggestion.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class SuggestionResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new SuggestionResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID userId = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+ SuggestionResponse resp = new SuggestionResponse();
+ resp.setUtilisateurId(userId);
+ resp.setUtilisateurNom("Alice Dupont");
+ resp.setTitre("Améliorer le dashboard");
+ resp.setDescription("Ajouter des graphiques");
+ resp.setCategorie("UI");
+ resp.setPrioriteEstimee("HAUTE");
+ resp.setStatut("EN_ATTENTE");
+ resp.setNbVotes(15);
+ resp.setNbCommentaires(3);
+ resp.setDateSoumission(now);
+
+ assertThat(resp.getUtilisateurId()).isEqualTo(userId);
+ assertThat(resp.getTitre()).isEqualTo("Améliorer le dashboard");
+ assertThat(resp.getStatut()).isEqualTo("EN_ATTENTE");
+ assertThat(resp.getNbVotes()).isEqualTo(15);
+ }
+
+ @Test
+ void testBuilder() {
+ SuggestionResponse resp = SuggestionResponse.builder()
+ .titre("Test suggestion")
+ .statut("ACCEPTEE")
+ .build();
+ assertThat(resp.getTitre()).isEqualTo("Test suggestion");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/system/request/UpdateSystemConfigRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/system/request/UpdateSystemConfigRequestTest.java
new file mode 100644
index 0000000..20ba25c
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/system/request/UpdateSystemConfigRequestTest.java
@@ -0,0 +1,48 @@
+package dev.lions.unionflow.server.api.dto.system.request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class UpdateSystemConfigRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new UpdateSystemConfigRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UpdateSystemConfigRequest req = new UpdateSystemConfigRequest();
+ req.setApplicationName("UnionFlow");
+ req.setTimezone("Africa/Dakar");
+ req.setDefaultLanguage("fr");
+ req.setMaintenanceMode(false);
+ req.setNetworkTimeout(30);
+ req.setMaxRetries(3);
+ req.setConnectionPoolSize(10);
+ req.setTwoFactorAuthEnabled(true);
+ req.setSessionTimeoutMinutes(60);
+ req.setAuditLoggingEnabled(true);
+ req.setMetricsCollectionEnabled(true);
+ req.setMetricsIntervalSeconds(60);
+ req.setAutoBackupEnabled(true);
+
+ assertThat(req.getApplicationName()).isEqualTo("UnionFlow");
+ assertThat(req.getTimezone()).isEqualTo("Africa/Dakar");
+ assertThat(req.getMaintenanceMode()).isFalse();
+ assertThat(req.getNetworkTimeout()).isEqualTo(30);
+ assertThat(req.getTwoFactorAuthEnabled()).isTrue();
+ assertThat(req.getAutoBackupEnabled()).isTrue();
+ }
+
+ @Test
+ void testBuilder() {
+ UpdateSystemConfigRequest req = UpdateSystemConfigRequest.builder()
+ .applicationName("Test")
+ .maintenanceMode(true)
+ .build();
+ assertThat(req.getApplicationName()).isEqualTo("Test");
+ assertThat(req.getMaintenanceMode()).isTrue();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/system/response/CacheStatsResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/system/response/CacheStatsResponseTest.java
new file mode 100644
index 0000000..f0f2dbe
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/system/response/CacheStatsResponseTest.java
@@ -0,0 +1,68 @@
+package dev.lions.unionflow.server.api.dto.system.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+class CacheStatsResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CacheStatsResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime cleared = LocalDateTime.now();
+ CacheStatsResponse resp = new CacheStatsResponse();
+ resp.setTotalSizeBytes(1048576L);
+ resp.setTotalSizeFormatted("1 MB");
+ resp.setTotalEntries(500);
+ resp.setHitRate(85.5);
+ resp.setHits(1000L);
+ resp.setMisses(150L);
+ resp.setLastCleared(cleared);
+
+ assertThat(resp.getTotalSizeBytes()).isEqualTo(1048576L);
+ assertThat(resp.getTotalSizeFormatted()).isEqualTo("1 MB");
+ assertThat(resp.getTotalEntries()).isEqualTo(500);
+ assertThat(resp.getHitRate()).isEqualTo(85.5);
+ assertThat(resp.getHits()).isEqualTo(1000L);
+ assertThat(resp.getLastCleared()).isEqualTo(cleared);
+ }
+
+ @Test
+ void testBuilder() {
+ CacheStatsResponse resp = CacheStatsResponse.builder()
+ .totalEntries(100)
+ .hitRate(90.0)
+ .build();
+ assertThat(resp.getTotalEntries()).isEqualTo(100);
+ }
+
+ @Test
+ void testCacheEntry() {
+ CacheStatsResponse.CacheEntry entry = new CacheStatsResponse.CacheEntry();
+ entry.setName("membres");
+ entry.setSizeBytes(512L);
+ entry.setEntries(50);
+ entry.setHitRate(80.0);
+ entry.setHits(800L);
+
+ assertThat(entry.getName()).isEqualTo("membres");
+ assertThat(entry.getSizeBytes()).isEqualTo(512L);
+ assertThat(entry.getHitRate()).isEqualTo(80.0);
+ }
+
+ @Test
+ void testCacheEntryBuilder() {
+ CacheStatsResponse.CacheEntry entry = CacheStatsResponse.CacheEntry.builder()
+ .name("cotisations")
+ .entries(200)
+ .build();
+ assertThat(entry.getName()).isEqualTo("cotisations");
+ assertThat(entry.getEntries()).isEqualTo(200);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/system/response/SystemConfigResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/system/response/SystemConfigResponseTest.java
new file mode 100644
index 0000000..6bb9e24
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/system/response/SystemConfigResponseTest.java
@@ -0,0 +1,43 @@
+package dev.lions.unionflow.server.api.dto.system.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class SystemConfigResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new SystemConfigResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ SystemConfigResponse resp = new SystemConfigResponse();
+ resp.setApplicationName("UnionFlow");
+ resp.setTimezone("Africa/Dakar");
+ resp.setDefaultLanguage("fr");
+ resp.setMaintenanceMode(false);
+ resp.setVersion("3.0.0");
+ resp.setLastUpdated(LocalDateTime.now());
+ resp.setNetworkTimeout(30);
+ resp.setTwoFactorAuthEnabled(true);
+ resp.setAuditLoggingEnabled(true);
+
+ assertThat(resp.getApplicationName()).isEqualTo("UnionFlow");
+ assertThat(resp.getTimezone()).isEqualTo("Africa/Dakar");
+ assertThat(resp.getVersion()).isEqualTo("3.0.0");
+ assertThat(resp.getMaintenanceMode()).isFalse();
+ assertThat(resp.getTwoFactorAuthEnabled()).isTrue();
+ }
+
+ @Test
+ void testBuilder() {
+ SystemConfigResponse resp = SystemConfigResponse.builder()
+ .applicationName("Test")
+ .version("1.0.0")
+ .build();
+ assertThat(resp.getVersion()).isEqualTo("1.0.0");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/system/response/SystemTestResultResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/system/response/SystemTestResultResponseTest.java
new file mode 100644
index 0000000..810cf85
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/system/response/SystemTestResultResponseTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.system.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class SystemTestResultResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new SystemTestResultResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime now = LocalDateTime.now();
+ SystemTestResultResponse resp = new SystemTestResultResponse();
+ resp.setTestType("EMAIL");
+ resp.setSuccess(true);
+ resp.setMessage("Email envoyé avec succès");
+ resp.setResponseTimeMs(250L);
+ resp.setTestedAt(now);
+ resp.setDetails("SMTP 587 OK");
+
+ assertThat(resp.getTestType()).isEqualTo("EMAIL");
+ assertThat(resp.getSuccess()).isTrue();
+ assertThat(resp.getMessage()).isEqualTo("Email envoyé avec succès");
+ assertThat(resp.getResponseTimeMs()).isEqualTo(250L);
+ assertThat(resp.getTestedAt()).isEqualTo(now);
+ assertThat(resp.getDetails()).isEqualTo("SMTP 587 OK");
+ }
+
+ @Test
+ void testBuilder() {
+ SystemTestResultResponse resp = SystemTestResultResponse.builder()
+ .testType("DATABASE")
+ .success(false)
+ .message("Connection refused")
+ .build();
+ assertThat(resp.getTestType()).isEqualTo("DATABASE");
+ assertThat(resp.getSuccess()).isFalse();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/ticket/response/TicketResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/ticket/response/TicketResponseTest.java
new file mode 100644
index 0000000..70ad01c
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/ticket/response/TicketResponseTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.dto.ticket.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class TicketResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TicketResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UUID userId = UUID.randomUUID();
+ TicketResponse resp = new TicketResponse();
+ resp.setNumeroTicket("TKT-001");
+ resp.setUtilisateurId(userId);
+ resp.setSujet("Problème connexion");
+ resp.setDescription("Impossible de se connecter");
+ resp.setCategorie("TECHNIQUE");
+ resp.setPriorite("HAUTE");
+ resp.setStatut("OUVERT");
+ resp.setNbMessages(3);
+
+ assertThat(resp.getNumeroTicket()).isEqualTo("TKT-001");
+ assertThat(resp.getUtilisateurId()).isEqualTo(userId);
+ assertThat(resp.getSujet()).isEqualTo("Problème connexion");
+ assertThat(resp.getCategorie()).isEqualTo("TECHNIQUE");
+ assertThat(resp.getStatut()).isEqualTo("OUVERT");
+ assertThat(resp.getNbMessages()).isEqualTo(3);
+ }
+
+ @Test
+ void testBuilder() {
+ TicketResponse resp = TicketResponse.builder()
+ .numeroTicket("TKT-002")
+ .statut("RESOLU")
+ .build();
+ assertThat(resp.getNumeroTicket()).isEqualTo("TKT-002");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TontineRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TontineRequestTest.java
new file mode 100644
index 0000000..5b32920
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TontineRequestTest.java
@@ -0,0 +1,42 @@
+package dev.lions.unionflow.server.api.dto.tontine;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.tontine.FrequenceTour;
+import dev.lions.unionflow.server.api.enums.tontine.TypeTontine;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class TontineRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TontineRequest()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ TontineRequest req = new TontineRequest();
+ req.setNom("Tontine Mensuelle");
+ req.setDescription("Tontine des membres");
+ req.setOrganisationId("org-1");
+ req.setTypeTontine(TypeTontine.ROTATIVE_CLASSIQUE);
+ req.setFrequence(FrequenceTour.MENSUELLE);
+ req.setDateDebutPrevue(LocalDate.of(2026, 2, 1));
+
+ assertThat(req.getNom()).isEqualTo("Tontine Mensuelle");
+ assertThat(req.getOrganisationId()).isEqualTo("org-1");
+ assertThat(req.getTypeTontine()).isEqualTo(TypeTontine.ROTATIVE_CLASSIQUE);
+ assertThat(req.getFrequence()).isEqualTo(FrequenceTour.MENSUELLE);
+ }
+
+ @Test
+ void testBuilder() {
+ TontineRequest req = TontineRequest.builder()
+ .nom("Tontine Test")
+ .typeTontine(TypeTontine.ACCUMULATIVE)
+ .build();
+ assertThat(req.getTypeTontine()).isEqualTo(TypeTontine.ACCUMULATIVE);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TontineResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TontineResponseTest.java
new file mode 100644
index 0000000..1bc6e67
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TontineResponseTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.tontine;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.tontine.FrequenceTour;
+import dev.lions.unionflow.server.api.enums.tontine.StatutTontine;
+import dev.lions.unionflow.server.api.enums.tontine.TypeTontine;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class TontineResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TontineResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ TontineResponse resp = new TontineResponse();
+ resp.setNom("Tontine Mensuelle");
+ resp.setOrganisationId("org-1");
+ resp.setTypeTontine(TypeTontine.ROTATIVE_CLASSIQUE);
+ resp.setFrequence(FrequenceTour.MENSUELLE);
+ resp.setStatut(StatutTontine.EN_COURS);
+ resp.setMontantMiseParTour(new BigDecimal("10000"));
+ resp.setLimiteParticipants(12);
+
+ assertThat(resp.getNom()).isEqualTo("Tontine Mensuelle");
+ assertThat(resp.getTypeTontine()).isEqualTo(TypeTontine.ROTATIVE_CLASSIQUE);
+ assertThat(resp.getStatut()).isEqualTo(StatutTontine.EN_COURS);
+ assertThat(resp.getMontantMiseParTour()).isEqualByComparingTo("10000");
+ assertThat(resp.getLimiteParticipants()).isEqualTo(12);
+ }
+
+ @Test
+ void testBuilder() {
+ TontineResponse resp = TontineResponse.builder()
+ .nom("Tontine 2026")
+ .statut(StatutTontine.PLANIFIEE)
+ .build();
+ assertThat(resp.getNom()).isEqualTo("Tontine 2026");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TourTontineDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TourTontineDTOTest.java
new file mode 100644
index 0000000..d1c4989
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/tontine/TourTontineDTOTest.java
@@ -0,0 +1,44 @@
+package dev.lions.unionflow.server.api.dto.tontine;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import org.junit.jupiter.api.Test;
+
+class TourTontineDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new TourTontineDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ TourTontineDTO dto = new TourTontineDTO();
+ dto.setTontineId("tontine-1");
+ dto.setOrdreTour(1);
+ dto.setDateOuvertureCotisations(LocalDate.of(2026, 1, 1));
+ dto.setDateTirageOuRemise(LocalDate.of(2026, 1, 31));
+ dto.setMontantCible(new BigDecimal("120000"));
+ dto.setCagnotteCollectee(new BigDecimal("110000"));
+ dto.setMembreBeneficiaireId("m-1");
+ dto.setStatutInterne("EN_COURS");
+
+ assertThat(dto.getTontineId()).isEqualTo("tontine-1");
+ assertThat(dto.getOrdreTour()).isEqualTo(1);
+ assertThat(dto.getMontantCible()).isEqualByComparingTo("120000");
+ assertThat(dto.getCagnotteCollectee()).isEqualByComparingTo("110000");
+ assertThat(dto.getMembreBeneficiaireId()).isEqualTo("m-1");
+ assertThat(dto.getStatutInterne()).isEqualTo("EN_COURS");
+ }
+
+ @Test
+ void testBuilder() {
+ TourTontineDTO dto = TourTontineDTO.builder()
+ .ordreTour(2)
+ .statutInterne("CLOTURE")
+ .build();
+ assertThat(dto.getOrdreTour()).isEqualTo(2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/user/response/UserResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/user/response/UserResponseTest.java
new file mode 100644
index 0000000..6b7a365
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/user/response/UserResponseTest.java
@@ -0,0 +1,49 @@
+package dev.lions.unionflow.server.api.dto.user.response;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+class UserResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new UserResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ UserResponse resp = new UserResponse();
+ resp.setUsername("alice.dupont");
+ resp.setPrenom("Alice");
+ resp.setNom("Dupont");
+ resp.setEmail("alice@test.com");
+ resp.setEmailVerified(true);
+ resp.setEnabled(true);
+ resp.setStatut("ACTIF");
+ resp.setRoles(List.of("MEMBRE", "TRESORIER"));
+ resp.setPrimaryRole("TRESORIER");
+ resp.setTotp(false);
+ resp.setFailedLoginAttempts(0);
+
+ assertThat(resp.getUsername()).isEqualTo("alice.dupont");
+ assertThat(resp.getPrenom()).isEqualTo("Alice");
+ assertThat(resp.getEmail()).isEqualTo("alice@test.com");
+ assertThat(resp.getEmailVerified()).isTrue();
+ assertThat(resp.getEnabled()).isTrue();
+ assertThat(resp.getRoles()).contains("TRESORIER");
+ assertThat(resp.getPrimaryRole()).isEqualTo("TRESORIER");
+ }
+
+ @Test
+ void testBuilder() {
+ UserResponse resp = UserResponse.builder()
+ .username("bob")
+ .statut("INACTIF")
+ .build();
+ assertThat(resp.getUsername()).isEqualTo("bob");
+ assertThat(resp.getStatut()).isEqualTo("INACTIF");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/DeclarerVersementManuelRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/DeclarerVersementManuelRequestTest.java
new file mode 100644
index 0000000..89d8dea
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/DeclarerVersementManuelRequestTest.java
@@ -0,0 +1,123 @@
+package dev.lions.unionflow.server.api.dto.versement.request;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests unitaires pour {@link DeclarerVersementManuelRequest}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("DeclarerVersementManuelRequest")
+class DeclarerVersementManuelRequestTest {
+
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ UUID cotisationId = UUID.randomUUID();
+
+ DeclarerVersementManuelRequest req = DeclarerVersementManuelRequest.builder()
+ .cotisationId(cotisationId)
+ .methodePaiement("ESPECES")
+ .reference("REF-001")
+ .commentaire("Remis en mains propres")
+ .origineFonds("Salaire")
+ .justificationLcbFt("Usage personnel")
+ .build();
+
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.methodePaiement()).isEqualTo("ESPECES");
+ assertThat(req.reference()).isEqualTo("REF-001");
+ assertThat(req.commentaire()).isEqualTo("Remis en mains propres");
+ assertThat(req.origineFonds()).isEqualTo("Salaire");
+ assertThat(req.justificationLcbFt()).isEqualTo("Usage personnel");
+ }
+
+ @Test
+ @DisplayName("builder — champs optionnels null")
+ void builder_optionalFieldsNull() {
+ UUID cotisationId = UUID.randomUUID();
+
+ DeclarerVersementManuelRequest req = DeclarerVersementManuelRequest.builder()
+ .cotisationId(cotisationId)
+ .methodePaiement("VIREMENT")
+ .build();
+
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.methodePaiement()).isEqualTo("VIREMENT");
+ assertThat(req.reference()).isNull();
+ assertThat(req.commentaire()).isNull();
+ assertThat(req.origineFonds()).isNull();
+ assertThat(req.justificationLcbFt()).isNull();
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"ESPECES", "VIREMENT", "CHEQUE", "AUTRE"})
+ @DisplayName("méthodes autorisées acceptées")
+ void methodesAutorisees(String methode) {
+ DeclarerVersementManuelRequest req = DeclarerVersementManuelRequest.builder()
+ .cotisationId(UUID.randomUUID())
+ .methodePaiement(methode)
+ .build();
+
+ assertThat(req.methodePaiement()).isEqualTo(methode);
+ }
+
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ UUID cotisationId = UUID.randomUUID();
+
+ DeclarerVersementManuelRequest req = new DeclarerVersementManuelRequest(
+ cotisationId, "CHEQUE", "CHQ-123", "Chèque no 123", null, null);
+
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.methodePaiement()).isEqualTo("CHEQUE");
+ assertThat(req.reference()).isEqualTo("CHQ-123");
+ assertThat(req.commentaire()).isEqualTo("Chèque no 123");
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID cotisationId = UUID.randomUUID();
+
+ DeclarerVersementManuelRequest a = new DeclarerVersementManuelRequest(
+ cotisationId, "ESPECES", null, null, null, null);
+ DeclarerVersementManuelRequest b = new DeclarerVersementManuelRequest(
+ cotisationId, "ESPECES", null, null, null, null);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ DeclarerVersementManuelRequest a = new DeclarerVersementManuelRequest(
+ UUID.randomUUID(), "ESPECES", null, null, null, null);
+ DeclarerVersementManuelRequest b = new DeclarerVersementManuelRequest(
+ UUID.randomUUID(), "VIREMENT", null, null, null, null);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ DeclarerVersementManuelRequest req = DeclarerVersementManuelRequest.builder()
+ .cotisationId(UUID.randomUUID())
+ .methodePaiement("ESPECES")
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/InitierDepotEpargneRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/InitierDepotEpargneRequestTest.java
new file mode 100644
index 0000000..cf8f359
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/InitierDepotEpargneRequestTest.java
@@ -0,0 +1,105 @@
+package dev.lions.unionflow.server.api.dto.versement.request;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests unitaires pour {@link InitierDepotEpargneRequest}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("InitierDepotEpargneRequest")
+class InitierDepotEpargneRequestTest {
+
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ UUID compteId = UUID.randomUUID();
+
+ InitierDepotEpargneRequest req = InitierDepotEpargneRequest.builder()
+ .compteId(compteId)
+ .montant(new BigDecimal("10000.00"))
+ .numeroTelephone("771234567")
+ .origineFonds("Salaire")
+ .justificationLcbFt("Épargne mensuelle")
+ .build();
+
+ assertThat(req.compteId()).isEqualTo(compteId);
+ assertThat(req.montant()).isEqualByComparingTo("10000.00");
+ assertThat(req.numeroTelephone()).isEqualTo("771234567");
+ assertThat(req.origineFonds()).isEqualTo("Salaire");
+ assertThat(req.justificationLcbFt()).isEqualTo("Épargne mensuelle");
+ }
+
+ @Test
+ @DisplayName("builder — champs optionnels null")
+ void builder_optionalFieldsNull() {
+ UUID compteId = UUID.randomUUID();
+
+ InitierDepotEpargneRequest req = InitierDepotEpargneRequest.builder()
+ .compteId(compteId)
+ .montant(new BigDecimal("5000"))
+ .build();
+
+ assertThat(req.compteId()).isEqualTo(compteId);
+ assertThat(req.montant()).isEqualByComparingTo("5000");
+ assertThat(req.numeroTelephone()).isNull();
+ assertThat(req.origineFonds()).isNull();
+ assertThat(req.justificationLcbFt()).isNull();
+ }
+
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ UUID compteId = UUID.randomUUID();
+
+ InitierDepotEpargneRequest req = new InitierDepotEpargneRequest(
+ compteId, new BigDecimal("25000"), "701234567", null, null);
+
+ assertThat(req.compteId()).isEqualTo(compteId);
+ assertThat(req.montant()).isEqualByComparingTo("25000");
+ assertThat(req.numeroTelephone()).isEqualTo("701234567");
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID compteId = UUID.randomUUID();
+ BigDecimal montant = new BigDecimal("10000");
+
+ InitierDepotEpargneRequest a = new InitierDepotEpargneRequest(compteId, montant, "771234567", null, null);
+ InitierDepotEpargneRequest b = new InitierDepotEpargneRequest(compteId, montant, "771234567", null, null);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ InitierDepotEpargneRequest a = new InitierDepotEpargneRequest(
+ UUID.randomUUID(), new BigDecimal("5000"), null, null, null);
+ InitierDepotEpargneRequest b = new InitierDepotEpargneRequest(
+ UUID.randomUUID(), new BigDecimal("10000"), null, null, null);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ InitierDepotEpargneRequest req = InitierDepotEpargneRequest.builder()
+ .compteId(UUID.randomUUID())
+ .montant(new BigDecimal("5000"))
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/InitierVersementWaveRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/InitierVersementWaveRequestTest.java
new file mode 100644
index 0000000..1c81f23
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/versement/request/InitierVersementWaveRequestTest.java
@@ -0,0 +1,98 @@
+package dev.lions.unionflow.server.api.dto.versement.request;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests unitaires pour {@link InitierVersementWaveRequest}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("InitierVersementWaveRequest")
+class InitierVersementWaveRequestTest {
+
+ @Test
+ @DisplayName("builder — tous les champs renseignés")
+ void builder_allFields() {
+ UUID cotisationId = UUID.randomUUID();
+
+ InitierVersementWaveRequest req = InitierVersementWaveRequest.builder()
+ .cotisationId(cotisationId)
+ .numeroTelephone("771234567")
+ .origineFonds("Salaire")
+ .justificationLcbFt("Usage personnel")
+ .build();
+
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.numeroTelephone()).isEqualTo("771234567");
+ assertThat(req.origineFonds()).isEqualTo("Salaire");
+ assertThat(req.justificationLcbFt()).isEqualTo("Usage personnel");
+ }
+
+ @Test
+ @DisplayName("builder — champs optionnels null")
+ void builder_optionalFieldsNull() {
+ UUID cotisationId = UUID.randomUUID();
+
+ InitierVersementWaveRequest req = InitierVersementWaveRequest.builder()
+ .cotisationId(cotisationId)
+ .build();
+
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.numeroTelephone()).isNull();
+ assertThat(req.origineFonds()).isNull();
+ assertThat(req.justificationLcbFt()).isNull();
+ }
+
+ @Test
+ @DisplayName("constructeur canonique record")
+ void canonicalConstructor() {
+ UUID cotisationId = UUID.randomUUID();
+
+ InitierVersementWaveRequest req = new InitierVersementWaveRequest(
+ cotisationId, "701234567", "Épargne", null);
+
+ assertThat(req.cotisationId()).isEqualTo(cotisationId);
+ assertThat(req.numeroTelephone()).isEqualTo("701234567");
+ assertThat(req.origineFonds()).isEqualTo("Épargne");
+ assertThat(req.justificationLcbFt()).isNull();
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID cotisationId = UUID.randomUUID();
+
+ InitierVersementWaveRequest a = new InitierVersementWaveRequest(cotisationId, "771234567", null, null);
+ InitierVersementWaveRequest b = new InitierVersementWaveRequest(cotisationId, "771234567", null, null);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ InitierVersementWaveRequest a = new InitierVersementWaveRequest(UUID.randomUUID(), "771234567", null, null);
+ InitierVersementWaveRequest b = new InitierVersementWaveRequest(UUID.randomUUID(), "771234567", null, null);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ InitierVersementWaveRequest req = InitierVersementWaveRequest.builder()
+ .cotisationId(UUID.randomUUID())
+ .numeroTelephone("771234567")
+ .build();
+
+ assertThat(req.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementGatewayResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementGatewayResponseTest.java
new file mode 100644
index 0000000..114c02e
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementGatewayResponseTest.java
@@ -0,0 +1,128 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests unitaires pour {@link VersementGatewayResponse}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("VersementGatewayResponse")
+class VersementGatewayResponseTest {
+
+ @Test
+ @DisplayName("builder — tous les champs")
+ void builder_allFields() {
+ UUID versementId = UUID.randomUUID();
+
+ VersementGatewayResponse resp = VersementGatewayResponse.builder()
+ .versementId(versementId)
+ .waveLaunchUrl("wave://checkout/abc123")
+ .waveCheckoutSessionId("cos-abc123")
+ .clientReference("ref-uuid")
+ .montant(new BigDecimal("5000.00"))
+ .statut("EN_ATTENTE")
+ .referenceCotisation("COT-2026-001")
+ .message("Ouvrez Wave pour confirmer votre versement")
+ .build();
+
+ assertThat(resp.getVersementId()).isEqualTo(versementId);
+ assertThat(resp.getWaveLaunchUrl()).isEqualTo("wave://checkout/abc123");
+ assertThat(resp.getWaveCheckoutSessionId()).isEqualTo("cos-abc123");
+ assertThat(resp.getClientReference()).isEqualTo("ref-uuid");
+ assertThat(resp.getMontant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.getStatut()).isEqualTo("EN_ATTENTE");
+ assertThat(resp.getReferenceCotisation()).isEqualTo("COT-2026-001");
+ assertThat(resp.getMessage()).isEqualTo("Ouvrez Wave pour confirmer votre versement");
+ }
+
+ @Test
+ @DisplayName("setters fonctionnent")
+ void setters_work() {
+ VersementGatewayResponse resp = new VersementGatewayResponse();
+ UUID versementId = UUID.randomUUID();
+
+ resp.setVersementId(versementId);
+ resp.setWaveLaunchUrl("wave://checkout/xyz");
+ resp.setStatut("EN_ATTENTE");
+ resp.setMontant(new BigDecimal("10000"));
+
+ assertThat(resp.getVersementId()).isEqualTo(versementId);
+ assertThat(resp.getWaveLaunchUrl()).isEqualTo("wave://checkout/xyz");
+ assertThat(resp.getStatut()).isEqualTo("EN_ATTENTE");
+ assertThat(resp.getMontant()).isEqualByComparingTo("10000");
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID versementId = UUID.randomUUID();
+
+ VersementGatewayResponse a = VersementGatewayResponse.builder()
+ .versementId(versementId)
+ .waveLaunchUrl("wave://checkout/abc")
+ .statut("EN_ATTENTE")
+ .montant(new BigDecimal("5000"))
+ .build();
+
+ VersementGatewayResponse b = VersementGatewayResponse.builder()
+ .versementId(versementId)
+ .waveLaunchUrl("wave://checkout/abc")
+ .statut("EN_ATTENTE")
+ .montant(new BigDecimal("5000"))
+ .build();
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ VersementGatewayResponse a = VersementGatewayResponse.builder()
+ .versementId(UUID.randomUUID())
+ .waveLaunchUrl("wave://checkout/abc")
+ .build();
+
+ VersementGatewayResponse b = VersementGatewayResponse.builder()
+ .versementId(UUID.randomUUID())
+ .waveLaunchUrl("wave://checkout/xyz")
+ .build();
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("constructeur no-arg — champs null")
+ void noArgConstructor_fieldsNull() {
+ VersementGatewayResponse resp = new VersementGatewayResponse();
+
+ assertThat(resp.getVersementId()).isNull();
+ assertThat(resp.getWaveLaunchUrl()).isNull();
+ assertThat(resp.getStatut()).isNull();
+ }
+
+ @Test
+ @DisplayName("constructeur all-args")
+ void allArgsConstructor() {
+ UUID versementId = UUID.randomUUID();
+
+ VersementGatewayResponse resp = new VersementGatewayResponse(
+ versementId, "wave://checkout/test", "cos-test",
+ "ref-001", new BigDecimal("3000"), "EN_ATTENTE",
+ "COT-001", "Message test");
+
+ assertThat(resp.getVersementId()).isEqualTo(versementId);
+ assertThat(resp.getWaveLaunchUrl()).isEqualTo("wave://checkout/test");
+ assertThat(resp.getMontant()).isEqualByComparingTo("3000");
+ assertThat(resp.getMessage()).isEqualTo("Message test");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementResponseTest.java
new file mode 100644
index 0000000..aa941ca
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementResponseTest.java
@@ -0,0 +1,144 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests unitaires pour {@link VersementResponse}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("VersementResponse")
+class VersementResponseTest {
+
+ @Test
+ @DisplayName("builder — tous les champs")
+ void builder_allFields() {
+ UUID membreId = UUID.randomUUID();
+ UUID transactionWaveId = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ VersementResponse resp = VersementResponse.builder()
+ .numeroReference("VRS-2026-001")
+ .montant(new BigDecimal("5000.00"))
+ .codeDevise("XOF")
+ .methodePaiement("WAVE")
+ .methodePaiementLibelle("Wave Mobile Money")
+ .statutPaiement("CONFIRME")
+ .statutPaiementLibelle("Confirmé")
+ .statutPaiementSeverity("success")
+ .datePaiement(now)
+ .dateValidation(now)
+ .validateur("admin@test.com")
+ .referenceExterne("TCN123")
+ .urlPreuve("https://example.com/preuve")
+ .commentaire("RAS")
+ .membreId(membreId)
+ .membreNom("Diallo Alpha")
+ .numeroTelephone("+221771234567")
+ .transactionWaveId(transactionWaveId)
+ .origineFonds("Salaire")
+ .justificationLcbFt("Usage personnel")
+ .build();
+
+ assertThat(resp.getNumeroReference()).isEqualTo("VRS-2026-001");
+ assertThat(resp.getMontant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.getCodeDevise()).isEqualTo("XOF");
+ assertThat(resp.getMethodePaiement()).isEqualTo("WAVE");
+ assertThat(resp.getMethodePaiementLibelle()).isEqualTo("Wave Mobile Money");
+ assertThat(resp.getStatutPaiement()).isEqualTo("CONFIRME");
+ assertThat(resp.getStatutPaiementLibelle()).isEqualTo("Confirmé");
+ assertThat(resp.getStatutPaiementSeverity()).isEqualTo("success");
+ assertThat(resp.getDatePaiement()).isEqualTo(now);
+ assertThat(resp.getDateValidation()).isEqualTo(now);
+ assertThat(resp.getValidateur()).isEqualTo("admin@test.com");
+ assertThat(resp.getReferenceExterne()).isEqualTo("TCN123");
+ assertThat(resp.getUrlPreuve()).isEqualTo("https://example.com/preuve");
+ assertThat(resp.getCommentaire()).isEqualTo("RAS");
+ assertThat(resp.getMembreId()).isEqualTo(membreId);
+ assertThat(resp.getMembreNom()).isEqualTo("Diallo Alpha");
+ assertThat(resp.getNumeroTelephone()).isEqualTo("+221771234567");
+ assertThat(resp.getTransactionWaveId()).isEqualTo(transactionWaveId);
+ assertThat(resp.getOrigineFonds()).isEqualTo("Salaire");
+ assertThat(resp.getJustificationLcbFt()).isEqualTo("Usage personnel");
+ }
+
+ @Test
+ @DisplayName("setters fonctionnent")
+ void setters_work() {
+ VersementResponse resp = new VersementResponse();
+ resp.setNumeroReference("VRS-2026-002");
+ resp.setMontant(new BigDecimal("10000"));
+ resp.setStatutPaiement("EN_ATTENTE");
+ resp.setNumeroTelephone("+221771234567");
+
+ assertThat(resp.getNumeroReference()).isEqualTo("VRS-2026-002");
+ assertThat(resp.getMontant()).isEqualByComparingTo("10000");
+ assertThat(resp.getStatutPaiement()).isEqualTo("EN_ATTENTE");
+ assertThat(resp.getNumeroTelephone()).isEqualTo("+221771234567");
+ }
+
+ @Test
+ @DisplayName("equals — mêmes champs VersementResponse (callSuper=false : id ignoré)")
+ void equals_sameFields() {
+ // @EqualsAndHashCode(callSuper = false) : égalité basée sur les champs de
+ // VersementResponse uniquement — l'id hérité de BaseResponse est ignoré.
+ VersementResponse a = VersementResponse.builder().numeroReference("VRS-001").build();
+ VersementResponse b = VersementResponse.builder().numeroReference("VRS-001").build();
+ // Ids différents définis via setters — ne doivent pas affecter l'égalité
+ a.setId(UUID.randomUUID());
+ b.setId(UUID.randomUUID());
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — champs différents → non égaux")
+ void equals_differentFields() {
+ VersementResponse a = VersementResponse.builder()
+ .numeroReference("VRS-001").statutPaiement("CONFIRME").build();
+ VersementResponse b = VersementResponse.builder()
+ .numeroReference("VRS-002").statutPaiement("EN_ATTENTE").build();
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("constructeur no-arg — champs null")
+ void noArgConstructor_fieldsNull() {
+ VersementResponse resp = new VersementResponse();
+
+ assertThat(resp.getNumeroReference()).isNull();
+ assertThat(resp.getMontant()).isNull();
+ assertThat(resp.getStatutPaiement()).isNull();
+ }
+
+ @Test
+ @DisplayName("champs BaseResponse accessibles via setters")
+ void baseResponseFields() {
+ UUID id = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ VersementResponse resp = VersementResponse.builder().build();
+ resp.setId(id);
+ resp.setDateCreation(now);
+ resp.setCreePar("user@test.com");
+ resp.setActif(true);
+ resp.setVersion(1L);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getDateCreation()).isEqualTo(now);
+ assertThat(resp.getCreePar()).isEqualTo("user@test.com");
+ assertThat(resp.getActif()).isTrue();
+ assertThat(resp.getVersion()).isEqualTo(1L);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementStatutResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementStatutResponseTest.java
new file mode 100644
index 0000000..c16fa1b
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementStatutResponseTest.java
@@ -0,0 +1,186 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests unitaires pour {@link VersementStatutResponse}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("VersementStatutResponse")
+class VersementStatutResponseTest {
+
+ @Test
+ @DisplayName("builder — statut COMPLETEE confirme=true")
+ void builder_completee_confirmeTrue() {
+ UUID intentionId = UUID.randomUUID();
+
+ VersementStatutResponse resp = VersementStatutResponse.builder()
+ .intentionId(intentionId)
+ .statut("COMPLETEE")
+ .confirme(true)
+ .waveTransactionId("TCN123456789")
+ .montant(new BigDecimal("5000.00"))
+ .referenceCotisation("COT-2026-001")
+ .message("Versement confirmé !")
+ .build();
+
+ assertThat(resp.getIntentionId()).isEqualTo(intentionId);
+ assertThat(resp.getStatut()).isEqualTo("COMPLETEE");
+ assertThat(resp.isConfirme()).isTrue();
+ assertThat(resp.getWaveTransactionId()).isEqualTo("TCN123456789");
+ assertThat(resp.getMontant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.getReferenceCotisation()).isEqualTo("COT-2026-001");
+ assertThat(resp.getMessage()).isEqualTo("Versement confirmé !");
+ }
+
+ @Test
+ @DisplayName("builder — statut EN_COURS confirme=false")
+ void builder_enCours_confirmeFalse() {
+ UUID intentionId = UUID.randomUUID();
+
+ VersementStatutResponse resp = VersementStatutResponse.builder()
+ .intentionId(intentionId)
+ .statut("EN_COURS")
+ .confirme(false)
+ .waveLaunchUrl("wave://checkout/abc")
+ .waveCheckoutSessionId("cos-abc")
+ .montant(new BigDecimal("5000"))
+ .build();
+
+ assertThat(resp.getStatut()).isEqualTo("EN_COURS");
+ assertThat(resp.isConfirme()).isFalse();
+ assertThat(resp.getWaveLaunchUrl()).isEqualTo("wave://checkout/abc");
+ assertThat(resp.getWaveCheckoutSessionId()).isEqualTo("cos-abc");
+ assertThat(resp.getWaveTransactionId()).isNull();
+ }
+
+ @Test
+ @DisplayName("builder — statut EXPIREE confirme=false")
+ void builder_expiree_confirmeFalse() {
+ VersementStatutResponse resp = VersementStatutResponse.builder()
+ .statut("EXPIREE")
+ .confirme(false)
+ .message("Session expirée. Veuillez relancer le versement.")
+ .build();
+
+ assertThat(resp.getStatut()).isEqualTo("EXPIREE");
+ assertThat(resp.isConfirme()).isFalse();
+ assertThat(resp.getMessage()).contains("expirée");
+ }
+
+ @Test
+ @DisplayName("builder — statut ECHOUEE confirme=false")
+ void builder_echouee_confirmeFalse() {
+ VersementStatutResponse resp = VersementStatutResponse.builder()
+ .statut("ECHOUEE")
+ .confirme(false)
+ .message("Versement échoué.")
+ .build();
+
+ assertThat(resp.getStatut()).isEqualTo("ECHOUEE");
+ assertThat(resp.isConfirme()).isFalse();
+ }
+
+ @Test
+ @DisplayName("setters fonctionnent (@Data)")
+ void setters_work() {
+ VersementStatutResponse resp = new VersementStatutResponse();
+ UUID intentionId = UUID.randomUUID();
+
+ resp.setIntentionId(intentionId);
+ resp.setStatut("COMPLETEE");
+ resp.setConfirme(true);
+ resp.setWaveTransactionId("TCN999");
+ resp.setMontant(new BigDecimal("7500"));
+
+ assertThat(resp.getIntentionId()).isEqualTo(intentionId);
+ assertThat(resp.getStatut()).isEqualTo("COMPLETEE");
+ assertThat(resp.isConfirme()).isTrue();
+ assertThat(resp.getWaveTransactionId()).isEqualTo("TCN999");
+ assertThat(resp.getMontant()).isEqualByComparingTo("7500");
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données")
+ void equalsHashCode_sameData() {
+ UUID intentionId = UUID.randomUUID();
+
+ VersementStatutResponse a = VersementStatutResponse.builder()
+ .intentionId(intentionId)
+ .statut("COMPLETEE")
+ .confirme(true)
+ .build();
+
+ VersementStatutResponse b = VersementStatutResponse.builder()
+ .intentionId(intentionId)
+ .statut("COMPLETEE")
+ .confirme(true)
+ .build();
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ VersementStatutResponse a = VersementStatutResponse.builder()
+ .intentionId(UUID.randomUUID())
+ .statut("COMPLETEE")
+ .confirme(true)
+ .build();
+
+ VersementStatutResponse b = VersementStatutResponse.builder()
+ .intentionId(UUID.randomUUID())
+ .statut("EN_COURS")
+ .confirme(false)
+ .build();
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("constructeur no-arg — confirme false par défaut")
+ void noArgConstructor_confirmeFalseByDefault() {
+ VersementStatutResponse resp = new VersementStatutResponse();
+
+ assertThat(resp.isConfirme()).isFalse();
+ assertThat(resp.getIntentionId()).isNull();
+ assertThat(resp.getStatut()).isNull();
+ }
+
+ @Test
+ @DisplayName("constructeur all-args")
+ void allArgsConstructor() {
+ UUID intentionId = UUID.randomUUID();
+
+ VersementStatutResponse resp = new VersementStatutResponse(
+ intentionId, "COMPLETEE", true,
+ null, null, "TCN123",
+ new BigDecimal("5000"), "COT-001", "Confirmé !");
+
+ assertThat(resp.getIntentionId()).isEqualTo(intentionId);
+ assertThat(resp.isConfirme()).isTrue();
+ assertThat(resp.getWaveTransactionId()).isEqualTo("TCN123");
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ VersementStatutResponse resp = VersementStatutResponse.builder()
+ .intentionId(UUID.randomUUID())
+ .statut("EN_COURS")
+ .build();
+
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementSummaryResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementSummaryResponseTest.java
new file mode 100644
index 0000000..e941c12
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/versement/response/VersementSummaryResponseTest.java
@@ -0,0 +1,122 @@
+package dev.lions.unionflow.server.api.dto.versement.response;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests unitaires pour {@link VersementSummaryResponse}.
+ *
+ * @author UnionFlow Team
+ * @version 4.0
+ * @since 2026-04-13
+ */
+@DisplayName("VersementSummaryResponse")
+class VersementSummaryResponseTest {
+
+ @Test
+ @DisplayName("setters/getters — tous les champs")
+ void settersGetters_allFields() {
+ UUID id = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ VersementSummaryResponse resp = new VersementSummaryResponse();
+ resp.setId(id);
+ resp.setNumeroReference("VRS-2026-001");
+ resp.setMontant(new BigDecimal("5000.00"));
+ resp.setCodeDevise("XOF");
+ resp.setMethodePaiementLibelle("Wave Mobile Money");
+ resp.setStatutPaiement("CONFIRME");
+ resp.setStatutPaiementLibelle("Confirmé");
+ resp.setStatutPaiementSeverity("success");
+ resp.setDatePaiement(now);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getNumeroReference()).isEqualTo("VRS-2026-001");
+ assertThat(resp.getMontant()).isEqualByComparingTo("5000.00");
+ assertThat(resp.getCodeDevise()).isEqualTo("XOF");
+ assertThat(resp.getMethodePaiementLibelle()).isEqualTo("Wave Mobile Money");
+ assertThat(resp.getStatutPaiement()).isEqualTo("CONFIRME");
+ assertThat(resp.getStatutPaiementLibelle()).isEqualTo("Confirmé");
+ assertThat(resp.getStatutPaiementSeverity()).isEqualTo("success");
+ assertThat(resp.getDatePaiement()).isEqualTo(now);
+ }
+
+ @Test
+ @DisplayName("equals et hashCode — même données (@Data)")
+ void equalsHashCode_sameData() {
+ UUID id = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ VersementSummaryResponse a = new VersementSummaryResponse(
+ id, "VRS-2026-001", new BigDecimal("5000"), "XOF",
+ "Wave Mobile Money", "CONFIRME", "Confirmé", "success", now);
+
+ VersementSummaryResponse b = new VersementSummaryResponse(
+ id, "VRS-2026-001", new BigDecimal("5000"), "XOF",
+ "Wave Mobile Money", "CONFIRME", "Confirmé", "success", now);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals — données différentes")
+ void equals_differentData() {
+ VersementSummaryResponse a = new VersementSummaryResponse(
+ UUID.randomUUID(), "VRS-001", new BigDecimal("5000"), "XOF",
+ "Wave", "CONFIRME", "Confirmé", "success", null);
+
+ VersementSummaryResponse b = new VersementSummaryResponse(
+ UUID.randomUUID(), "VRS-002", new BigDecimal("10000"), "XOF",
+ "Espèces", "EN_ATTENTE", "En attente", "info", null);
+
+ assertThat(a).isNotEqualTo(b);
+ }
+
+ @Test
+ @DisplayName("constructeur no-arg — champs null")
+ void noArgConstructor_fieldsNull() {
+ VersementSummaryResponse resp = new VersementSummaryResponse();
+
+ assertThat(resp.getId()).isNull();
+ assertThat(resp.getNumeroReference()).isNull();
+ assertThat(resp.getMontant()).isNull();
+ assertThat(resp.getStatutPaiement()).isNull();
+ }
+
+ @Test
+ @DisplayName("constructeur all-args")
+ void allArgsConstructor() {
+ UUID id = UUID.randomUUID();
+ LocalDateTime now = LocalDateTime.now();
+
+ VersementSummaryResponse resp = new VersementSummaryResponse(
+ id, "VRS-2026-TEST", new BigDecimal("2500"), "XOF",
+ "Espèces", "EN_ATTENTE_VALIDATION", "En attente de validation",
+ "warning", now);
+
+ assertThat(resp.getId()).isEqualTo(id);
+ assertThat(resp.getNumeroReference()).isEqualTo("VRS-2026-TEST");
+ assertThat(resp.getMontant()).isEqualByComparingTo("2500");
+ assertThat(resp.getCodeDevise()).isEqualTo("XOF");
+ assertThat(resp.getMethodePaiementLibelle()).isEqualTo("Espèces");
+ assertThat(resp.getStatutPaiement()).isEqualTo("EN_ATTENTE_VALIDATION");
+ assertThat(resp.getStatutPaiementSeverity()).isEqualTo("warning");
+ assertThat(resp.getDatePaiement()).isEqualTo(now);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void toString_nonNull() {
+ VersementSummaryResponse resp = new VersementSummaryResponse();
+ resp.setNumeroReference("VRS-2026-001");
+
+ assertThat(resp.toString()).isNotNull().isNotEmpty();
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/vote/CampagneVoteRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/vote/CampagneVoteRequestTest.java
new file mode 100644
index 0000000..dbf52b3
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/vote/CampagneVoteRequestTest.java
@@ -0,0 +1,57 @@
+package dev.lions.unionflow.server.api.dto.vote;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.vote.ModeScrutin;
+import dev.lions.unionflow.server.api.enums.vote.TypeVote;
+import java.time.LocalDateTime;
+import org.junit.jupiter.api.Test;
+
+class CampagneVoteRequestTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ CampagneVoteRequest req = new CampagneVoteRequest();
+ assertThat(req).isNotNull();
+ assertThat(req.getRestreindreMembresAJour()).isTrue();
+ assertThat(req.getAutoriserVoteBlanc()).isTrue();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ LocalDateTime ouverture = LocalDateTime.now().plusDays(1);
+ LocalDateTime fermeture = LocalDateTime.now().plusDays(7);
+ CampagneVoteRequest req = new CampagneVoteRequest();
+ req.setTitre("Election Président");
+ req.setDescriptionOuResolution("Élection du président 2026");
+ req.setOrganisationId("org-1");
+ req.setTypeVote(TypeVote.ELECTION_BUREAU);
+ req.setModeScrutin(ModeScrutin.MAJORITAIRE_UN_TOUR);
+ req.setDateOuverture(ouverture);
+ req.setDateFermeture(fermeture);
+ req.setRestreindreMembresAJour(false);
+ req.setAutoriserVoteBlanc(true);
+
+ assertThat(req.getTitre()).isEqualTo("Election Président");
+ assertThat(req.getTypeVote()).isEqualTo(TypeVote.ELECTION_BUREAU);
+ assertThat(req.getModeScrutin()).isEqualTo(ModeScrutin.MAJORITAIRE_UN_TOUR);
+ assertThat(req.getRestreindreMembresAJour()).isFalse();
+ }
+
+ @Test
+ void testBuilder() {
+ CampagneVoteRequest req = CampagneVoteRequest.builder()
+ .titre("Résolution")
+ .typeVote(TypeVote.ADOPTION_RESOLUTION)
+ .build();
+ assertThat(req.getTitre()).isEqualTo("Résolution");
+ assertThat(req.getRestreindreMembresAJour()).isTrue();
+ }
+
+ @Test
+ void testEqualsHashCode() {
+ CampagneVoteRequest r1 = CampagneVoteRequest.builder().titre("t").organisationId("o").build();
+ CampagneVoteRequest r2 = CampagneVoteRequest.builder().titre("t").organisationId("o").build();
+ assertThat(r1).isEqualTo(r2);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/vote/CampagneVoteResponseTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/vote/CampagneVoteResponseTest.java
new file mode 100644
index 0000000..43d13f4
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/vote/CampagneVoteResponseTest.java
@@ -0,0 +1,47 @@
+package dev.lions.unionflow.server.api.dto.vote;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.lions.unionflow.server.api.enums.vote.ModeScrutin;
+import dev.lions.unionflow.server.api.enums.vote.StatutVote;
+import dev.lions.unionflow.server.api.enums.vote.TypeVote;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class CampagneVoteResponseTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CampagneVoteResponse()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CampagneVoteResponse resp = new CampagneVoteResponse();
+ resp.setTitre("Election Président 2026");
+ resp.setOrganisationId("org-1");
+ resp.setTypeVote(TypeVote.ELECTION_BUREAU);
+ resp.setModeScrutin(ModeScrutin.MAJORITAIRE_UN_TOUR);
+ resp.setStatut(StatutVote.OUVERT);
+ resp.setTotalElecteursInscrits(100);
+ resp.setTotalVotantsEffectifs(75);
+ resp.setTauxDeParticipation(75.0);
+ resp.setCandidatsExposes(List.of());
+
+ assertThat(resp.getTitre()).isEqualTo("Election Président 2026");
+ assertThat(resp.getTypeVote()).isEqualTo(TypeVote.ELECTION_BUREAU);
+ assertThat(resp.getStatut()).isEqualTo(StatutVote.OUVERT);
+ assertThat(resp.getTotalElecteursInscrits()).isEqualTo(100);
+ assertThat(resp.getTauxDeParticipation()).isEqualTo(75.0);
+ }
+
+ @Test
+ void testBuilder() {
+ CampagneVoteResponse resp = CampagneVoteResponse.builder()
+ .titre("Résolution Test")
+ .statut(StatutVote.CLOTURE)
+ .build();
+
+ assertThat(resp.getTitre()).isEqualTo("Résolution Test");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/vote/CandidatDTOTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/vote/CandidatDTOTest.java
new file mode 100644
index 0000000..55bb115
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/dto/vote/CandidatDTOTest.java
@@ -0,0 +1,40 @@
+package dev.lions.unionflow.server.api.dto.vote;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+
+class CandidatDTOTest {
+
+ @Test
+ void testConstructeurParDefaut() {
+ assertThat(new CandidatDTO()).isNotNull();
+ }
+
+ @Test
+ void testSettersEtGetters() {
+ CandidatDTO dto = new CandidatDTO();
+ dto.setCampagneVoteId("campagne-1");
+ dto.setNomCandidatureOuChoix("Alice Dupont");
+ dto.setMembreIdAssocie("m-1");
+ dto.setProfessionDeFoi("Je m'engage à...");
+ dto.setPhotoUrl("https://photos/alice.jpg");
+ dto.setNombreDeVoix(45);
+ dto.setPourcentageObtenu(new BigDecimal("60.5"));
+
+ assertThat(dto.getCampagneVoteId()).isEqualTo("campagne-1");
+ assertThat(dto.getNomCandidatureOuChoix()).isEqualTo("Alice Dupont");
+ assertThat(dto.getNombreDeVoix()).isEqualTo(45);
+ assertThat(dto.getPourcentageObtenu()).isEqualByComparingTo("60.5");
+ }
+
+ @Test
+ void testBuilder() {
+ CandidatDTO dto = CandidatDTO.builder()
+ .nomCandidatureOuChoix("OUI")
+ .nombreDeVoix(30)
+ .build();
+ assertThat(dto.getNomCandidatureOuChoix()).isEqualTo("OUI");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/membre/NiveauRisqueKycTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/membre/NiveauRisqueKycTest.java
new file mode 100644
index 0000000..5e6e448
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/membre/NiveauRisqueKycTest.java
@@ -0,0 +1,72 @@
+package dev.lions.unionflow.server.api.enums.membre;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests NiveauRisqueKyc")
+class NiveauRisqueKycTest {
+
+ @Test
+ @DisplayName("Toutes les valeurs existent avec les bons libellés")
+ void testValeurs() {
+ assertThat(NiveauRisqueKyc.FAIBLE.getLibelle()).isEqualTo("Risque faible");
+ assertThat(NiveauRisqueKyc.MOYEN.getLibelle()).isEqualTo("Risque moyen");
+ assertThat(NiveauRisqueKyc.ELEVE.getLibelle()).isEqualTo("Risque élevé");
+ assertThat(NiveauRisqueKyc.CRITIQUE.getLibelle()).isEqualTo("Risque critique");
+ }
+
+ @Test
+ @DisplayName("Bornes scoreMin et scoreMax correctes")
+ void testBornes() {
+ assertThat(NiveauRisqueKyc.FAIBLE.getScoreMin()).isEqualTo(0);
+ assertThat(NiveauRisqueKyc.FAIBLE.getScoreMax()).isEqualTo(39);
+ assertThat(NiveauRisqueKyc.MOYEN.getScoreMin()).isEqualTo(40);
+ assertThat(NiveauRisqueKyc.MOYEN.getScoreMax()).isEqualTo(69);
+ assertThat(NiveauRisqueKyc.ELEVE.getScoreMin()).isEqualTo(70);
+ assertThat(NiveauRisqueKyc.ELEVE.getScoreMax()).isEqualTo(89);
+ assertThat(NiveauRisqueKyc.CRITIQUE.getScoreMin()).isEqualTo(90);
+ assertThat(NiveauRisqueKyc.CRITIQUE.getScoreMax()).isEqualTo(100);
+ }
+
+ @Test
+ @DisplayName("fromScore retourne FAIBLE pour score 0-39")
+ void testFromScoreFaible() {
+ assertThat(NiveauRisqueKyc.fromScore(0)).isEqualTo(NiveauRisqueKyc.FAIBLE);
+ assertThat(NiveauRisqueKyc.fromScore(20)).isEqualTo(NiveauRisqueKyc.FAIBLE);
+ assertThat(NiveauRisqueKyc.fromScore(39)).isEqualTo(NiveauRisqueKyc.FAIBLE);
+ }
+
+ @Test
+ @DisplayName("fromScore retourne MOYEN pour score 40-69")
+ void testFromScoreMoyen() {
+ assertThat(NiveauRisqueKyc.fromScore(40)).isEqualTo(NiveauRisqueKyc.MOYEN);
+ assertThat(NiveauRisqueKyc.fromScore(55)).isEqualTo(NiveauRisqueKyc.MOYEN);
+ assertThat(NiveauRisqueKyc.fromScore(69)).isEqualTo(NiveauRisqueKyc.MOYEN);
+ }
+
+ @Test
+ @DisplayName("fromScore retourne ELEVE pour score 70-89")
+ void testFromScoreEleve() {
+ assertThat(NiveauRisqueKyc.fromScore(70)).isEqualTo(NiveauRisqueKyc.ELEVE);
+ assertThat(NiveauRisqueKyc.fromScore(80)).isEqualTo(NiveauRisqueKyc.ELEVE);
+ assertThat(NiveauRisqueKyc.fromScore(89)).isEqualTo(NiveauRisqueKyc.ELEVE);
+ }
+
+ @Test
+ @DisplayName("fromScore retourne CRITIQUE pour score 90-100")
+ void testFromScoreCritique() {
+ assertThat(NiveauRisqueKyc.fromScore(90)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
+ assertThat(NiveauRisqueKyc.fromScore(95)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
+ assertThat(NiveauRisqueKyc.fromScore(100)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
+ }
+
+ @Test
+ @DisplayName("fromScore retourne CRITIQUE pour score hors bornes (>100 ou négatif)")
+ void testFromScoreHorsBornes() {
+ assertThat(NiveauRisqueKyc.fromScore(101)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
+ assertThat(NiveauRisqueKyc.fromScore(999)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
+ assertThat(NiveauRisqueKyc.fromScore(-1)).isEqualTo(NiveauRisqueKyc.CRITIQUE);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/membre/TypePieceIdentiteTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/membre/TypePieceIdentiteTest.java
new file mode 100644
index 0000000..e641239
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/membre/TypePieceIdentiteTest.java
@@ -0,0 +1,42 @@
+package dev.lions.unionflow.server.api.enums.membre;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests TypePieceIdentite")
+class TypePieceIdentiteTest {
+
+ @Test
+ @DisplayName("Toutes les valeurs existent")
+ void testValeurs() {
+ assertThat(TypePieceIdentite.values()).containsExactlyInAnyOrder(
+ TypePieceIdentite.CNI,
+ TypePieceIdentite.PASSEPORT,
+ TypePieceIdentite.TITRE_SEJOUR,
+ TypePieceIdentite.CARTE_CONSULAIRE,
+ TypePieceIdentite.PERMIS_CONDUIRE,
+ TypePieceIdentite.AUTRE
+ );
+ }
+
+ @Test
+ @DisplayName("Libellés corrects pour chaque valeur")
+ void testLibelles() {
+ assertThat(TypePieceIdentite.CNI.getLibelle()).isEqualTo("Carte Nationale d'Identité");
+ assertThat(TypePieceIdentite.PASSEPORT.getLibelle()).isEqualTo("Passeport");
+ assertThat(TypePieceIdentite.TITRE_SEJOUR.getLibelle()).isEqualTo("Titre de séjour");
+ assertThat(TypePieceIdentite.CARTE_CONSULAIRE.getLibelle()).isEqualTo("Carte consulaire");
+ assertThat(TypePieceIdentite.PERMIS_CONDUIRE.getLibelle()).isEqualTo("Permis de conduire");
+ assertThat(TypePieceIdentite.AUTRE.getLibelle()).isEqualTo("Autre pièce officielle");
+ }
+
+ @Test
+ @DisplayName("valueOf fonctionne pour chaque valeur")
+ void testValueOf() {
+ assertThat(TypePieceIdentite.valueOf("CNI")).isEqualTo(TypePieceIdentite.CNI);
+ assertThat(TypePieceIdentite.valueOf("PASSEPORT")).isEqualTo(TypePieceIdentite.PASSEPORT);
+ assertThat(TypePieceIdentite.valueOf("AUTRE")).isEqualTo(TypePieceIdentite.AUTRE);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/StatutConversationTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/StatutConversationTest.java
new file mode 100644
index 0000000..d036678
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/StatutConversationTest.java
@@ -0,0 +1,39 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("StatutConversation")
+class StatutConversationTest {
+
+ @Test
+ @DisplayName("contient exactement 2 valeurs")
+ void values_count() {
+ assertThat(StatutConversation.values()).hasSize(2);
+ }
+
+ @Test
+ @DisplayName("toutes les valeurs attendues sont présentes")
+ void values_allPresent() {
+ assertThat(StatutConversation.values())
+ .containsExactlyInAnyOrder(
+ StatutConversation.ACTIVE,
+ StatutConversation.ARCHIVEE);
+ }
+
+ @Test
+ @DisplayName("valueOf fonctionne pour chaque constante")
+ void valueOf_works() {
+ assertThat(StatutConversation.valueOf("ACTIVE")).isEqualTo(StatutConversation.ACTIVE);
+ assertThat(StatutConversation.valueOf("ARCHIVEE")).isEqualTo(StatutConversation.ARCHIVEE);
+ }
+
+ @Test
+ @DisplayName("name retourne le nom correct")
+ void name_correct() {
+ assertThat(StatutConversation.ACTIVE.name()).isEqualTo("ACTIVE");
+ assertThat(StatutConversation.ARCHIVEE.name()).isEqualTo("ARCHIVEE");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypeContenuTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypeContenuTest.java
new file mode 100644
index 0000000..07d0b22
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypeContenuTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("TypeContenu")
+class TypeContenuTest {
+
+ @Test
+ @DisplayName("contient exactement 4 valeurs")
+ void values_count() {
+ assertThat(TypeContenu.values()).hasSize(4);
+ }
+
+ @Test
+ @DisplayName("toutes les valeurs attendues sont présentes")
+ void values_allPresent() {
+ assertThat(TypeContenu.values())
+ .containsExactlyInAnyOrder(
+ TypeContenu.TEXTE,
+ TypeContenu.VOCAL,
+ TypeContenu.IMAGE,
+ TypeContenu.SYSTEME);
+ }
+
+ @Test
+ @DisplayName("valueOf fonctionne pour chaque constante")
+ void valueOf_works() {
+ assertThat(TypeContenu.valueOf("TEXTE")).isEqualTo(TypeContenu.TEXTE);
+ assertThat(TypeContenu.valueOf("VOCAL")).isEqualTo(TypeContenu.VOCAL);
+ assertThat(TypeContenu.valueOf("IMAGE")).isEqualTo(TypeContenu.IMAGE);
+ assertThat(TypeContenu.valueOf("SYSTEME")).isEqualTo(TypeContenu.SYSTEME);
+ }
+
+ @Test
+ @DisplayName("name retourne le nom correct")
+ void name_correct() {
+ assertThat(TypeContenu.TEXTE.name()).isEqualTo("TEXTE");
+ assertThat(TypeContenu.VOCAL.name()).isEqualTo("VOCAL");
+ assertThat(TypeContenu.IMAGE.name()).isEqualTo("IMAGE");
+ assertThat(TypeContenu.SYSTEME.name()).isEqualTo("SYSTEME");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypeConversationTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypeConversationTest.java
new file mode 100644
index 0000000..8e49e84
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypeConversationTest.java
@@ -0,0 +1,42 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("TypeConversation")
+class TypeConversationTest {
+
+ @Test
+ @DisplayName("contient exactement 3 valeurs")
+ void values_count() {
+ assertThat(TypeConversation.values()).hasSize(3);
+ }
+
+ @Test
+ @DisplayName("toutes les valeurs attendues sont présentes")
+ void values_allPresent() {
+ assertThat(TypeConversation.values())
+ .containsExactlyInAnyOrder(
+ TypeConversation.DIRECTE,
+ TypeConversation.ROLE_CANAL,
+ TypeConversation.GROUPE);
+ }
+
+ @Test
+ @DisplayName("valueOf fonctionne pour chaque constante")
+ void valueOf_works() {
+ assertThat(TypeConversation.valueOf("DIRECTE")).isEqualTo(TypeConversation.DIRECTE);
+ assertThat(TypeConversation.valueOf("ROLE_CANAL")).isEqualTo(TypeConversation.ROLE_CANAL);
+ assertThat(TypeConversation.valueOf("GROUPE")).isEqualTo(TypeConversation.GROUPE);
+ }
+
+ @Test
+ @DisplayName("name retourne le nom correct")
+ void name_correct() {
+ assertThat(TypeConversation.DIRECTE.name()).isEqualTo("DIRECTE");
+ assertThat(TypeConversation.ROLE_CANAL.name()).isEqualTo("ROLE_CANAL");
+ assertThat(TypeConversation.GROUPE.name()).isEqualTo("GROUPE");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypePolitiqueCommunicationTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypePolitiqueCommunicationTest.java
new file mode 100644
index 0000000..905e2ba
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/messagerie/TypePolitiqueCommunicationTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.enums.messagerie;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("TypePolitiqueCommunication")
+class TypePolitiqueCommunicationTest {
+
+ @Test
+ @DisplayName("contient exactement 3 valeurs")
+ void values_count() {
+ assertThat(TypePolitiqueCommunication.values()).hasSize(3);
+ }
+
+ @Test
+ @DisplayName("toutes les valeurs attendues sont présentes")
+ void values_allPresent() {
+ assertThat(TypePolitiqueCommunication.values())
+ .containsExactlyInAnyOrder(
+ TypePolitiqueCommunication.OUVERT,
+ TypePolitiqueCommunication.BUREAU_SEULEMENT,
+ TypePolitiqueCommunication.GROUPES_INTERNES);
+ }
+
+ @Test
+ @DisplayName("valueOf fonctionne pour chaque constante")
+ void valueOf_works() {
+ assertThat(TypePolitiqueCommunication.valueOf("OUVERT"))
+ .isEqualTo(TypePolitiqueCommunication.OUVERT);
+ assertThat(TypePolitiqueCommunication.valueOf("BUREAU_SEULEMENT"))
+ .isEqualTo(TypePolitiqueCommunication.BUREAU_SEULEMENT);
+ assertThat(TypePolitiqueCommunication.valueOf("GROUPES_INTERNES"))
+ .isEqualTo(TypePolitiqueCommunication.GROUPES_INTERNES);
+ }
+
+ @Test
+ @DisplayName("name retourne le nom correct")
+ void name_correct() {
+ assertThat(TypePolitiqueCommunication.OUVERT.name()).isEqualTo("OUVERT");
+ assertThat(TypePolitiqueCommunication.BUREAU_SEULEMENT.name()).isEqualTo("BUREAU_SEULEMENT");
+ assertThat(TypePolitiqueCommunication.GROUPES_INTERNES.name()).isEqualTo("GROUPES_INTERNES");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/StatutComptePartsSocialesTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/StatutComptePartsSocialesTest.java
new file mode 100644
index 0000000..87e8a8f
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/StatutComptePartsSocialesTest.java
@@ -0,0 +1,19 @@
+package dev.lions.unionflow.server.api.enums.mutuelle.parts;
+
+import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class StatutComptePartsSocialesTest {
+ @Test void values_nonVide() {
+ assertThat(StatutComptePartsSociales.values()).isNotEmpty();
+ }
+ @Test void chaque_valeur_a_libelle() {
+ for (StatutComptePartsSociales s : StatutComptePartsSociales.values()) {
+ assertThat(s.getLibelle()).isNotBlank();
+ }
+ }
+ @Test void valueOf_actif() {
+ assertThat(StatutComptePartsSociales.valueOf("ACTIF"))
+ .isEqualTo(StatutComptePartsSociales.ACTIF);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/TypeTransactionPartsSocialesTest.java b/src/test/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/TypeTransactionPartsSocialesTest.java
new file mode 100644
index 0000000..71fbc63
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/enums/mutuelle/parts/TypeTransactionPartsSocialesTest.java
@@ -0,0 +1,19 @@
+package dev.lions.unionflow.server.api.enums.mutuelle.parts;
+
+import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class TypeTransactionPartsSocialesTest {
+ @Test void values_nonVide() {
+ assertThat(TypeTransactionPartsSociales.values()).isNotEmpty();
+ }
+ @Test void chaque_valeur_a_libelle() {
+ for (TypeTransactionPartsSociales t : TypeTransactionPartsSociales.values()) {
+ assertThat(t.getLibelle()).isNotBlank();
+ }
+ }
+ @Test void valueOf_retourne_correct() {
+ assertThat(TypeTransactionPartsSociales.valueOf("SOUSCRIPTION"))
+ .isEqualTo(TypeTransactionPartsSociales.SOUSCRIPTION);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/payment/CheckoutRequestTest.java b/src/test/java/dev/lions/unionflow/server/api/payment/CheckoutRequestTest.java
new file mode 100644
index 0000000..934c53d
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/payment/CheckoutRequestTest.java
@@ -0,0 +1,98 @@
+package dev.lions.unionflow.server.api.payment;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.math.BigDecimal;
+import java.util.Map;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests CheckoutRequest")
+class CheckoutRequestTest {
+
+ @Test
+ @DisplayName("Création valide")
+ void testCreationValide() {
+ CheckoutRequest req = new CheckoutRequest(
+ new BigDecimal("5000"), "XOF", "+221700000000", "test@email.com",
+ "REF-001", "https://success.url", "https://cancel.url", Map.of("key", "val"));
+ assertThat(req.amount()).isEqualByComparingTo("5000");
+ assertThat(req.currency()).isEqualTo("XOF");
+ assertThat(req.customerPhone()).isEqualTo("+221700000000");
+ assertThat(req.customerEmail()).isEqualTo("test@email.com");
+ assertThat(req.reference()).isEqualTo("REF-001");
+ assertThat(req.successUrl()).isEqualTo("https://success.url");
+ assertThat(req.cancelUrl()).isEqualTo("https://cancel.url");
+ assertThat(req.metadata()).containsEntry("key", "val");
+ }
+
+ @Test
+ @DisplayName("Amount null lève IllegalArgumentException")
+ void testAmountNull() {
+ assertThatThrownBy(() -> new CheckoutRequest(null, "XOF", null, null, "REF", null, null, null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("amount");
+ }
+
+ @Test
+ @DisplayName("Amount zero lève IllegalArgumentException")
+ void testAmountZero() {
+ assertThatThrownBy(() -> new CheckoutRequest(BigDecimal.ZERO, "XOF", null, null, "REF", null, null, null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("amount");
+ }
+
+ @Test
+ @DisplayName("Amount négatif lève IllegalArgumentException")
+ void testAmountNegatif() {
+ assertThatThrownBy(() -> new CheckoutRequest(new BigDecimal("-1"), "XOF", null, null, "REF", null, null, null))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ @DisplayName("Currency null lève IllegalArgumentException")
+ void testCurrencyNull() {
+ assertThatThrownBy(() -> new CheckoutRequest(new BigDecimal("100"), null, null, null, "REF", null, null, null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("currency");
+ }
+
+ @Test
+ @DisplayName("Currency blank lève IllegalArgumentException")
+ void testCurrencyBlank() {
+ assertThatThrownBy(() -> new CheckoutRequest(new BigDecimal("100"), " ", null, null, "REF", null, null, null))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ @DisplayName("Reference null lève IllegalArgumentException")
+ void testReferenceNull() {
+ assertThatThrownBy(() -> new CheckoutRequest(new BigDecimal("100"), "XOF", null, null, null, null, null, null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("reference");
+ }
+
+ @Test
+ @DisplayName("Reference blank lève IllegalArgumentException")
+ void testReferenceBlank() {
+ assertThatThrownBy(() -> new CheckoutRequest(new BigDecimal("100"), "XOF", null, null, "", null, null, null))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ @DisplayName("Deux instances égales avec mêmes champs")
+ void testEquality() {
+ CheckoutRequest r1 = new CheckoutRequest(new BigDecimal("100"), "XOF", null, null, "REF", null, null, null);
+ CheckoutRequest r2 = new CheckoutRequest(new BigDecimal("100"), "XOF", null, null, "REF", null, null, null);
+ assertThat(r1).isEqualTo(r2);
+ assertThat(r1.hashCode()).isEqualTo(r2.hashCode());
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void testToString() {
+ CheckoutRequest req = new CheckoutRequest(new BigDecimal("100"), "XOF", null, null, "REF-X", null, null, null);
+ assertThat(req.toString()).isNotNull().contains("REF-X");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/payment/CheckoutSessionTest.java b/src/test/java/dev/lions/unionflow/server/api/payment/CheckoutSessionTest.java
new file mode 100644
index 0000000..1a38c87
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/payment/CheckoutSessionTest.java
@@ -0,0 +1,50 @@
+package dev.lions.unionflow.server.api.payment;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.Instant;
+import java.util.Map;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests CheckoutSession")
+class CheckoutSessionTest {
+
+ @Test
+ @DisplayName("Création et accesseurs")
+ void testCreation() {
+ Instant expires = Instant.now().plusSeconds(3600);
+ CheckoutSession session = new CheckoutSession("ext-123", "https://pay.url", expires, Map.of("k", "v"));
+ assertThat(session.externalId()).isEqualTo("ext-123");
+ assertThat(session.checkoutUrl()).isEqualTo("https://pay.url");
+ assertThat(session.expiresAt()).isEqualTo(expires);
+ assertThat(session.providerMetadata()).containsEntry("k", "v");
+ }
+
+ @Test
+ @DisplayName("Champs null acceptés")
+ void testChampsNull() {
+ CheckoutSession session = new CheckoutSession(null, null, null, null);
+ assertThat(session.externalId()).isNull();
+ assertThat(session.checkoutUrl()).isNull();
+ assertThat(session.expiresAt()).isNull();
+ assertThat(session.providerMetadata()).isNull();
+ }
+
+ @Test
+ @DisplayName("Égalité de deux instances identiques")
+ void testEquality() {
+ Instant now = Instant.now();
+ CheckoutSession s1 = new CheckoutSession("id1", "url", now, null);
+ CheckoutSession s2 = new CheckoutSession("id1", "url", now, null);
+ assertThat(s1).isEqualTo(s2);
+ assertThat(s1.hashCode()).isEqualTo(s2.hashCode());
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void testToString() {
+ CheckoutSession session = new CheckoutSession("ext-456", "https://url", null, null);
+ assertThat(session.toString()).isNotNull().contains("ext-456");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/payment/PaymentEventTest.java b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentEventTest.java
new file mode 100644
index 0000000..08dd46a
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentEventTest.java
@@ -0,0 +1,49 @@
+package dev.lions.unionflow.server.api.payment;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.math.BigDecimal;
+import java.time.Instant;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests PaymentEvent")
+class PaymentEventTest {
+
+ @Test
+ @DisplayName("Création et accesseurs")
+ void testCreation() {
+ Instant now = Instant.now();
+ PaymentEvent event = new PaymentEvent("ext-1", "REF-1", PaymentStatus.SUCCESS, new BigDecimal("5000"), "TX-123", now);
+ assertThat(event.externalId()).isEqualTo("ext-1");
+ assertThat(event.reference()).isEqualTo("REF-1");
+ assertThat(event.status()).isEqualTo(PaymentStatus.SUCCESS);
+ assertThat(event.amountConfirmed()).isEqualByComparingTo("5000");
+ assertThat(event.transactionCode()).isEqualTo("TX-123");
+ assertThat(event.occurredAt()).isEqualTo(now);
+ }
+
+ @Test
+ @DisplayName("Champs null acceptés")
+ void testChampsNull() {
+ PaymentEvent event = new PaymentEvent(null, null, null, null, null, null);
+ assertThat(event.externalId()).isNull();
+ assertThat(event.status()).isNull();
+ }
+
+ @Test
+ @DisplayName("Égalité de deux instances identiques")
+ void testEquality() {
+ Instant now = Instant.now();
+ PaymentEvent e1 = new PaymentEvent("id", "ref", PaymentStatus.FAILED, null, null, now);
+ PaymentEvent e2 = new PaymentEvent("id", "ref", PaymentStatus.FAILED, null, null, now);
+ assertThat(e1).isEqualTo(e2);
+ }
+
+ @Test
+ @DisplayName("toString non null")
+ void testToString() {
+ PaymentEvent event = new PaymentEvent("ext-2", "REF-2", PaymentStatus.CANCELLED, null, null, null);
+ assertThat(event.toString()).isNotNull().contains("ext-2");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/payment/PaymentExceptionTest.java b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentExceptionTest.java
new file mode 100644
index 0000000..d8432f3
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentExceptionTest.java
@@ -0,0 +1,45 @@
+package dev.lions.unionflow.server.api.payment;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests PaymentException")
+class PaymentExceptionTest {
+
+ @Test
+ @DisplayName("Constructeur sans cause")
+ void testConstructeurSansCause() {
+ PaymentException ex = new PaymentException("WAVE", "Timeout", 504);
+ assertThat(ex.getProviderCode()).isEqualTo("WAVE");
+ assertThat(ex.getHttpStatus()).isEqualTo(504);
+ assertThat(ex.getMessage()).contains("WAVE").contains("Timeout");
+ assertThat(ex.getCause()).isNull();
+ }
+
+ @Test
+ @DisplayName("Constructeur avec cause")
+ void testConstructeurAvecCause() {
+ RuntimeException cause = new RuntimeException("Network error");
+ PaymentException ex = new PaymentException("ORANGE_MONEY", "Connection refused", 503, cause);
+ assertThat(ex.getProviderCode()).isEqualTo("ORANGE_MONEY");
+ assertThat(ex.getHttpStatus()).isEqualTo(503);
+ assertThat(ex.getMessage()).contains("ORANGE_MONEY").contains("Connection refused");
+ assertThat(ex.getCause()).isEqualTo(cause);
+ }
+
+ @Test
+ @DisplayName("Message format [code] message")
+ void testMessageFormat() {
+ PaymentException ex = new PaymentException("MTN", "Invalid amount", 400);
+ assertThat(ex.getMessage()).isEqualTo("[MTN] Invalid amount");
+ }
+
+ @Test
+ @DisplayName("Est une RuntimeException")
+ void testIsRuntimeException() {
+ PaymentException ex = new PaymentException("WAVE", "Error", 500);
+ assertThat(ex).isInstanceOf(RuntimeException.class);
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/payment/PaymentProviderTest.java b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentProviderTest.java
new file mode 100644
index 0000000..d17b271
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentProviderTest.java
@@ -0,0 +1,55 @@
+package dev.lions.unionflow.server.api.payment;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Map;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests PaymentProvider default methods")
+class PaymentProviderTest {
+
+ private final PaymentProvider provider = new PaymentProvider() {
+ @Override
+ public String getProviderCode() { return "TEST"; }
+
+ @Override
+ public CheckoutSession initiateCheckout(CheckoutRequest request) throws PaymentException {
+ return null;
+ }
+
+ @Override
+ public PaymentStatus getStatus(String externalId) throws PaymentException {
+ return PaymentStatus.INITIATED;
+ }
+
+ @Override
+ public PaymentEvent processWebhook(String rawBody, Map headers) throws PaymentException {
+ return null;
+ }
+ };
+
+ @Test
+ @DisplayName("getSupportedCurrencies retourne XOF par défaut")
+ void testGetSupportedCurrencies() {
+ assertThat(provider.getSupportedCurrencies()).containsExactly("XOF");
+ }
+
+ @Test
+ @DisplayName("supportsRefund retourne false par défaut")
+ void testSupportsRefund() {
+ assertThat(provider.supportsRefund()).isFalse();
+ }
+
+ @Test
+ @DisplayName("isAvailable retourne true par défaut")
+ void testIsAvailable() {
+ assertThat(provider.isAvailable()).isTrue();
+ }
+
+ @Test
+ @DisplayName("getProviderCode retourne le code")
+ void testGetProviderCode() {
+ assertThat(provider.getProviderCode()).isEqualTo("TEST");
+ }
+}
diff --git a/src/test/java/dev/lions/unionflow/server/api/payment/PaymentStatusTest.java b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentStatusTest.java
new file mode 100644
index 0000000..c84bfd9
--- /dev/null
+++ b/src/test/java/dev/lions/unionflow/server/api/payment/PaymentStatusTest.java
@@ -0,0 +1,34 @@
+package dev.lions.unionflow.server.api.payment;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("Tests PaymentStatus")
+class PaymentStatusTest {
+
+ @Test
+ @DisplayName("Toutes les valeurs de l'enum existent")
+ void testValeurs() {
+ assertThat(PaymentStatus.values()).containsExactlyInAnyOrder(
+ PaymentStatus.INITIATED,
+ PaymentStatus.PROCESSING,
+ PaymentStatus.SUCCESS,
+ PaymentStatus.FAILED,
+ PaymentStatus.CANCELLED,
+ PaymentStatus.EXPIRED
+ );
+ }
+
+ @Test
+ @DisplayName("valueOf fonctionne pour chaque valeur")
+ void testValueOf() {
+ assertThat(PaymentStatus.valueOf("INITIATED")).isEqualTo(PaymentStatus.INITIATED);
+ assertThat(PaymentStatus.valueOf("PROCESSING")).isEqualTo(PaymentStatus.PROCESSING);
+ assertThat(PaymentStatus.valueOf("SUCCESS")).isEqualTo(PaymentStatus.SUCCESS);
+ assertThat(PaymentStatus.valueOf("FAILED")).isEqualTo(PaymentStatus.FAILED);
+ assertThat(PaymentStatus.valueOf("CANCELLED")).isEqualTo(PaymentStatus.CANCELLED);
+ assertThat(PaymentStatus.valueOf("EXPIRED")).isEqualTo(PaymentStatus.EXPIRED);
+ }
+}